summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/app.md6
-rw-r--r--src/app/config/.may_include2
-rw-r--r--src/app/config/app_config.md6
-rw-r--r--src/app/config/config.c3591
-rw-r--r--src/app/config/config.h119
-rw-r--r--src/app/config/include.am23
-rw-r--r--src/app/config/or_options_st.h152
-rw-r--r--src/app/config/or_state_st.h11
-rw-r--r--src/app/config/quiet_level.c38
-rw-r--r--src/app/config/quiet_level.h30
-rw-r--r--src/app/config/resolve_addr.c314
-rw-r--r--src/app/config/resolve_addr.h28
-rw-r--r--src/app/config/statefile.c81
-rw-r--r--src/app/config/statefile.h4
-rw-r--r--src/app/config/testnet.inc3
-rw-r--r--src/app/config/tor_cmdline_mode.h34
-rw-r--r--src/app/main/.may_include1
-rw-r--r--src/app/main/app_main.md2
-rw-r--r--src/app/main/include.am18
-rw-r--r--src/app/main/main.c124
-rw-r--r--src/app/main/main.h2
-rw-r--r--src/app/main/ntmain.c7
-rw-r--r--src/app/main/ntmain.h5
-rw-r--r--src/app/main/shutdown.c8
-rw-r--r--src/app/main/shutdown.h2
-rw-r--r--src/app/main/subsysmgr.c250
-rw-r--r--src/app/main/subsysmgr.h26
-rw-r--r--src/app/main/subsystem_list.c29
-rw-r--r--src/app/main/tor_main.c2
-rw-r--r--src/arch_goals.md31
-rw-r--r--src/config/mmdb-convert.py7
-rw-r--r--src/core/core.md18
-rw-r--r--src/core/crypto/core_crypto.md6
-rw-r--r--src/core/crypto/hs_ntor.c46
-rw-r--r--src/core/crypto/hs_ntor.h32
-rw-r--r--src/core/crypto/include.am18
-rw-r--r--src/core/crypto/onion_crypto.c2
-rw-r--r--src/core/crypto/onion_crypto.h2
-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.h7
-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.c7
-rw-r--r--src/core/crypto/relay_crypto.h2
-rw-r--r--src/core/include.am425
-rw-r--r--src/core/mainloop/.may_include6
-rw-r--r--src/core/mainloop/connection.c404
-rw-r--r--src/core/mainloop/connection.h201
-rw-r--r--src/core/mainloop/core_mainloop.md10
-rw-r--r--src/core/mainloop/cpuworker.c8
-rw-r--r--src/core/mainloop/cpuworker.h6
-rw-r--r--src/core/mainloop/include.am22
-rw-r--r--src/core/mainloop/mainloop.c51
-rw-r--r--src/core/mainloop/mainloop.h5
-rw-r--r--src/core/mainloop/mainloop_pubsub.c11
-rw-r--r--src/core/mainloop/mainloop_pubsub.h39
-rw-r--r--src/core/mainloop/mainloop_state.inc19
-rw-r--r--src/core/mainloop/mainloop_state_st.h23
-rw-r--r--src/core/mainloop/mainloop_sys.c60
-rw-r--r--src/core/mainloop/mainloop_sys.h7
-rw-r--r--src/core/mainloop/netstatus.c12
-rw-r--r--src/core/mainloop/netstatus.h14
-rw-r--r--src/core/mainloop/periodic.c5
-rw-r--r--src/core/mainloop/periodic.h9
-rw-r--r--src/core/or/.may_include4
-rw-r--r--src/core/or/addr_policy_st.h9
-rw-r--r--src/core/or/address_set.c4
-rw-r--r--src/core/or/address_set.h2
-rw-r--r--src/core/or/cell_queue_st.h9
-rw-r--r--src/core/or/cell_st.h8
-rw-r--r--src/core/or/channel.c217
-rw-r--r--src/core/or/channel.h98
-rw-r--r--src/core/or/channelpadding.c11
-rw-r--r--src/core/or/channelpadding.h2
-rw-r--r--src/core/or/channeltls.c54
-rw-r--r--src/core/or/channeltls.h8
-rw-r--r--src/core/or/circuit_st.h13
-rw-r--r--src/core/or/circuitbuild.c299
-rw-r--r--src/core/or/circuitbuild.h25
-rw-r--r--src/core/or/circuitlist.c54
-rw-r--r--src/core/or/circuitlist.h8
-rw-r--r--src/core/or/circuitmux.c66
-rw-r--r--src/core/or/circuitmux.h70
-rw-r--r--src/core/or/circuitmux_ewma.c119
-rw-r--r--src/core/or/circuitmux_ewma.h114
-rw-r--r--src/core/or/circuitpadding.c18
-rw-r--r--src/core/or/circuitpadding.h6
-rw-r--r--src/core/or/circuitpadding_machines.c2
-rw-r--r--src/core/or/circuitstats.c16
-rw-r--r--src/core/or/circuitstats.h4
-rw-r--r--src/core/or/circuituse.c95
-rw-r--r--src/core/or/circuituse.h11
-rw-r--r--src/core/or/command.c23
-rw-r--r--src/core/or/command.h3
-rw-r--r--src/core/or/connection_edge.c212
-rw-r--r--src/core/or/connection_edge.h35
-rw-r--r--src/core/or/connection_or.c685
-rw-r--r--src/core/or/connection_or.h29
-rw-r--r--src/core/or/connection_st.h10
-rw-r--r--src/core/or/core_or.md62
-rw-r--r--src/core/or/cpath_build_state_st.h8
-rw-r--r--src/core/or/crypt_path.c2
-rw-r--r--src/core/or/crypt_path_reference_st.h8
-rw-r--r--src/core/or/crypt_path_st.h7
-rw-r--r--src/core/or/dataflow.md236
-rw-r--r--src/core/or/destroy_cell_queue_st.h12
-rw-r--r--src/core/or/dos.c15
-rw-r--r--src/core/or/dos.h2
-rw-r--r--src/core/or/edge_connection_st.h8
-rw-r--r--src/core/or/entry_connection_st.h8
-rw-r--r--src/core/or/entry_port_cfg_st.h11
-rw-r--r--src/core/or/extend_info_st.h7
-rw-r--r--src/core/or/half_edge_st.h8
-rw-r--r--src/core/or/include.am96
-rw-r--r--src/core/or/listener_connection_st.h8
-rw-r--r--src/core/or/ocirc_event.c13
-rw-r--r--src/core/or/ocirc_event.h2
-rw-r--r--src/core/or/ocirc_event_sys.h13
-rw-r--r--src/core/or/onion.c53
-rw-r--r--src/core/or/onion.h12
-rw-r--r--src/core/or/or.h29
-rw-r--r--src/core/or/or_circuit_st.h4
-rw-r--r--src/core/or/or_connection_st.h9
-rw-r--r--src/core/or/or_handshake_certs_st.h7
-rw-r--r--src/core/or/or_handshake_state_st.h8
-rw-r--r--src/core/or/or_periodic.c4
-rw-r--r--src/core/or/or_periodic.h2
-rw-r--r--src/core/or/or_sys.c15
-rw-r--r--src/core/or/or_sys.h6
-rw-r--r--src/core/or/orconn_event.c13
-rw-r--r--src/core/or/orconn_event.h2
-rw-r--r--src/core/or/orconn_event_sys.h12
-rw-r--r--src/core/or/origin_circuit_st.h7
-rw-r--r--src/core/or/policies.c83
-rw-r--r--src/core/or/policies.h3
-rw-r--r--src/core/or/port_cfg_st.h8
-rw-r--r--src/core/or/protover.c10
-rw-r--r--src/core/or/protover.h2
-rw-r--r--src/core/or/protover_rust.c2
-rw-r--r--src/core/or/reasons.c6
-rw-r--r--src/core/or/reasons.h2
-rw-r--r--src/core/or/relay.c11
-rw-r--r--src/core/or/relay.h4
-rw-r--r--src/core/or/relay_crypto_st.h9
-rw-r--r--src/core/or/scheduler.c84
-rw-r--r--src/core/or/scheduler.h17
-rw-r--r--src/core/or/scheduler_kist.c40
-rw-r--r--src/core/or/scheduler_vanilla.c12
-rw-r--r--src/core/or/sendme.c2
-rw-r--r--src/core/or/sendme.h2
-rw-r--r--src/core/or/server_port_cfg_st.h8
-rw-r--r--src/core/or/socks_request_st.h14
-rw-r--r--src/core/or/status.c5
-rw-r--r--src/core/or/status.h8
-rw-r--r--src/core/or/tor_version_st.h8
-rw-r--r--src/core/or/var_cell_st.h8
-rw-r--r--src/core/or/versions.c4
-rw-r--r--src/core/or/versions.h2
-rw-r--r--src/core/proto/.may_include6
-rw-r--r--src/core/proto/core_proto.md6
-rw-r--r--src/core/proto/include.am18
-rw-r--r--src/core/proto/proto_cell.c10
-rw-r--r--src/core/proto/proto_cell.h8
-rw-r--r--src/core/proto/proto_control0.c8
-rw-r--r--src/core/proto/proto_control0.h8
-rw-r--r--src/core/proto/proto_ext_or.c8
-rw-r--r--src/core/proto/proto_ext_or.h14
-rw-r--r--src/core/proto/proto_haproxy.c45
-rw-r--r--src/core/proto/proto_haproxy.h12
-rw-r--r--src/core/proto/proto_http.c8
-rw-r--r--src/core/proto/proto_http.h8
-rw-r--r--src/core/proto/proto_socks.c20
-rw-r--r--src/core/proto/proto_socks.h7
-rw-r--r--src/core/stA1RajU0
-rw-r--r--src/core/stiysZNDbin0 -> 19083264 bytes
-rw-r--r--src/ext/ed25519/ref10/base.py19
-rw-r--r--src/ext/ed25519/ref10/base2.py15
-rw-r--r--src/ext/ed25519/ref10/d.py7
-rw-r--r--src/ext/ed25519/ref10/d2.py7
-rw-r--r--src/ext/ed25519/ref10/sqrtm1.py7
-rw-r--r--src/ext/ht.h19
-rw-r--r--src/ext/siphash.h2
-rw-r--r--src/ext/timeouts/timeout.h6
-rw-r--r--src/ext/tinytest_macros.h4
-rw-r--r--src/feature/api/.may_include1
-rw-r--r--src/feature/api/feature_api.md2
-rw-r--r--src/feature/api/include.am11
-rw-r--r--src/feature/api/tor_api.c2
-rw-r--r--src/feature/api/tor_api.h2
-rw-r--r--src/feature/api/tor_api_internal.h7
-rw-r--r--src/feature/client/.may_include1
-rw-r--r--src/feature/client/addressmap.c7
-rw-r--r--src/feature/client/addressmap.h8
-rw-r--r--src/feature/client/bridges.c5
-rw-r--r--src/feature/client/bridges.h2
-rw-r--r--src/feature/client/circpathbias.c7
-rw-r--r--src/feature/client/circpathbias.h2
-rw-r--r--src/feature/client/dnsserv.c2
-rw-r--r--src/feature/client/dnsserv.h2
-rw-r--r--src/feature/client/entrynodes.c296
-rw-r--r--src/feature/client/entrynodes.h33
-rw-r--r--src/feature/client/feature_client.md5
-rw-r--r--src/feature/client/include.am20
-rw-r--r--src/feature/client/proxymode.c32
-rw-r--r--src/feature/client/proxymode.h17
-rw-r--r--src/feature/client/transports.c20
-rw-r--r--src/feature/client/transports.h2
-rw-r--r--src/feature/control/.may_include1
-rw-r--r--src/feature/control/btrack.c5
-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.c3
-rw-r--r--src/feature/control/btrack_orconn_cevent.h2
-rw-r--r--src/feature/control/btrack_orconn_maps.c11
-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.c2
-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.c8
-rw-r--r--src/feature/control/control_cmd.c165
-rw-r--r--src/feature/control/control_cmd.h2
-rw-r--r--src/feature/control/control_cmd_args_st.h2
-rw-r--r--src/feature/control/control_connection_st.h7
-rw-r--r--src/feature/control/control_events.c56
-rw-r--r--src/feature/control/control_events.h16
-rw-r--r--src/feature/control/control_fmt.c95
-rw-r--r--src/feature/control/control_fmt.h4
-rw-r--r--src/feature/control/control_getinfo.c215
-rw-r--r--src/feature/control/control_getinfo.h6
-rw-r--r--src/feature/control/control_hs.c343
-rw-r--r--src/feature/control/control_hs.h34
-rw-r--r--src/feature/control/control_proto.c159
-rw-r--r--src/feature/control/control_proto.h74
-rw-r--r--src/feature/control/feature_control.md8
-rw-r--r--src/feature/control/fmt_serverstatus.c7
-rw-r--r--src/feature/control/fmt_serverstatus.h2
-rw-r--r--src/feature/control/getinfo_geoip.c9
-rw-r--r--src/feature/control/getinfo_geoip.h7
-rw-r--r--src/feature/control/include.am39
-rw-r--r--src/feature/dirauth/.may_include2
-rw-r--r--src/feature/dirauth/authmode.c11
-rw-r--r--src/feature/dirauth/authmode.h12
-rw-r--r--src/feature/dirauth/bridgeauth.c7
-rw-r--r--src/feature/dirauth/bridgeauth.h7
-rw-r--r--src/feature/dirauth/bwauth.c8
-rw-r--r--src/feature/dirauth/bwauth.h2
-rw-r--r--src/feature/dirauth/dirauth_config.c471
-rw-r--r--src/feature/dirauth/dirauth_config.h91
-rw-r--r--src/feature/dirauth/dirauth_options.inc105
-rw-r--r--src/feature/dirauth/dirauth_options_st.h24
-rw-r--r--src/feature/dirauth/dirauth_periodic.c9
-rw-r--r--src/feature/dirauth/dirauth_periodic.h7
-rw-r--r--src/feature/dirauth/dirauth_stub.c34
-rw-r--r--src/feature/dirauth/dirauth_sys.c35
-rw-r--r--src/feature/dirauth/dirauth_sys.h22
-rw-r--r--src/feature/dirauth/dircollate.c15
-rw-r--r--src/feature/dirauth/dircollate.h10
-rw-r--r--src/feature/dirauth/dirvote.c251
-rw-r--r--src/feature/dirauth/dirvote.h67
-rw-r--r--src/feature/dirauth/dsigs_parse.c2
-rw-r--r--src/feature/dirauth/dsigs_parse.h2
-rw-r--r--src/feature/dirauth/feature_dirauth.md9
-rw-r--r--src/feature/dirauth/guardfraction.c4
-rw-r--r--src/feature/dirauth/guardfraction.h4
-rw-r--r--src/feature/dirauth/include.am54
-rw-r--r--src/feature/dirauth/keypin.c12
-rw-r--r--src/feature/dirauth/keypin.h9
-rw-r--r--src/feature/dirauth/ns_detached_signatures_st.h8
-rw-r--r--src/feature/dirauth/process_descs.c298
-rw-r--r--src/feature/dirauth/process_descs.h68
-rw-r--r--src/feature/dirauth/reachability.c12
-rw-r--r--src/feature/dirauth/reachability.h33
-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.c91
-rw-r--r--src/feature/dirauth/shared_random.h61
-rw-r--r--src/feature/dirauth/shared_random_state.c179
-rw-r--r--src/feature/dirauth/shared_random_state.h64
-rw-r--r--src/feature/dirauth/vote_microdesc_hash_st.h8
-rw-r--r--src/feature/dirauth/voteflags.c48
-rw-r--r--src/feature/dirauth/voteflags.h2
-rw-r--r--src/feature/dirauth/voting_schedule.c (renamed from src/feature/dircommon/voting_schedule.c)116
-rw-r--r--src/feature/dirauth/voting_schedule.h (renamed from src/feature/dircommon/voting_schedule.h)52
-rw-r--r--src/feature/dircache/.may_include1
-rw-r--r--src/feature/dircache/cached_dir_st.h8
-rw-r--r--src/feature/dircache/conscache.c26
-rw-r--r--src/feature/dircache/conscache.h13
-rw-r--r--src/feature/dircache/consdiffmgr.c12
-rw-r--r--src/feature/dircache/consdiffmgr.h21
-rw-r--r--src/feature/dircache/dircache.c19
-rw-r--r--src/feature/dircache/dircache.h2
-rw-r--r--src/feature/dircache/dircache_stub.c78
-rw-r--r--src/feature/dircache/dirserv.c182
-rw-r--r--src/feature/dircache/dirserv.h43
-rw-r--r--src/feature/dircache/feature_dircache.md6
-rw-r--r--src/feature/dircache/include.am21
-rw-r--r--src/feature/dirclient/.may_include1
-rw-r--r--src/feature/dirclient/dir_server_st.h7
-rw-r--r--src/feature/dirclient/dirclient.c144
-rw-r--r--src/feature/dirclient/dirclient.h6
-rw-r--r--src/feature/dirclient/dirclient_modes.c96
-rw-r--r--src/feature/dirclient/dirclient_modes.h24
-rw-r--r--src/feature/dirclient/dlstatus.c7
-rw-r--r--src/feature/dirclient/dlstatus.h2
-rw-r--r--src/feature/dirclient/download_status_st.h8
-rw-r--r--src/feature/dirclient/feature_dirclient.md7
-rw-r--r--src/feature/dirclient/include.am14
-rw-r--r--src/feature/dircommon/.may_include1
-rw-r--r--src/feature/dircommon/consdiff.c8
-rw-r--r--src/feature/dircommon/consdiff.h7
-rw-r--r--src/feature/dircommon/dir_connection_st.h11
-rw-r--r--src/feature/dircommon/directory.c33
-rw-r--r--src/feature/dircommon/directory.h8
-rw-r--r--src/feature/dircommon/feature_dircommon.md7
-rw-r--r--src/feature/dircommon/fp_pair.c19
-rw-r--r--src/feature/dircommon/fp_pair.h6
-rw-r--r--src/feature/dircommon/include.am14
-rw-r--r--src/feature/dircommon/vote_timing_st.h8
-rw-r--r--src/feature/dirparse/.may_include1
-rw-r--r--src/feature/dirparse/authcert_members.h31
-rw-r--r--src/feature/dirparse/authcert_members.i13
-rw-r--r--src/feature/dirparse/authcert_parse.c12
-rw-r--r--src/feature/dirparse/authcert_parse.h2
-rw-r--r--src/feature/dirparse/feature_dirparse.md8
-rw-r--r--src/feature/dirparse/include.am25
-rw-r--r--src/feature/dirparse/microdesc_parse.c6
-rw-r--r--src/feature/dirparse/microdesc_parse.h2
-rw-r--r--src/feature/dirparse/ns_parse.c13
-rw-r--r--src/feature/dirparse/ns_parse.h2
-rw-r--r--src/feature/dirparse/parsecommon.c2
-rw-r--r--src/feature/dirparse/parsecommon.h2
-rw-r--r--src/feature/dirparse/policy_parse.c4
-rw-r--r--src/feature/dirparse/policy_parse.h2
-rw-r--r--src/feature/dirparse/routerparse.c8
-rw-r--r--src/feature/dirparse/routerparse.h5
-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.c7
-rw-r--r--src/feature/dirparse/unparseable.h2
-rw-r--r--src/feature/feature.md7
-rw-r--r--src/feature/hibernate/.may_include1
-rw-r--r--src/feature/hibernate/feature_hibernate.md14
-rw-r--r--src/feature/hibernate/hibernate.c2
-rw-r--r--src/feature/hibernate/hibernate.h2
-rw-r--r--src/feature/hibernate/include.am8
-rw-r--r--src/feature/hs/.may_include2
-rw-r--r--src/feature/hs/feature_hs.md8
-rw-r--r--src/feature/hs/hs_cache.c285
-rw-r--r--src/feature/hs/hs_cache.h45
-rw-r--r--src/feature/hs/hs_cell.c188
-rw-r--r--src/feature/hs/hs_cell.h60
-rw-r--r--src/feature/hs/hs_circuit.c303
-rw-r--r--src/feature/hs/hs_circuit.h28
-rw-r--r--src/feature/hs/hs_circuitmap.c69
-rw-r--r--src/feature/hs/hs_circuitmap.h13
-rw-r--r--src/feature/hs/hs_client.c1093
-rw-r--r--src/feature/hs/hs_client.h85
-rw-r--r--src/feature/hs/hs_common.c157
-rw-r--r--src/feature/hs/hs_common.h79
-rw-r--r--src/feature/hs/hs_config.c514
-rw-r--r--src/feature/hs/hs_config.h5
-rw-r--r--src/feature/hs/hs_control.c20
-rw-r--r--src/feature/hs/hs_control.h2
-rw-r--r--src/feature/hs/hs_descriptor.c265
-rw-r--r--src/feature/hs/hs_descriptor.h138
-rw-r--r--src/feature/hs/hs_dos.c53
-rw-r--r--src/feature/hs/hs_dos.h5
-rw-r--r--src/feature/hs/hs_ident.c21
-rw-r--r--src/feature/hs/hs_ident.h42
-rw-r--r--src/feature/hs/hs_intropoint.c32
-rw-r--r--src/feature/hs/hs_intropoint.h11
-rw-r--r--src/feature/hs/hs_ob.c408
-rw-r--r--src/feature/hs/hs_ob.h40
-rw-r--r--src/feature/hs/hs_options.inc36
-rw-r--r--src/feature/hs/hs_opts_st.h30
-rw-r--r--src/feature/hs/hs_service.c494
-rw-r--r--src/feature/hs/hs_service.h171
-rw-r--r--src/feature/hs/hs_stats.c2
-rw-r--r--src/feature/hs/hs_stats.h2
-rw-r--r--src/feature/hs/hsdir_index_st.h15
-rw-r--r--src/feature/hs/include.am39
-rw-r--r--src/feature/hs_common/.may_include1
-rw-r--r--src/feature/hs_common/feature_hs_common.md3
-rw-r--r--src/feature/hs_common/include.am10
-rw-r--r--src/feature/hs_common/replaycache.c2
-rw-r--r--src/feature/hs_common/replaycache.h15
-rw-r--r--src/feature/hs_common/shared_random_client.c102
-rw-r--r--src/feature/hs_common/shared_random_client.h4
-rw-r--r--src/feature/keymgt/.may_include1
-rw-r--r--src/feature/keymgt/feature_keymgt.md3
-rw-r--r--src/feature/keymgt/include.am8
-rw-r--r--src/feature/keymgt/loadkey.c4
-rw-r--r--src/feature/keymgt/loadkey.h2
-rw-r--r--src/feature/nodelist/.may_include1
-rw-r--r--src/feature/nodelist/authcert.c16
-rw-r--r--src/feature/nodelist/authcert.h2
-rw-r--r--src/feature/nodelist/authority_cert_st.h8
-rw-r--r--src/feature/nodelist/desc_store_st.h7
-rw-r--r--src/feature/nodelist/describe.c2
-rw-r--r--src/feature/nodelist/describe.h2
-rw-r--r--src/feature/nodelist/dirlist.c6
-rw-r--r--src/feature/nodelist/dirlist.h2
-rw-r--r--src/feature/nodelist/document_signature_st.h8
-rw-r--r--src/feature/nodelist/extrainfo_st.h8
-rw-r--r--src/feature/nodelist/feature_nodelist.md2
-rw-r--r--src/feature/nodelist/fmt_routerstatus.c21
-rw-r--r--src/feature/nodelist/fmt_routerstatus.h3
-rw-r--r--src/feature/nodelist/include.am49
-rw-r--r--src/feature/nodelist/microdesc.c9
-rw-r--r--src/feature/nodelist/microdesc.h2
-rw-r--r--src/feature/nodelist/microdesc_st.h9
-rw-r--r--src/feature/nodelist/networkstatus.c122
-rw-r--r--src/feature/nodelist/networkstatus.h11
-rw-r--r--src/feature/nodelist/networkstatus_sr_info_st.h8
-rw-r--r--src/feature/nodelist/networkstatus_st.h7
-rw-r--r--src/feature/nodelist/networkstatus_voter_info_st.h7
-rw-r--r--src/feature/nodelist/nickname.c2
-rw-r--r--src/feature/nodelist/nickname.h2
-rw-r--r--src/feature/nodelist/node_select.c63
-rw-r--r--src/feature/nodelist/node_select.h2
-rw-r--r--src/feature/nodelist/node_st.h8
-rw-r--r--src/feature/nodelist/nodefamily.c6
-rw-r--r--src/feature/nodelist/nodefamily.h2
-rw-r--r--src/feature/nodelist/nodefamily_st.h7
-rw-r--r--src/feature/nodelist/nodelist.c28
-rw-r--r--src/feature/nodelist/nodelist.h14
-rw-r--r--src/feature/nodelist/routerinfo.c7
-rw-r--r--src/feature/nodelist/routerinfo.h2
-rw-r--r--src/feature/nodelist/routerinfo_st.h10
-rw-r--r--src/feature/nodelist/routerlist.c32
-rw-r--r--src/feature/nodelist/routerlist.h2
-rw-r--r--src/feature/nodelist/routerlist_st.h8
-rw-r--r--src/feature/nodelist/routerset.c4
-rw-r--r--src/feature/nodelist/routerset.h5
-rw-r--r--src/feature/nodelist/routerstatus_st.h12
-rw-r--r--src/feature/nodelist/signed_descriptor_st.h8
-rw-r--r--src/feature/nodelist/torcert.c2
-rw-r--r--src/feature/nodelist/torcert.h7
-rw-r--r--src/feature/nodelist/vote_routerstatus_st.h6
-rw-r--r--src/feature/relay/.may_include1
-rw-r--r--src/feature/relay/circuitbuild_relay.c549
-rw-r--r--src/feature/relay/circuitbuild_relay.h87
-rw-r--r--src/feature/relay/dns.c79
-rw-r--r--src/feature/relay/dns.h63
-rw-r--r--src/feature/relay/dns_structs.h5
-rw-r--r--src/feature/relay/ext_orport.c79
-rw-r--r--src/feature/relay/ext_orport.h57
-rw-r--r--src/feature/relay/feature_relay.md4
-rw-r--r--src/feature/relay/include.am46
-rw-r--r--src/feature/relay/onion_queue.c8
-rw-r--r--src/feature/relay/onion_queue.h2
-rw-r--r--src/feature/relay/relay_config.c1444
-rw-r--r--src/feature/relay/relay_config.h196
-rw-r--r--src/feature/relay/relay_find_addr.c133
-rw-r--r--src/feature/relay/relay_find_addr.h23
-rw-r--r--src/feature/relay/relay_handshake.c565
-rw-r--r--src/feature/relay/relay_handshake.h90
-rw-r--r--src/feature/relay/relay_periodic.c47
-rw-r--r--src/feature/relay/relay_periodic.h15
-rw-r--r--src/feature/relay/relay_stub.c21
-rw-r--r--src/feature/relay/relay_sys.c5
-rw-r--r--src/feature/relay/relay_sys.h10
-rw-r--r--src/feature/relay/router.c258
-rw-r--r--src/feature/relay/router.h21
-rw-r--r--src/feature/relay/routerkeys.c2
-rw-r--r--src/feature/relay/routerkeys.h89
-rw-r--r--src/feature/relay/routermode.c24
-rw-r--r--src/feature/relay/routermode.h22
-rw-r--r--src/feature/relay/selftest.c52
-rw-r--r--src/feature/relay/selftest.h48
-rw-r--r--src/feature/relay/transport_config.c307
-rw-r--r--src/feature/relay/transport_config.h85
-rw-r--r--src/feature/rend/.may_include1
-rw-r--r--src/feature/rend/feature_rend.md7
-rw-r--r--src/feature/rend/include.am22
-rw-r--r--src/feature/rend/rend_authorized_client_st.h8
-rw-r--r--src/feature/rend/rend_encoded_v2_service_descriptor_st.h8
-rw-r--r--src/feature/rend/rend_intro_point_st.h7
-rw-r--r--src/feature/rend/rend_service_descriptor_st.h8
-rw-r--r--src/feature/rend/rendcache.c22
-rw-r--r--src/feature/rend/rendcache.h4
-rw-r--r--src/feature/rend/rendclient.c89
-rw-r--r--src/feature/rend/rendclient.h5
-rw-r--r--src/feature/rend/rendcommon.c2
-rw-r--r--src/feature/rend/rendcommon.h2
-rw-r--r--src/feature/rend/rendmid.c24
-rw-r--r--src/feature/rend/rendmid.h2
-rw-r--r--src/feature/rend/rendparse.c2
-rw-r--r--src/feature/rend/rendparse.h6
-rw-r--r--src/feature/rend/rendservice.c265
-rw-r--r--src/feature/rend/rendservice.h5
-rw-r--r--src/feature/stats/.may_include1
-rw-r--r--src/feature/stats/feature_stats.md10
-rw-r--r--src/feature/stats/geoip_stats.c10
-rw-r--r--src/feature/stats/geoip_stats.h3
-rw-r--r--src/feature/stats/include.am12
-rw-r--r--src/feature/stats/predict_ports.c2
-rw-r--r--src/feature/stats/predict_ports.h4
-rw-r--r--src/feature/stats/rephist.c8
-rw-r--r--src/feature/stats/rephist.h2
-rw-r--r--src/include.am38
-rw-r--r--src/lib/arch/bytes.h23
-rw-r--r--src/lib/arch/lib_arch.md2
-rw-r--r--src/lib/buf/buffers.c35
-rw-r--r--src/lib/buf/buffers.h5
-rw-r--r--src/lib/buf/lib_buf.md13
-rw-r--r--src/lib/cc/compat_compiler.h39
-rw-r--r--src/lib/cc/ctassert.h2
-rw-r--r--src/lib/cc/include.am1
-rw-r--r--src/lib/cc/lib_cc.md2
-rw-r--r--src/lib/cc/tokpaste.h30
-rw-r--r--src/lib/cc/torint.h9
-rw-r--r--src/lib/compress/compress.c5
-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.c6
-rw-r--r--src/lib/compress/compress_zstd.h2
-rw-r--r--src/lib/compress/lib_compress.md6
-rw-r--r--src/lib/conf/confdecl.h221
-rw-r--r--src/lib/conf/config.md126
-rw-r--r--src/lib/conf/confmacros.h9
-rw-r--r--src/lib/conf/conftesting.h19
-rw-r--r--src/lib/conf/conftypes.h187
-rw-r--r--src/lib/conf/include.am1
-rw-r--r--src/lib/conf/lib_conf.md3
-rw-r--r--src/lib/confmgt/.may_include1
-rw-r--r--src/lib/confmgt/confmgt.c (renamed from src/lib/confmgt/confparse.c)191
-rw-r--r--src/lib/confmgt/confmgt.h (renamed from src/lib/confmgt/confparse.h)134
-rw-r--r--src/lib/confmgt/include.am4
-rw-r--r--src/lib/confmgt/lib_confmgt.md7
-rw-r--r--src/lib/confmgt/structvar.c24
-rw-r--r--src/lib/confmgt/structvar.h2
-rw-r--r--src/lib/confmgt/type_defs.c244
-rw-r--r--src/lib/confmgt/type_defs.h2
-rw-r--r--src/lib/confmgt/typedvar.c22
-rw-r--r--src/lib/confmgt/typedvar.h4
-rw-r--r--src/lib/confmgt/unitparse.c76
-rw-r--r--src/lib/confmgt/unitparse.h5
-rw-r--r--src/lib/confmgt/var_type_def_st.h7
-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.h25
-rw-r--r--src/lib/container/lib_container.md49
-rw-r--r--src/lib/container/map.c14
-rw-r--r--src/lib/container/map.h129
-rw-r--r--src/lib/container/namemap.c11
-rw-r--r--src/lib/container/namemap.h2
-rw-r--r--src/lib/container/namemap_st.h9
-rw-r--r--src/lib/container/order.c2
-rw-r--r--src/lib/container/order.h2
-rw-r--r--src/lib/container/smartlist.c4
-rw-r--r--src/lib/container/smartlist.h4
-rw-r--r--src/lib/crypt_ops/.may_include3
-rw-r--r--src/lib/crypt_ops/aes.h4
-rw-r--r--src/lib/crypt_ops/aes_nss.c6
-rw-r--r--src/lib/crypt_ops/aes_openssl.c9
-rw-r--r--src/lib/crypt_ops/certs.md29
-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.h4
-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.c4
-rw-r--r--src/lib/crypt_ops/crypto_dh_openssl.c8
-rw-r--r--src/lib/crypt_ops/crypto_digest.c5
-rw-r--r--src/lib/crypt_ops/crypto_digest.h35
-rw-r--r--src/lib/crypt_ops/crypto_digest_nss.c12
-rw-r--r--src/lib/crypt_ops/crypto_digest_openssl.c11
-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.c69
-rw-r--r--src/lib/crypt_ops/crypto_init.h2
-rw-r--r--src/lib/crypt_ops/crypto_nss_mgt.c6
-rw-r--r--src/lib/crypt_ops/crypto_nss_mgt.h2
-rw-r--r--src/lib/crypt_ops/crypto_ope.c7
-rw-r--r--src/lib/crypt_ops/crypto_ope.h13
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.c44
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.h2
-rw-r--r--src/lib/crypt_ops/crypto_options.inc19
-rw-r--r--src/lib/crypt_ops/crypto_options_st.h23
-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.c6
-rw-r--r--src/lib/crypt_ops/crypto_rand.h2
-rw-r--r--src/lib/crypt_ops/crypto_rand_fast.c13
-rw-r--r--src/lib/crypt_ops/crypto_rand_numeric.c4
-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.c4
-rw-r--r--src/lib/crypt_ops/crypto_rsa_openssl.c14
-rw-r--r--src/lib/crypt_ops/crypto_s2k.c4
-rw-r--r--src/lib/crypt_ops/crypto_s2k.h2
-rw-r--r--src/lib/crypt_ops/crypto_sys.h4
-rw-r--r--src/lib/crypt_ops/crypto_util.c22
-rw-r--r--src/lib/crypt_ops/crypto_util.h12
-rw-r--r--src/lib/crypt_ops/digestset.c2
-rw-r--r--src/lib/crypt_ops/digestset.h2
-rw-r--r--src/lib/crypt_ops/include.am2
-rw-r--r--src/lib/crypt_ops/lib_crypt_ops.md137
-rw-r--r--src/lib/ctime/di_ops.c36
-rw-r--r--src/lib/ctime/di_ops.h27
-rw-r--r--src/lib/ctime/lib_ctime.md14
-rw-r--r--src/lib/defs/dh_sizes.h2
-rw-r--r--src/lib/defs/digest_sizes.h2
-rw-r--r--src/lib/defs/lib_defs.md2
-rw-r--r--src/lib/defs/logging_types.h2
-rw-r--r--src/lib/defs/time.h4
-rw-r--r--src/lib/defs/x25519_sizes.h10
-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.h7
-rw-r--r--src/lib/dispatch/dispatch_cfg_st.h14
-rw-r--r--src/lib/dispatch/dispatch_core.c2
-rw-r--r--src/lib/dispatch/dispatch_naming.c9
-rw-r--r--src/lib/dispatch/dispatch_naming.h7
-rw-r--r--src/lib/dispatch/dispatch_new.c2
-rw-r--r--src/lib/dispatch/dispatch_st.h2
-rw-r--r--src/lib/dispatch/lib_dispatch.md14
-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.c36
-rw-r--r--src/lib/encoding/confline.h3
-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.c54
-rw-r--r--src/lib/encoding/kvline.h3
-rw-r--r--src/lib/encoding/lib_encoding.md6
-rw-r--r--src/lib/encoding/pem.c4
-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.c4
-rw-r--r--src/lib/err/backtrace.h6
-rw-r--r--src/lib/err/lib_err.md13
-rw-r--r--src/lib/err/torerr.c31
-rw-r--r--src/lib/err/torerr.h3
-rw-r--r--src/lib/err/torerr_sys.c6
-rw-r--r--src/lib/err/torerr_sys.h2
-rw-r--r--src/lib/evloop/compat_libevent.c6
-rw-r--r--src/lib/evloop/compat_libevent.h8
-rw-r--r--src/lib/evloop/evloop_sys.c3
-rw-r--r--src/lib/evloop/evloop_sys.h2
-rw-r--r--src/lib/evloop/lib_evloop.md7
-rw-r--r--src/lib/evloop/procmon.c6
-rw-r--r--src/lib/evloop/procmon.h2
-rw-r--r--src/lib/evloop/time_periodic.md76
-rw-r--r--src/lib/evloop/timers.c14
-rw-r--r--src/lib/evloop/timers.h3
-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.c20
-rw-r--r--src/lib/evloop/workqueue.h8
-rw-r--r--src/lib/fdio/fdio.c9
-rw-r--r--src/lib/fdio/fdio.h5
-rw-r--r--src/lib/fdio/lib_fdio.md5
-rw-r--r--src/lib/fs/conffile.c3
-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/lib_fs.md9
-rw-r--r--src/lib/fs/lockfile.c2
-rw-r--r--src/lib/fs/lockfile.h2
-rw-r--r--src/lib/fs/mmap.c18
-rw-r--r--src/lib/fs/mmap.h7
-rw-r--r--src/lib/fs/path.c7
-rw-r--r--src/lib/fs/path.h4
-rw-r--r--src/lib/fs/storagedir.c2
-rw-r--r--src/lib/fs/storagedir.h6
-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.h8
-rw-r--r--src/lib/geoip/geoip.c18
-rw-r--r--src/lib/geoip/geoip.h3
-rw-r--r--src/lib/geoip/lib_geoip.md3
-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/lib_intmath.md2
-rw-r--r--src/lib/intmath/logic.h2
-rw-r--r--src/lib/intmath/muldiv.c16
-rw-r--r--src/lib/intmath/muldiv.h4
-rw-r--r--src/lib/intmath/weakrng.c2
-rw-r--r--src/lib/intmath/weakrng.h5
-rw-r--r--src/lib/lib.md131
-rw-r--r--src/lib/llharden/.may_include3
-rw-r--r--src/lib/llharden/include.am19
-rw-r--r--src/lib/llharden/lib_llharden.md6
-rw-r--r--src/lib/llharden/winprocess_sys.c (renamed from src/lib/process/winprocess_sys.c)5
-rw-r--r--src/lib/llharden/winprocess_sys.h (renamed from src/lib/process/winprocess_sys.h)2
-rw-r--r--src/lib/lock/compat_mutex.c2
-rw-r--r--src/lib/lock/compat_mutex.h7
-rw-r--r--src/lib/lock/compat_mutex_pthreads.c8
-rw-r--r--src/lib/lock/compat_mutex_winthreads.c2
-rw-r--r--src/lib/lock/lib_lock.md6
-rw-r--r--src/lib/log/escape.c2
-rw-r--r--src/lib/log/escape.h2
-rw-r--r--src/lib/log/lib_log.md10
-rw-r--r--src/lib/log/log.c97
-rw-r--r--src/lib/log/log.h23
-rw-r--r--src/lib/log/log_sys.c3
-rw-r--r--src/lib/log/log_sys.h2
-rw-r--r--src/lib/log/ratelim.c2
-rw-r--r--src/lib/log/ratelim.h4
-rw-r--r--src/lib/log/util_bug.c8
-rw-r--r--src/lib/log/util_bug.h34
-rw-r--r--src/lib/log/win32err.c2
-rw-r--r--src/lib/log/win32err.h2
-rw-r--r--src/lib/malloc/lib_malloc.md76
-rw-r--r--src/lib/malloc/malloc.c2
-rw-r--r--src/lib/malloc/malloc.h2
-rw-r--r--src/lib/malloc/map_anon.c6
-rw-r--r--src/lib/malloc/map_anon.h2
-rw-r--r--src/lib/math/fp.c18
-rw-r--r--src/lib/math/fp.h2
-rw-r--r--src/lib/math/laplace.c4
-rw-r--r--src/lib/math/laplace.h2
-rw-r--r--src/lib/math/lib_math.md6
-rw-r--r--src/lib/math/prob_distr.c238
-rw-r--r--src/lib/math/prob_distr.h132
-rw-r--r--src/lib/memarea/lib_memarea.md28
-rw-r--r--src/lib/memarea/memarea.c4
-rw-r--r--src/lib/memarea/memarea.h5
-rw-r--r--src/lib/meminfo/lib_meminfo.md5
-rw-r--r--src/lib/meminfo/meminfo.c6
-rw-r--r--src/lib/meminfo/meminfo.h2
-rw-r--r--src/lib/net/.may_include3
-rw-r--r--src/lib/net/address.c123
-rw-r--r--src/lib/net/address.h52
-rw-r--r--src/lib/net/alertsock.c2
-rw-r--r--src/lib/net/alertsock.h2
-rw-r--r--src/lib/net/buffers_net.c14
-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.c29
-rw-r--r--src/lib/net/inaddr.h2
-rw-r--r--src/lib/net/inaddr_st.h2
-rw-r--r--src/lib/net/lib_net.md6
-rw-r--r--src/lib/net/nettypes.h2
-rw-r--r--src/lib/net/network_sys.c5
-rw-r--r--src/lib/net/network_sys.h4
-rw-r--r--src/lib/net/resolve.c6
-rw-r--r--src/lib/net/resolve.h2
-rw-r--r--src/lib/net/socket.c3
-rw-r--r--src/lib/net/socket.h2
-rw-r--r--src/lib/net/socketpair.c7
-rw-r--r--src/lib/net/socketpair.h7
-rw-r--r--src/lib/net/socks5_status.h13
-rw-r--r--src/lib/osinfo/lib_osinfo.md8
-rw-r--r--src/lib/osinfo/uname.c61
-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.c3
-rw-r--r--src/lib/process/env.h2
-rw-r--r--src/lib/process/include.am6
-rw-r--r--src/lib/process/lib_process.md2
-rw-r--r--src/lib/process/pidfile.c2
-rw-r--r--src/lib/process/pidfile.h2
-rw-r--r--src/lib/process/process.c3
-rw-r--r--src/lib/process/process.h21
-rw-r--r--src/lib/process/process_sys.c5
-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.c8
-rw-r--r--src/lib/process/restrict.h2
-rw-r--r--src/lib/process/setuid.c6
-rw-r--r--src/lib/process/setuid.h2
-rw-r--r--src/lib/process/waitpid.c6
-rw-r--r--src/lib/process/waitpid.h2
-rw-r--r--src/lib/pubsub/lib_pubsub.md14
-rw-r--r--src/lib/pubsub/pub_binding_st.h2
-rw-r--r--src/lib/pubsub/publish_subscribe.md144
-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.h7
-rw-r--r--src/lib/pubsub/pubsub_builder_st.h2
-rw-r--r--src/lib/pubsub/pubsub_check.c4
-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.h10
-rw-r--r--src/lib/pubsub/pubsub_publish.c2
-rw-r--r--src/lib/pubsub/pubsub_publish.h7
-rw-r--r--src/lib/sandbox/lib_sandbox.md15
-rw-r--r--src/lib/sandbox/sandbox.c158
-rw-r--r--src/lib/sandbox/sandbox.h19
-rw-r--r--src/lib/smartlist_core/lib_smartlist_core.md10
-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.c3
-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/lib_string.md13
-rw-r--r--src/lib/string/parse_int.c7
-rw-r--r--src/lib/string/parse_int.h2
-rw-r--r--src/lib/string/printf.c2
-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/strings.md102
-rw-r--r--src/lib/string/util_string.c23
-rw-r--r--src/lib/string/util_string.h2
-rw-r--r--src/lib/subsys/initialization.md75
-rw-r--r--src/lib/subsys/lib_subsys.md32
-rw-r--r--src/lib/subsys/subsys.h135
-rw-r--r--src/lib/term/getpass.c2
-rw-r--r--src/lib/term/getpass.h2
-rw-r--r--src/lib/term/lib_term.md2
-rw-r--r--src/lib/testsupport/lib_testsupport.md2
-rw-r--r--src/lib/testsupport/testsupport.h55
-rw-r--r--src/lib/thread/compat_pthreads.c2
-rw-r--r--src/lib/thread/compat_threads.c7
-rw-r--r--src/lib/thread/compat_winthreads.c2
-rw-r--r--src/lib/thread/lib_thread.md7
-rw-r--r--src/lib/thread/numcpus.c2
-rw-r--r--src/lib/thread/numcpus.h2
-rw-r--r--src/lib/thread/thread_sys.h4
-rw-r--r--src/lib/thread/threading.md26
-rw-r--r--src/lib/thread/threads.h6
-rw-r--r--src/lib/time/compat_time.c2
-rw-r--r--src/lib/time/compat_time.h2
-rw-r--r--src/lib/time/lib_time.md9
-rw-r--r--src/lib/time/time_sys.c3
-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.c14
-rw-r--r--src/lib/tls/buffers_tls.h2
-rw-r--r--src/lib/tls/lib_tls.md11
-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.c8
-rw-r--r--src/lib/tls/tortls.h3
-rw-r--r--src/lib/tls/tortls_internal.h9
-rw-r--r--src/lib/tls/tortls_nss.c29
-rw-r--r--src/lib/tls/tortls_openssl.c28
-rw-r--r--src/lib/tls/tortls_st.h13
-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.c6
-rw-r--r--src/lib/trace/debug.h2
-rw-r--r--src/lib/trace/events.h2
-rw-r--r--src/lib/trace/lib_trace.md6
-rw-r--r--src/lib/trace/trace.c2
-rw-r--r--src/lib/trace/trace.h2
-rw-r--r--src/lib/version/git_revision.c17
-rw-r--r--src/lib/version/git_revision.h7
-rw-r--r--src/lib/version/lib_version.md2
-rw-r--r--src/lib/version/torversion.h7
-rw-r--r--src/lib/version/version.c11
-rw-r--r--src/lib/wallclock/approx_time.c9
-rw-r--r--src/lib/wallclock/approx_time.h2
-rw-r--r--src/lib/wallclock/lib_wallclock.md11
-rw-r--r--src/lib/wallclock/time_to_tm.c3
-rw-r--r--src/lib/wallclock/time_to_tm.h2
-rw-r--r--src/lib/wallclock/timeval.h4
-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/mainpage.md150
-rw-r--r--src/rust/protover/protover.rs8
-rw-r--r--src/test/.may_include2
-rw-r--r--src/test/bench.c2
-rwxr-xr-xsrc/test/bt_test.py4
-rw-r--r--src/test/conf_examples/badnick_1/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/badnick_1/expected_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/badnick_1/torrc2
-rw-r--r--src/test/conf_examples/badnick_2/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/badnick_2/expected_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/badnick_2/torrc2
-rw-r--r--src/test/conf_examples/bridgeauth_1/error_no_dirauth1
-rw-r--r--src/test/conf_examples/bridgeauth_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/bridgeauth_1/expected7
-rw-r--r--src/test/conf_examples/bridgeauth_1/expected_log1
-rw-r--r--src/test/conf_examples/bridgeauth_1/torrc8
-rw-r--r--src/test/conf_examples/contactinfo_notutf8/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/contactinfo_notutf8/expected_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/contactinfo_notutf8/torrc4
-rw-r--r--src/test/conf_examples/controlsock/error1
-rw-r--r--src/test/conf_examples/controlsock/torrc1
-rw-r--r--src/test/conf_examples/crypto_accel/expected2
-rw-r--r--src/test/conf_examples/crypto_accel/expected_log1
-rw-r--r--src/test/conf_examples/crypto_accel/expected_log_nss1
-rw-r--r--src/test/conf_examples/crypto_accel/expected_nss2
-rw-r--r--src/test/conf_examples/crypto_accel/torrc3
-rw-r--r--src/test/conf_examples/crypto_accel_req/error1
-rw-r--r--src/test/conf_examples/crypto_accel_req/expected_log_nss1
-rw-r--r--src/test/conf_examples/crypto_accel_req/expected_nss2
-rw-r--r--src/test/conf_examples/crypto_accel_req/torrc3
-rw-r--r--src/test/conf_examples/dirauth_1/error_no_dirauth1
-rw-r--r--src/test/conf_examples/dirauth_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/dirauth_1/expected8
-rw-r--r--src/test/conf_examples/dirauth_1/expected_log1
-rw-r--r--src/test/conf_examples/dirauth_1/torrc8
-rw-r--r--src/test/conf_examples/dirauth_2/expected1
-rw-r--r--src/test/conf_examples/dirauth_2/expected_log1
-rw-r--r--src/test/conf_examples/dirauth_2/expected_log_no_dirauth1
-rw-r--r--src/test/conf_examples/dirauth_2/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/dirauth_2/expected_no_dirauth0
-rw-r--r--src/test/conf_examples/dirauth_2/expected_no_dirauth_relay0
-rw-r--r--src/test/conf_examples/dirauth_2/torrc5
-rw-r--r--src/test/conf_examples/empty_1/expected0
-rw-r--r--src/test/conf_examples/empty_1/expected_log1
-rw-r--r--src/test/conf_examples/empty_1/torrc0
-rw-r--r--src/test/conf_examples/empty_2/cmdline0
-rw-r--r--src/test/conf_examples/empty_2/expected0
-rw-r--r--src/test/conf_examples/empty_2/expected_log1
-rw-r--r--src/test/conf_examples/empty_2/torrc0
-rw-r--r--src/test/conf_examples/empty_2/torrc.defaults0
-rw-r--r--src/test/conf_examples/empty_3/expected0
-rw-r--r--src/test/conf_examples/empty_3/expected_log1
-rw-r--r--src/test/conf_examples/empty_3/included/empty0
-rw-r--r--src/test/conf_examples/empty_3/torrc1
-rw-r--r--src/test/conf_examples/empty_4/error1
-rw-r--r--src/test/conf_examples/example_1/expected_log1
-rw-r--r--src/test/conf_examples/example_3/expected_log1
-rw-r--r--src/test/conf_examples/include_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/include_1/expected_log1
-rw-r--r--src/test/conf_examples/include_bug_31408/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/include_bug_31408/expected_log1
-rw-r--r--src/test/conf_examples/large_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/large_1/expected1
-rw-r--r--src/test/conf_examples/large_1/expected_log1
-rw-r--r--src/test/conf_examples/large_1/expected_log_no_dirauth1
-rw-r--r--src/test/conf_examples/large_1/expected_no_dirauth157
-rw-r--r--src/test/conf_examples/large_1/torrc1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected0
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_lzma1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_zstd1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_lzma0
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_lzma_zstd0
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_zstd0
-rw-r--r--src/test/conf_examples/lzma_zstd_1/torrc1
-rw-r--r--src/test/conf_examples/missing_cl_arg/cmdline1
-rw-r--r--src/test/conf_examples/missing_cl_arg/error1
-rw-r--r--src/test/conf_examples/missing_cl_arg/torrc0
-rw-r--r--src/test/conf_examples/nss_1/expected0
-rw-r--r--src/test/conf_examples/nss_1/expected_log1
-rw-r--r--src/test/conf_examples/nss_1/expected_log_nss1
-rw-r--r--src/test/conf_examples/nss_1/expected_nss0
-rw-r--r--src/test/conf_examples/nss_1/torrc1
-rw-r--r--src/test/conf_examples/obsolete_1/expected_log1
-rw-r--r--src/test/conf_examples/obsolete_1/torrc136
-rw-r--r--src/test/conf_examples/obsolete_2/expected_log1
-rw-r--r--src/test/conf_examples/obsolete_2/torrc3
-rw-r--r--src/test/conf_examples/obsolete_3/expected0
-rw-r--r--src/test/conf_examples/obsolete_3/expected_log1
-rw-r--r--src/test/conf_examples/obsolete_3/torrc4
-rw-r--r--src/test/conf_examples/ops_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/ops_1/expected_log1
-rw-r--r--src/test/conf_examples/ops_2/expected_log1
-rw-r--r--src/test/conf_examples/ops_3/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/ops_3/expected_log1
-rw-r--r--src/test/conf_examples/ops_4/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/ops_4/expected_log1
-rw-r--r--src/test/conf_examples/ops_5/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/ops_5/expected_log1
-rw-r--r--src/test/conf_examples/ops_6/expected_log1
-rw-r--r--src/test/conf_examples/pt_01/expected0
-rw-r--r--src/test/conf_examples/pt_01/expected_log1
-rw-r--r--src/test/conf_examples/pt_01/torrc7
-rw-r--r--src/test/conf_examples/pt_02/error1
-rw-r--r--src/test/conf_examples/pt_02/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_02/expected_no_dirauth_relay8
-rw-r--r--src/test/conf_examples/pt_02/torrc13
-rw-r--r--src/test/conf_examples/pt_03/expected1
-rw-r--r--src/test/conf_examples/pt_03/expected_log1
-rw-r--r--src/test/conf_examples/pt_03/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_03/expected_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_03/torrc4
-rw-r--r--src/test/conf_examples/pt_04/expected3
-rw-r--r--src/test/conf_examples/pt_04/expected_log1
-rw-r--r--src/test/conf_examples/pt_04/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_04/expected_no_dirauth_relay3
-rw-r--r--src/test/conf_examples/pt_04/torrc6
-rw-r--r--src/test/conf_examples/pt_05/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_05/expected4
-rw-r--r--src/test/conf_examples/pt_05/expected_log1
-rw-r--r--src/test/conf_examples/pt_05/torrc6
-rw-r--r--src/test/conf_examples/pt_06/expected6
-rw-r--r--src/test/conf_examples/pt_06/expected_log1
-rw-r--r--src/test/conf_examples/pt_06/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_06/expected_no_dirauth_relay6
-rw-r--r--src/test/conf_examples/pt_06/torrc9
-rw-r--r--src/test/conf_examples/pt_07/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_07/expected4
-rw-r--r--src/test/conf_examples/pt_07/expected_log1
-rw-r--r--src/test/conf_examples/pt_07/torrc6
-rw-r--r--src/test/conf_examples/pt_08/error1
-rw-r--r--src/test/conf_examples/pt_08/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_08/expected_no_dirauth_relay2
-rw-r--r--src/test/conf_examples/pt_08/torrc7
-rw-r--r--src/test/conf_examples/pt_09/error1
-rw-r--r--src/test/conf_examples/pt_09/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_09/torrc7
-rw-r--r--src/test/conf_examples/relay_01/expected0
-rw-r--r--src/test/conf_examples/relay_01/expected_log1
-rw-r--r--src/test/conf_examples/relay_01/torrc5
-rw-r--r--src/test/conf_examples/relay_02/error1
-rw-r--r--src/test/conf_examples/relay_02/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_02/torrc7
-rw-r--r--src/test/conf_examples/relay_03/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_03/expected2
-rw-r--r--src/test/conf_examples/relay_03/expected_log1
-rw-r--r--src/test/conf_examples/relay_03/torrc5
-rw-r--r--src/test/conf_examples/relay_04/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_04/expected2
-rw-r--r--src/test/conf_examples/relay_04/expected_log1
-rw-r--r--src/test/conf_examples/relay_04/torrc4
-rw-r--r--src/test/conf_examples/relay_05/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_05/expected3
-rw-r--r--src/test/conf_examples/relay_05/expected_log1
-rw-r--r--src/test/conf_examples/relay_05/torrc5
-rw-r--r--src/test/conf_examples/relay_06/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_06/expected3
-rw-r--r--src/test/conf_examples/relay_06/expected_log1
-rw-r--r--src/test/conf_examples/relay_06/torrc5
-rw-r--r--src/test/conf_examples/relay_07/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_07/expected3
-rw-r--r--src/test/conf_examples/relay_07/expected_log1
-rw-r--r--src/test/conf_examples/relay_07/torrc5
-rw-r--r--src/test/conf_examples/relay_08/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_08/expected3
-rw-r--r--src/test/conf_examples/relay_08/expected_log1
-rw-r--r--src/test/conf_examples/relay_08/torrc6
-rw-r--r--src/test/conf_examples/relay_09/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_09/expected3
-rw-r--r--src/test/conf_examples/relay_09/expected_log1
-rw-r--r--src/test/conf_examples/relay_09/torrc6
-rw-r--r--src/test/conf_examples/relay_10/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_10/expected3
-rw-r--r--src/test/conf_examples/relay_10/expected_log1
-rw-r--r--src/test/conf_examples/relay_10/torrc7
-rw-r--r--src/test/conf_examples/relay_11/error1
-rw-r--r--src/test/conf_examples/relay_11/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_11/torrc4
-rw-r--r--src/test/conf_examples/relay_12/error1
-rw-r--r--src/test/conf_examples/relay_12/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_12/torrc4
-rw-r--r--src/test/conf_examples/relay_13/error1
-rw-r--r--src/test/conf_examples/relay_13/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_13/torrc4
-rw-r--r--src/test/conf_examples/relay_14/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_14/expected1
-rw-r--r--src/test/conf_examples/relay_14/expected_log1
-rw-r--r--src/test/conf_examples/relay_14/torrc4
-rw-r--r--src/test/conf_examples/relay_15/error1
-rw-r--r--src/test/conf_examples/relay_15/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_15/torrc5
-rw-r--r--src/test/conf_examples/relay_16/error1
-rw-r--r--src/test/conf_examples/relay_16/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_16/torrc4
-rw-r--r--src/test/conf_examples/relay_17/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_17/expected4
-rw-r--r--src/test/conf_examples/relay_17/expected_log1
-rw-r--r--src/test/conf_examples/relay_17/torrc6
-rw-r--r--src/test/conf_examples/relay_18/error1
-rw-r--r--src/test/conf_examples/relay_18/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_18/torrc4
-rw-r--r--src/test/conf_examples/relay_19/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_19/expected3
-rw-r--r--src/test/conf_examples/relay_19/expected_log1
-rw-r--r--src/test/conf_examples/relay_19/torrc5
-rw-r--r--src/test/conf_examples/relay_20/error1
-rw-r--r--src/test/conf_examples/relay_20/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_20/torrc5
-rw-r--r--src/test/conf_examples/relay_21/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_21/expected3
-rw-r--r--src/test/conf_examples/relay_21/expected_log1
-rw-r--r--src/test/conf_examples/relay_21/torrc5
-rw-r--r--src/test/conf_examples/relay_22/error1
-rw-r--r--src/test/conf_examples/relay_22/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_22/torrc6
-rw-r--r--src/test/conf_examples/relay_23/error1
-rw-r--r--src/test/conf_examples/relay_23/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_23/torrc5
-rw-r--r--src/test/conf_examples/relay_24/error1
-rw-r--r--src/test/conf_examples/relay_24/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_24/torrc5
-rw-r--r--src/test/conf_examples/relay_25/error1
-rw-r--r--src/test/conf_examples/relay_25/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_25/torrc5
-rw-r--r--src/test/conf_examples/relay_26/error1
-rw-r--r--src/test/conf_examples/relay_26/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_26/torrc5
-rw-r--r--src/test/conf_examples/relay_27/error1
-rw-r--r--src/test/conf_examples/relay_27/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_27/torrc5
-rw-r--r--src/test/conf_examples/relay_28/error1
-rw-r--r--src/test/conf_examples/relay_28/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_28/torrc5
-rw-r--r--src/test/conf_examples/relay_29/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_29/expected2
-rw-r--r--src/test/conf_examples/relay_29/expected_log1
-rw-r--r--src/test/conf_examples/relay_29/torrc5
-rw-r--r--src/test/conf_examples/relay_30/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_30/expected2
-rw-r--r--src/test/conf_examples/relay_30/expected_log1
-rw-r--r--src/test/conf_examples/relay_30/torrc3
-rw-r--r--src/test/conf_examples/relay_31/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_31/expected3
-rw-r--r--src/test/conf_examples/relay_31/expected_log1
-rw-r--r--src/test/conf_examples/relay_31/torrc4
-rw-r--r--src/test/conf_examples/relay_32/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_32/expected3
-rw-r--r--src/test/conf_examples/relay_32/expected_log1
-rw-r--r--src/test/conf_examples/relay_32/torrc4
-rw-r--r--src/test/conf_examples/relay_33/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_33/expected3
-rw-r--r--src/test/conf_examples/relay_33/expected_log1
-rw-r--r--src/test/conf_examples/relay_33/torrc4
-rw-r--r--src/test/conf_examples/relay_34/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_34/expected4
-rw-r--r--src/test/conf_examples/relay_34/expected_log1
-rw-r--r--src/test/conf_examples/relay_34/torrc5
-rw-r--r--src/test/conf_failures/README5
-rw-r--r--src/test/conf_failures/fail-error-success/error1
-rw-r--r--src/test/conf_failures/fail-error-success/torrc0
-rw-r--r--src/test/conf_failures/fail-error/error1
-rw-r--r--src/test/conf_failures/fail-error/torrc1
-rw-r--r--src/test/conf_failures/fail-expected-error/expected0
-rw-r--r--src/test/conf_failures/fail-expected-error/torrc1
-rw-r--r--src/test/conf_failures/fail-expected-log/expected0
-rw-r--r--src/test/conf_failures/fail-expected-log/expected_log1
-rw-r--r--src/test/conf_failures/fail-expected-log/torrc0
-rw-r--r--src/test/conf_failures/fail-expected/expected1
-rw-r--r--src/test/conf_failures/fail-expected/torrc0
-rw-r--r--src/test/ed25519_exts_ref.py25
-rw-r--r--src/test/fakechans.h2
-rw-r--r--src/test/fakecircs.c91
-rw-r--r--src/test/fakecircs.h17
-rw-r--r--src/test/fuzz/.may_include1
-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.c2
-rw-r--r--src/test/fuzz/fuzz_hsdescv3.c9
-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/hs_build_address.py5
-rw-r--r--src/test/hs_indexes.py5
-rw-r--r--src/test/hs_ntor_ref.py5
-rw-r--r--src/test/hs_test_helpers.c124
-rw-r--r--src/test/hs_test_helpers.h24
-rw-r--r--src/test/include.am36
-rw-r--r--src/test/log_test_helpers.c2
-rw-r--r--src/test/log_test_helpers.h18
-rwxr-xr-xsrc/test/ntor_ref.py7
-rw-r--r--src/test/ope_ref.py5
-rw-r--r--src/test/opts_test_helpers.c38
-rw-r--r--src/test/opts_test_helpers.h22
-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.c2
-rw-r--r--src/test/rend_test_helpers.h2
-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/slow_ed25519.py7
-rw-r--r--src/test/slownacl_curve25519.py7
-rw-r--r--src/test/sr_commit_calc_ref.py5
-rw-r--r--src/test/sr_srv_calc_ref.py5
-rw-r--r--src/test/test-memwipe.c2
-rw-r--r--src/test/test-process.c2
-rw-r--r--src/test/test-timers.c4
-rw-r--r--src/test/test.c169
-rw-r--r--src/test/test.h102
-rw-r--r--src/test/test_accounting.c18
-rw-r--r--src/test/test_addr.c173
-rw-r--r--src/test/test_address.c6
-rw-r--r--src/test/test_address_set.c2
-rw-r--r--src/test/test_bridges.c4
-rw-r--r--src/test/test_bt_cl.c6
-rw-r--r--src/test/test_btrack.c2
-rw-r--r--src/test/test_buffers.c2
-rw-r--r--src/test/test_bwmgt.c12
-rw-r--r--src/test/test_cell_formats.c80
-rw-r--r--src/test/test_cell_queue.c2
-rw-r--r--src/test/test_channel.c84
-rw-r--r--src/test/test_channelpadding.c4
-rw-r--r--src/test/test_channeltls.c5
-rw-r--r--src/test/test_checkdir.c2
-rw-r--r--src/test/test_circuitbuild.c1389
-rw-r--r--src/test/test_circuitlist.c6
-rw-r--r--src/test/test_circuitmux.c395
-rw-r--r--src/test/test_circuitmux_ewma.c228
-rw-r--r--src/test/test_circuitpadding.c84
-rw-r--r--src/test/test_circuitstats.c4
-rw-r--r--src/test/test_circuituse.c2
-rwxr-xr-xsrc/test/test_cmdline.sh17
-rw-r--r--src/test/test_compat_libevent.c4
-rw-r--r--src/test/test_config.c408
-rw-r--r--src/test/test_confmgr.c186
-rw-r--r--src/test/test_confparse.c63
-rw-r--r--src/test/test_connection.c109
-rw-r--r--src/test/test_connection.h5
-rw-r--r--src/test/test_conscache.c2
-rw-r--r--src/test/test_consdiff.c16
-rw-r--r--src/test/test_consdiffmgr.c6
-rw-r--r--src/test/test_containers.c2
-rw-r--r--src/test/test_controller.c302
-rw-r--r--src/test/test_controller_events.c137
-rw-r--r--src/test/test_crypto.c8
-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.c6
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_dir.c588
-rw-r--r--src/test/test_dir_common.c4
-rw-r--r--src/test/test_dir_common.h2
-rw-r--r--src/test/test_dir_handle_get.c298
-rw-r--r--src/test/test_dispatch.c8
-rw-r--r--src/test/test_dns.c197
-rw-r--r--src/test/test_dos.c4
-rw-r--r--src/test/test_entryconn.c4
-rw-r--r--src/test/test_entrynodes.c153
-rw-r--r--src/test/test_extorport.c2
-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.c90
-rw-r--r--src/test/test_helpers.h5
-rw-r--r--src/test/test_hs.c2
-rw-r--r--src/test/test_hs_cache.c166
-rw-r--r--src/test/test_hs_cell.c2
-rw-r--r--src/test/test_hs_client.c509
-rw-r--r--src/test/test_hs_common.c77
-rw-r--r--src/test/test_hs_config.c45
-rw-r--r--src/test/test_hs_control.c521
-rw-r--r--src/test/test_hs_descriptor.c90
-rw-r--r--src/test/test_hs_dos.c2
-rw-r--r--src/test/test_hs_intropoint.c5
-rw-r--r--src/test/test_hs_ntor.c10
-rwxr-xr-xsrc/test/test_hs_ntor.sh2
-rw-r--r--src/test/test_hs_ntor_cl.c18
-rw-r--r--src/test/test_hs_ob.c268
-rw-r--r--src/test/test_hs_service.c556
-rw-r--r--src/test/test_introduce.c2
-rwxr-xr-xsrc/test/test_key_expiration.sh26
-rwxr-xr-xsrc/test/test_keygen.sh24
-rw-r--r--src/test/test_keypin.c2
-rw-r--r--src/test/test_link_handshake.c13
-rw-r--r--src/test/test_logging.c2
-rw-r--r--src/test/test_mainloop.c22
-rw-r--r--src/test/test_microdesc.c6
-rw-r--r--src/test/test_namemap.c2
-rw-r--r--src/test/test_netinfo.c2
-rw-r--r--src/test/test_nodelist.c167
-rw-r--r--src/test/test_ntor_cl.c2
-rw-r--r--src/test/test_oom.c2
-rw-r--r--src/test/test_oos.c2
-rw-r--r--src/test/test_options.c2146
-rw-r--r--src/test/test_options_act.c272
-rw-r--r--src/test/test_parsecommon.c2
-rwxr-xr-xsrc/test/test_parseconf.sh583
-rw-r--r--src/test/test_pem.c2
-rw-r--r--src/test/test_periodic_event.c2
-rw-r--r--src/test/test_policy.c56
-rw-r--r--src/test/test_prob_distr.c38
-rw-r--r--src/test/test_process.c2
-rw-r--r--src/test/test_process_descs.c19
-rw-r--r--src/test/test_process_slow.c2
-rw-r--r--src/test/test_procmon.c5
-rw-r--r--src/test/test_proto_haproxy.c66
-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.c49
-rw-r--r--src/test/test_pt.c9
-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
-rw-r--r--src/test/test_rebind.py3
-rwxr-xr-xsrc/test/test_rebind.sh35
-rw-r--r--src/test/test_relay.c41
-rw-r--r--src/test/test_relaycell.c3
-rw-r--r--src/test/test_relaycrypt.c2
-rw-r--r--src/test/test_rendcache.c43
-rw-r--r--src/test/test_replay.c2
-rw-r--r--src/test/test_rng.c2
-rw-r--r--src/test/test_router.c139
-rw-r--r--src/test/test_routerkeys.c2
-rw-r--r--src/test/test_routerlist.c2
-rw-r--r--src/test/test_routerset.c1029
-rw-r--r--src/test/test_scheduler.c60
-rw-r--r--src/test/test_sendme.c2
-rw-r--r--src/test/test_shared_random.c28
-rw-r--r--src/test/test_slow.c2
-rw-r--r--src/test/test_socks.c39
-rw-r--r--src/test/test_stats.c258
-rw-r--r--src/test/test_status.c608
-rw-r--r--src/test/test_storagedir.c2
-rw-r--r--src/test/test_switch_id.c2
-rw-r--r--src/test/test_threads.c4
-rw-r--r--src/test/test_token_bucket.c2
-rw-r--r--src/test/test_tortls.c4
-rw-r--r--src/test/test_tortls.h2
-rw-r--r--src/test/test_tortls_openssl.c10
-rw-r--r--src/test/test_util.c179
-rw-r--r--src/test/test_util_format.c5
-rw-r--r--src/test/test_util_process.c11
-rw-r--r--src/test/test_voting_flags.c6
-rw-r--r--src/test/test_voting_schedule.c8
-rw-r--r--src/test/test_workqueue.c10
-rw-r--r--src/test/test_x509.c2
-rwxr-xr-xsrc/test/test_zero_length_keys.sh40
-rw-r--r--src/test/testing_common.c23
-rw-r--r--src/test/testing_rsakeys.c2
-rw-r--r--src/tools/.may_include1
-rw-r--r--src/tools/tools.md6
-rw-r--r--src/tools/tor-gencert.c6
-rw-r--r--src/tools/tor-print-ed-signing-cert.c2
-rw-r--r--src/tools/tor-resolve.c10
-rw-r--r--src/tools/tor_runner.c2
-rw-r--r--src/trunnel/.may_include1
-rw-r--r--src/trunnel/hs/.may_include1
-rw-r--r--src/win32/orconfig.h5
1374 files changed, 33122 insertions, 13621 deletions
diff --git a/src/app/app.md b/src/app/app.md
new file mode 100644
index 0000000000..138e75b127
--- /dev/null
+++ b/src/app/app.md
@@ -0,0 +1,6 @@
+@dir /app
+@brief app: top-level entry point for Tor
+
+The "app" directory has Tor's main entry point and configuration logic,
+and is responsible for initializing and managing the other modules in
+Tor.
diff --git a/src/app/config/.may_include b/src/app/config/.may_include
new file mode 100644
index 0000000000..11c5ffbb14
--- /dev/null
+++ b/src/app/config/.may_include
@@ -0,0 +1,2 @@
+*.h
+*.inc
diff --git a/src/app/config/app_config.md b/src/app/config/app_config.md
new file mode 100644
index 0000000000..b359ce77f6
--- /dev/null
+++ b/src/app/config/app_config.md
@@ -0,0 +1,6 @@
+@dir /app/config
+@brief app/config: Top-level configuration code
+
+Refactoring this module is a work in progress, see
+[ticket 29211](https://trac.torproject.org/projects/tor/ticket/29211).
+
diff --git a/src/app/config/config.c b/src/app/config/config.c
index f27fcd3108..930986483d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,7 +22,8 @@
*
* To add new items to the torrc, there are a minimum of three places to edit:
* <ul>
- * <li>The or_options_t structure in or.h, where the options are stored.
+ * <li>The or_options_t structure in or_options_st.h, where the options are
+ * stored.
* <li>The option_vars_ array below in this module, which configures
* the names of the torrc options, their types, their multiplicities,
* and their mappings to fields in or_options_t.
@@ -32,16 +33,18 @@
*
* Additionally, you might need to edit these places too:
* <ul>
- * <li>options_validate() below, in case you want to reject some possible
+ * <li>options_validate_cb() below, in case you want to reject some possible
* values of the new configuration option.
* <li>options_transition_allowed() below, in case you need to
* forbid some or all changes in the option while Tor is
* running.
* <li>options_transition_affects_workers(), in case changes in the option
* might require Tor to relaunch or reconfigure its worker threads.
+ * (This function is now in the relay module.)
* <li>options_transition_affects_descriptor(), in case changes in the
* option might require a Tor relay to build and publish a new server
* descriptor.
+ * (This function is now in the relay module.)
* <li>options_act() and/or options_act_reversible(), in case there's some
* action that needs to be taken immediately based on the option's
* value.
@@ -61,22 +64,19 @@
#define CONFIG_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "app/config/statefile.h"
#include "app/main/main.h"
#include "app/main/subsysmgr.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/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitmux.h"
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitstats.h"
#include "core/or/connection_edge.h"
-#include "core/or/connection_or.h"
#include "core/or/dos.h"
#include "core/or/policies.h"
#include "core/or/relay.h"
@@ -88,11 +88,7 @@
#include "feature/control/control.h"
#include "feature/control/control_auth.h"
#include "feature/control/control_events.h"
-#include "feature/dirauth/bwauth.h"
-#include "feature/dirauth/guardfraction.h"
-#include "feature/dircache/consdiffmgr.h"
-#include "feature/dircache/dirserv.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/hibernate/hibernate.h"
#include "feature/hs/hs_config.h"
#include "feature/nodelist/dirlist.h"
@@ -104,12 +100,12 @@
#include "feature/relay/dns.h"
#include "feature/relay/ext_orport.h"
#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 "feature/stats/predict_ports.h"
-#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
#include "lib/confmgt/structvar.h"
#include "lib/crypt_ops/crypto_init.h"
@@ -156,10 +152,8 @@
#include "lib/fs/conffile.h"
#include "lib/evloop/procmon.h"
-#include "feature/dirauth/dirvote.h"
-#include "feature/dirauth/dirauth_periodic.h"
-#include "feature/dirauth/recommend_pkg.h"
#include "feature/dirauth/authmode.h"
+#include "feature/dirauth/dirauth_config.h"
#include "core/or/connection_st.h"
#include "core/or/port_cfg_st.h"
@@ -186,8 +180,12 @@ static const char unix_q_socket_prefix[] = "unix:\"";
/** macro to help with the bulk rename of *DownloadSchedule to
* *DowloadInitialDelay . */
+#ifndef COCCI
#define DOWNLOAD_SCHEDULE(name) \
- { #name "DownloadSchedule", #name "DownloadInitialDelay", 0, 1 }
+ { (#name "DownloadSchedule"), (#name "DownloadInitialDelay"), 0, 1 }
+#else
+#define DOWNLOAD_SCHEDULE(name) { NULL, NULL, 0, 1 }
+#endif /* !defined(COCCI) */
/** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */
@@ -268,6 +266,9 @@ DUMMY_TYPECHECK_INSTANCE(or_options_t);
#define VAR_NODUMP(varname,conftype,member,initvalue) \
CONFIG_VAR_ETYPE(or_options_t, varname, conftype, member, \
CFLG_NODUMP, initvalue)
+#define VAR_NODUMP_IMMUTABLE(varname,conftype,member,initvalue) \
+ CONFIG_VAR_ETYPE(or_options_t, varname, conftype, member, \
+ CFLG_NODUMP | CFLG_IMMUTABLE, initvalue)
#define VAR_INVIS(varname,conftype,member,initvalue) \
CONFIG_VAR_ETYPE(or_options_t, varname, conftype, member, \
CFLG_NODUMP | CFLG_NOSET | CFLG_NOLIST, initvalue)
@@ -275,6 +276,13 @@ DUMMY_TYPECHECK_INSTANCE(or_options_t);
#define V(member,conftype,initvalue) \
VAR(#member, conftype, member, initvalue)
+#define VAR_IMMUTABLE(varname, conftype, member, initvalue) \
+ CONFIG_VAR_ETYPE(or_options_t, varname, conftype, member, \
+ CFLG_IMMUTABLE, initvalue)
+
+#define V_IMMUTABLE(member,conftype,initvalue) \
+ VAR_IMMUTABLE(#member, conftype, member, initvalue)
+
/** As V, but uses a type definition instead of a type enum */
#define V_D(member,type,initvalue) \
VAR_D(#member, type, member, initvalue)
@@ -321,17 +329,11 @@ static const config_var_t option_vars_[] = {
V(AuthDirBadExitCCs, CSV, ""),
V(AuthDirInvalid, LINELIST, NULL),
V(AuthDirInvalidCCs, CSV, ""),
- V(AuthDirFastGuarantee, MEMUNIT, "100 KB"),
- V(AuthDirGuardBWGuarantee, MEMUNIT, "2 MB"),
- V(AuthDirPinKeys, BOOL, "1"),
V(AuthDirReject, LINELIST, NULL),
V(AuthDirRejectCCs, CSV, ""),
OBSOLETE("AuthDirRejectUnlisted"),
OBSOLETE("AuthDirListBadDirs"),
- V(AuthDirListBadExits, BOOL, "0"),
- V(AuthDirMaxServersPerAddr, POSINT, "2"),
OBSOLETE("AuthDirMaxServersPerAuthAddr"),
- V(AuthDirHasIPv6Connectivity, BOOL, "0"),
VAR("AuthoritativeDirectory", BOOL, AuthoritativeDir, "0"),
V(AutomapHostsOnResolve, BOOL, "0"),
V(AutomapHostsSuffixes, CSV, ".onion,.exit"),
@@ -344,7 +346,7 @@ static const config_var_t option_vars_[] = {
V(BridgeRecordUsageByCountry, BOOL, "1"),
V(BridgeRelay, BOOL, "0"),
V(BridgeDistribution, STRING, NULL),
- VAR("CacheDirectory", FILENAME, CacheDirectory_option, NULL),
+ VAR_IMMUTABLE("CacheDirectory",FILENAME, CacheDirectory_option, NULL),
V(CacheDirectoryGroupReadable, AUTOBOOL, "auto"),
V(CellStatistics, BOOL, "0"),
V(PaddingStatistics, BOOL, "1"),
@@ -355,15 +357,20 @@ static const config_var_t option_vars_[] = {
V(CircuitStreamTimeout, INTERVAL, "0"),
V(CircuitPriorityHalflife, DOUBLE, "-1.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
+#if defined(HAVE_MODULE_RELAY) || defined(TOR_UNIT_TESTS)
+ /* The unit tests expect the ClientOnly default to be 0. */
V(ClientOnly, BOOL, "0"),
+#else
+ /* We must be a Client if the relay module is disabled. */
+ V(ClientOnly, BOOL, "1"),
+#endif /* defined(HAVE_MODULE_RELAY) || defined(TOR_UNIT_TESTS) */
V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"),
V(ClientPreferIPv6DirPort, AUTOBOOL, "auto"),
- V(ClientAutoIPv6ORPort, BOOL, "0"),
+ OBSOLETE("ClientAutoIPv6ORPort"),
V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientTransportPlugin, LINELIST, NULL),
V(ClientUseIPv6, BOOL, "0"),
V(ClientUseIPv4, BOOL, "1"),
- V(ConsensusParams, STRING, NULL),
V(ConnLimit, POSINT, "1000"),
V(ConnDirectionStatistics, BOOL, "0"),
V(ConstrainedSockets, BOOL, "0"),
@@ -378,21 +385,26 @@ static const config_var_t option_vars_[] = {
V(UnixSocksGroupWritable, BOOL, "0"),
V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"),
- V(CookieAuthFile, STRING, NULL),
+ V(CookieAuthFile, FILENAME, NULL),
V(CountPrivateBandwidth, BOOL, "0"),
- VAR("DataDirectory", FILENAME, DataDirectory_option, NULL),
+ VAR_IMMUTABLE("DataDirectory", FILENAME, DataDirectory_option, NULL),
V(DataDirectoryGroupReadable, BOOL, "0"),
V(DisableOOSCheck, BOOL, "1"),
V(DisableNetwork, BOOL, "0"),
V(DirAllowPrivateAddresses, BOOL, "0"),
- V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"),
OBSOLETE("DirListenAddress"),
V(DirPolicy, LINELIST, NULL),
VPORT(DirPort),
V(DirPortFrontPage, FILENAME, NULL),
VAR("DirReqStatistics", BOOL, DirReqStatistics_option, "1"),
VAR("DirAuthority", LINELIST, DirAuthorities, NULL),
+#if defined(HAVE_MODULE_RELAY) || defined(TOR_UNIT_TESTS)
+ /* The unit tests expect the DirCache default to be 1. */
V(DirCache, BOOL, "1"),
+#else
+ /* We can't be a DirCache if the relay module is disabled. */
+ V(DirCache, BOOL, "0"),
+#endif /* defined(HAVE_MODULE_RELAY) || defined(TOR_UNIT_TESTS) */
/* A DirAuthorityFallbackRate of 0.1 means that 0.5% of clients try an
* authority when all fallbacks are up, and 2% try an authority when 25% of
* fallbacks are down. (We rebuild the list when 25% of fallbacks are down).
@@ -401,8 +413,8 @@ static const config_var_t option_vars_[] = {
* an order of magnitude, so there isn't too much load shifting to
* authorities when fallbacks go down. */
V(DirAuthorityFallbackRate, DOUBLE, "0.1"),
- V(DisableAllSwap, BOOL, "0"),
- V(DisableDebuggerAttachment, BOOL, "1"),
+ V_IMMUTABLE(DisableAllSwap, BOOL, "0"),
+ V_IMMUTABLE(DisableDebuggerAttachment, BOOL, "1"),
OBSOLETE("DisableIOCP"),
OBSOLETE("DisableV2DirectoryInfo_"),
OBSOLETE("DynamicDHGroups"),
@@ -432,7 +444,7 @@ static const config_var_t option_vars_[] = {
V(EnforceDistinctSubnets, BOOL, "1"),
V_D(EntryNodes, ROUTERSET, NULL),
V(EntryStatistics, BOOL, "0"),
- V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"),
+ OBSOLETE("TestingEstimatedDescriptorPropagationTime"),
V_D(ExcludeNodes, ROUTERSET, NULL),
V_D(ExcludeExitNodes, ROUTERSET, NULL),
OBSOLETE("ExcludeSingleHopRelays"),
@@ -448,7 +460,7 @@ static const config_var_t option_vars_[] = {
V(ExtendAllowPrivateAddresses, BOOL, "0"),
V(ExitRelay, AUTOBOOL, "auto"),
VPORT(ExtORPort),
- V(ExtORPortCookieAuthFile, STRING, NULL),
+ V(ExtORPortCookieAuthFile, FILENAME, NULL),
V(ExtORPortCookieAuthFileGroupReadable, BOOL, "0"),
V(ExtraInfoStatistics, BOOL, "1"),
V(ExtendByEd25519ID, AUTOBOOL, "auto"),
@@ -478,11 +490,8 @@ static const config_var_t option_vars_[] = {
#endif /* defined(_WIN32) */
OBSOLETE("Group"),
V(GuardLifetime, INTERVAL, "0 minutes"),
- V(HardwareAccel, BOOL, "0"),
V(HeartbeatPeriod, INTERVAL, "6 hours"),
V(MainloopStats, BOOL, "0"),
- V(AccelName, STRING, NULL),
- V(AccelDir, FILENAME, NULL),
V(HashedControlPassword, LINELIST, NULL),
OBSOLETE("HidServDirectoryV2"),
VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
@@ -501,13 +510,15 @@ static const config_var_t option_vars_[] = {
LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceEnableIntroDoSBurstPerSec",
LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServiceOnionBalanceInstance",
+ LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
V(HidServAuth, LINELIST, NULL),
V(ClientOnionAuthDir, FILENAME, NULL),
OBSOLETE("CloseHSClientCircuitsImmediatelyOnTimeout"),
OBSOLETE("CloseHSServiceRendCircuitsImmediatelyOnTimeout"),
- V(HiddenServiceSingleHopMode, BOOL, "0"),
- V(HiddenServiceNonAnonymousMode,BOOL, "0"),
+ V_IMMUTABLE(HiddenServiceSingleHopMode, BOOL, "0"),
+ V_IMMUTABLE(HiddenServiceNonAnonymousMode,BOOL, "0"),
V(HTTPProxy, STRING, NULL),
V(HTTPProxyAuthenticator, STRING, NULL),
V(HTTPSProxy, STRING, NULL),
@@ -522,18 +533,19 @@ static const config_var_t option_vars_[] = {
V(Socks5Proxy, STRING, NULL),
V(Socks5ProxyUsername, STRING, NULL),
V(Socks5ProxyPassword, STRING, NULL),
- VAR("KeyDirectory", FILENAME, KeyDirectory_option, NULL),
- V(KeyDirectoryGroupReadable, BOOL, "0"),
+ V(TCPProxy, STRING, NULL),
+ VAR_IMMUTABLE("KeyDirectory", FILENAME, KeyDirectory_option, NULL),
+ V(KeyDirectoryGroupReadable, AUTOBOOL, "auto"),
VAR_D("HSLayer2Nodes", ROUTERSET, HSLayer2Nodes, NULL),
VAR_D("HSLayer3Nodes", ROUTERSET, HSLayer3Nodes, NULL),
V(KeepalivePeriod, INTERVAL, "5 minutes"),
- V(KeepBindCapabilities, AUTOBOOL, "auto"),
+ V_IMMUTABLE(KeepBindCapabilities, AUTOBOOL, "auto"),
VAR("Log", LINELIST, Logs, NULL),
V(LogMessageDomains, BOOL, "0"),
V(LogTimeGranularity, MSEC_INTERVAL, "1 second"),
V(TruncateLogFile, BOOL, "0"),
- V(SyslogIdentityTag, STRING, NULL),
- V(AndroidIdentityTag, STRING, NULL),
+ V_IMMUTABLE(SyslogIdentityTag, STRING, NULL),
+ V_IMMUTABLE(AndroidIdentityTag,STRING, NULL),
V(LongLivedPorts, CSV,
"21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"),
VAR("MapAddress", LINELIST, AddressMap, NULL),
@@ -545,7 +557,6 @@ static const config_var_t option_vars_[] = {
OBSOLETE("MaxOnionsPending"),
V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
V(MaxUnparseableDescSizeToLog, MEMUNIT, "10 MB"),
- V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"),
VAR("MyFamily", LINELIST, MyFamily_lines, NULL),
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
OBSOLETE("NamingAuthoritativeDirectory"),
@@ -555,7 +566,7 @@ static const config_var_t option_vars_[] = {
OBSOLETE("PredictedPortsRelevanceTime"),
OBSOLETE("WarnUnsafeSocks"),
VAR("NodeFamily", LINELIST, NodeFamilies, NULL),
- V(NoExec, BOOL, "0"),
+ V_IMMUTABLE(NoExec, BOOL, "0"),
V(NumCPUs, POSINT, "0"),
V(NumDirectoryGuards, POSINT, "0"),
V(NumEntryGuards, POSINT, "0"),
@@ -586,10 +597,8 @@ static const config_var_t option_vars_[] = {
V(PathsNeededToBuildCircuits, DOUBLE, "-1"),
V(PerConnBWBurst, MEMUNIT, "0"),
V(PerConnBWRate, MEMUNIT, "0"),
- V(PidFile, STRING, NULL),
- V(TestingTorNetwork, BOOL, "0"),
- V(TestingMinExitFlagThreshold, MEMUNIT, "0"),
- V(TestingMinFastFlagThreshold, MEMUNIT, "0"),
+ V_IMMUTABLE(PidFile, FILENAME, NULL),
+ V_IMMUTABLE(TestingTorNetwork, BOOL, "0"),
V(TestingLinkCertLifetime, INTERVAL, "2 days"),
V(TestingAuthKeyLifetime, INTERVAL, "2 days"),
@@ -607,9 +616,6 @@ static const config_var_t option_vars_[] = {
V(ReachableAddresses, LINELIST, NULL),
V(ReachableDirAddresses, LINELIST, NULL),
V(ReachableORAddresses, LINELIST, NULL),
- V(RecommendedVersions, LINELIST, NULL),
- V(RecommendedClientVersions, LINELIST, NULL),
- V(RecommendedServerVersions, LINELIST, NULL),
OBSOLETE("RecommendedPackages"),
V(ReducedConnectionPadding, BOOL, "0"),
V(ConnectionPadding, AUTOBOOL, "auto"),
@@ -621,17 +627,17 @@ static const config_var_t option_vars_[] = {
V(RelayBandwidthRate, MEMUNIT, "0"),
V(RendPostPeriod, INTERVAL, "1 hour"),
V(RephistTrackTime, INTERVAL, "24 hours"),
- V(RunAsDaemon, BOOL, "0"),
+ V_IMMUTABLE(RunAsDaemon, BOOL, "0"),
V(ReducedExitPolicy, BOOL, "0"),
OBSOLETE("RunTesting"), // currently unused
- V(Sandbox, BOOL, "0"),
+ V_IMMUTABLE(Sandbox, BOOL, "0"),
V(SafeLogging, STRING, "1"),
V(SafeSocks, BOOL, "0"),
V(ServerDNSAllowBrokenConfig, BOOL, "1"),
V(ServerDNSAllowNonRFC953Hostnames, BOOL,"0"),
V(ServerDNSDetectHijacking, BOOL, "1"),
V(ServerDNSRandomizeCase, BOOL, "1"),
- V(ServerDNSResolvConfFile, STRING, NULL),
+ V(ServerDNSResolvConfFile, FILENAME, NULL),
V(ServerDNSSearchDomains, BOOL, "0"),
V(ServerDNSTestAddresses, CSV,
"www.google.com,www.mit.edu,www.yahoo.com,www.slashdot.org"),
@@ -652,7 +658,7 @@ static const config_var_t option_vars_[] = {
V(StrictNodes, BOOL, "0"),
OBSOLETE("Support022HiddenServices"),
V(TestSocks, BOOL, "0"),
- V(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"),
+ V_IMMUTABLE(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"),
OBSOLETE("Tor2webMode"),
OBSOLETE("Tor2webRendezvousPoints"),
OBSOLETE("TLSECGroup"),
@@ -669,11 +675,8 @@ static const config_var_t option_vars_[] = {
V(UseGuardFraction, AUTOBOOL, "auto"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
OBSOLETE("UseNTorHandshake"),
- V(User, STRING, NULL),
+ V_IMMUTABLE(User, STRING, NULL),
OBSOLETE("UserspaceIOCPBuffers"),
- V(AuthDirRejectRequestsUnderLoad, BOOL, "1"),
- V(AuthDirSharedRandomness, BOOL, "1"),
- V(AuthDirTestEd25519LinkKeys, BOOL, "1"),
OBSOLETE("V1AuthoritativeDirectory"),
OBSOLETE("V2AuthoritativeDirectory"),
VAR("V3AuthoritativeDirectory",BOOL, V3AuthoritativeDir, "0"),
@@ -688,7 +691,6 @@ static const config_var_t option_vars_[] = {
V(V3AuthUseLegacyKey, BOOL, "0"),
V(V3BandwidthsFile, FILENAME, NULL),
V(GuardfractionFile, FILENAME, NULL),
- VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
OBSOLETE("VoteOnHidServDirectoriesV2"),
V(VirtualAddrNetworkIPv4, STRING, "127.192.0.0/10"),
V(VirtualAddrNetworkIPv6, STRING, "[FE80::]/10"),
@@ -698,15 +700,16 @@ static const config_var_t option_vars_[] = {
VAR_NODUMP("__ReloadTorrcOnSIGHUP", BOOL, ReloadTorrcOnSIGHUP, "1"),
VAR_NODUMP("__AllDirActionsPrivate", BOOL, AllDirActionsPrivate, "0"),
VAR_NODUMP("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"),
- VAR_NODUMP("__DisableSignalHandlers", BOOL, DisableSignalHandlers, "0"),
+ VAR_NODUMP_IMMUTABLE("__DisableSignalHandlers", BOOL,
+ DisableSignalHandlers, "0"),
VAR_NODUMP("__LeaveStreamsUnattached",BOOL, LeaveStreamsUnattached, "0"),
VAR_NODUMP("__HashedControlSessionPassword", LINELIST,
HashedControlSessionPassword,
NULL),
- VAR_NODUMP("__OwningControllerProcess",STRING,OwningControllerProcess, NULL),
- VAR_NODUMP("__OwningControllerFD", UINT64, OwningControllerFD,
+ VAR_NODUMP("__OwningControllerProcess",STRING,
+ OwningControllerProcess, NULL),
+ VAR_NODUMP_IMMUTABLE("__OwningControllerFD", UINT64, OwningControllerFD,
UINT64_MAX_STRING),
- V(MinUptimeHidServDirectoryV2, INTERVAL, "96 hours"),
V(TestingServerDownloadInitialDelay, CSV_INTERVAL, "0"),
V(TestingClientDownloadInitialDelay, CSV_INTERVAL, "0"),
V(TestingServerConsensusDownloadInitialDelay, CSV_INTERVAL, "0"),
@@ -752,12 +755,6 @@ static const config_var_t option_vars_[] = {
OBSOLETE("TestingDescriptorMaxDownloadTries"),
OBSOLETE("TestingMicrodescMaxDownloadTries"),
OBSOLETE("TestingCertMaxDownloadTries"),
- V_D(TestingDirAuthVoteExit, ROUTERSET, NULL),
- V(TestingDirAuthVoteExitIsStrict, BOOL, "0"),
- V_D(TestingDirAuthVoteGuard, ROUTERSET, NULL),
- V(TestingDirAuthVoteGuardIsStrict, BOOL, "0"),
- V_D(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
- V(TestingDirAuthVoteHSDirIsStrict, BOOL, "0"),
VAR_INVIS("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_,
"0"),
@@ -766,7 +763,9 @@ static const config_var_t option_vars_[] = {
/** List of default directory authorities */
static const char *default_authorities[] = {
+#ifndef COCCI
#include "auth_dirs.inc"
+#endif
NULL
};
@@ -774,7 +773,9 @@ static const char *default_authorities[] = {
* relays that meet certain stability criteria.
*/
static const char *default_fallbacks[] = {
+#ifndef COCCI
#include "fallback_dirs.inc"
+#endif
NULL
};
@@ -784,7 +785,9 @@ static const struct {
const char *k;
const char *v;
} testing_tor_network_defaults[] = {
+#ifndef COCCI
#include "testnet.inc"
+#endif
{ NULL, NULL }
};
@@ -807,38 +810,24 @@ static const config_deprecation_t option_deprecation_notes_[] = {
"effect on clients since 0.2.8." },
/* End of options deprecated since 0.3.2.2-alpha. */
+ /* Options deprecated since 0.4.3.1-alpha. */
+ { "ClientAutoIPv6ORPort", "This option is unreliable if a connection isn't "
+ "reliably dual-stack."},
+ /* End of options deprecated since 0.4.3.1-alpha. */
+
{ NULL, NULL }
};
#ifdef _WIN32
static char *get_windows_conf_root(void);
#endif
-static int options_act_reversible(const or_options_t *old_options, char **msg);
-static int options_transition_allowed(const or_options_t *old,
- const or_options_t *new,
- char **msg);
-static int options_transition_affects_workers(
- const or_options_t *old_options, const or_options_t *new_options);
-static int options_transition_affects_descriptor(
- const or_options_t *old_options, const or_options_t *new_options);
-static int options_transition_affects_dirauth_timing(
- const or_options_t *old_options, const or_options_t *new_options);
-static int normalize_nickname_list(config_line_t **normalized_out,
- const config_line_t *lst, const char *name,
- char **msg);
-static char *get_bindaddr_from_transport_listen_line(const char *line,
- const char *transport);
-static int parse_ports(or_options_t *options, int validate_only,
- char **msg_out, int *n_ports_out,
- int *world_writable_control_socket);
-static int check_server_ports(const smartlist_t *ports,
- const or_options_t *options,
- int *num_low_ports_out);
+
+static int options_check_transition_cb(const void *old,
+ const void *new,
+ char **msg);
static int validate_data_directories(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
-static int options_init_logs(const or_options_t *old_options,
- or_options_t *options, int validate_only);
static void init_libevent(const or_options_t *options);
static int opt_streq(const char *s1, const char *s2);
@@ -846,31 +835,37 @@ static int parse_outbound_addresses(or_options_t *options, int validate_only,
char **msg);
static void config_maybe_load_geoip_files_(const or_options_t *options,
const or_options_t *old_options);
-static int options_validate_cb(void *old_options, void *options,
- void *default_options,
- int from_setconf, char **msg);
+static int options_validate_cb(const void *old_options, void *options,
+ char **msg);
static void cleanup_protocol_warning_severity_level(void);
static void set_protocol_warning_severity_level(int warning_severity);
static void options_clear_cb(const config_mgr_t *mgr, void *opts);
+static setopt_err_t options_validate_and_set(const or_options_t *old_options,
+ or_options_t *new_options,
+ char **msg_out);
+struct listener_transaction_t;
+static void options_rollback_listener_transaction(
+ struct listener_transaction_t *xn);
/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909
/** Configuration format for or_options_t. */
static const config_format_t options_format = {
- sizeof(or_options_t),
- {
+ .size = sizeof(or_options_t),
+ .magic = {
"or_options_t",
OR_OPTIONS_MAGIC,
offsetof(or_options_t, magic_),
},
- option_abbrevs_,
- option_deprecation_notes_,
- option_vars_,
- options_validate_cb,
- options_clear_cb,
- NULL,
- offsetof(or_options_t, subconfigs_),
+ .abbrevs = option_abbrevs_,
+ .deprecations = option_deprecation_notes_,
+ .vars = option_vars_,
+ .legacy_validate_fn = options_validate_cb,
+ .check_transition_fn = options_check_transition_cb,
+ .clear_fn = options_clear_cb,
+ .has_config_suite = true,
+ .config_suite_offset = offsetof(or_options_t, subconfigs_),
};
/*
@@ -886,21 +881,15 @@ static or_options_t *global_default_options = NULL;
static char *torrc_fname = NULL;
/** Name of the most recently read torrc-defaults file.*/
static char *torrc_defaults_fname = NULL;
-/** Configuration options set by command line. */
-static config_line_t *global_cmdline_options = NULL;
-/** Non-configuration options set by the command line */
-static config_line_t *global_cmdline_only_options = NULL;
-/** Boolean: Have we parsed the command line? */
-static int have_parsed_cmdline = 0;
-/** Contents of most recently read DirPortFrontPage file. */
-static char *global_dirfrontpagecontents = NULL;
+/** Result of parsing the command line. */
+static parsed_cmdline_t *global_cmdline = NULL;
/** List of port_cfg_t for all configured ports. */
static smartlist_t *configured_ports = NULL;
/** True iff we're currently validating options, and any calls to
* get_options() are likely to be bugs. */
static int in_option_validation = 0;
-/* True iff we've initialized libevent */
-static int libevent_initialized = 0;
+/** True iff we have run options_act_once_on_startup() */
+static bool have_set_startup_options = false;
/* A global configuration manager to handle all configuration objects. */
static config_mgr_t *options_mgr = NULL;
@@ -911,17 +900,16 @@ get_options_mgr(void)
{
if (PREDICT_UNLIKELY(options_mgr == NULL)) {
options_mgr = config_mgr_new(&options_format);
+ int rv = subsystems_register_options_formats(options_mgr);
+ tor_assert(rv == 0);
config_mgr_freeze(options_mgr);
}
return options_mgr;
}
-/** Return the contents of our frontpage string, or NULL if not configured. */
-MOCK_IMPL(const char*,
-get_dirportfrontpage, (void))
-{
- return global_dirfrontpagecontents;
-}
+#define CHECK_OPTIONS_MAGIC(opt) STMT_BEGIN \
+ config_check_toplevel_magic(get_options_mgr(), (opt)); \
+ STMT_END
/** Returns the currently configured options. */
MOCK_IMPL(or_options_t *,
@@ -981,7 +969,8 @@ set_options(or_options_t *new_val, char **msg)
global_options = old_options;
return -1;
}
- if (options_act(old_options) < 0) { /* acting on the options failed. die. */
+ if (subsystems_set_options(get_options_mgr(), new_val) < 0 ||
+ options_act(old_options) < 0) { /* acting on the options failed. die. */
if (! tor_event_loop_shutdown_is_pending()) {
log_err(LD_BUG,
"Acting on config options left us in a broken state. Dying.");
@@ -993,15 +982,9 @@ set_options(or_options_t *new_val, char **msg)
/* Issues a CONF_CHANGED event to notify controller of the change. If Tor is
* just starting up then the old_options will be undefined. */
if (old_options && old_options != global_options) {
- smartlist_t *elements = smartlist_new();
config_line_t *changes =
config_get_changes(get_options_mgr(), old_options, new_val);
- for (config_line_t *line = changes; line; line = line->next) {
- smartlist_add(elements, line->key);
- smartlist_add(elements, line->value);
- }
- control_event_conf_changed(elements);
- smartlist_free(elements);
+ control_event_conf_changed(changes);
config_free_lines(changes);
}
@@ -1022,6 +1005,7 @@ static void
options_clear_cb(const config_mgr_t *mgr, void *opts)
{
(void)mgr;
+ CHECK_OPTIONS_MAGIC(opts);
or_options_t *options = opts;
routerset_free(options->ExcludeExitNodesUnion_);
@@ -1065,11 +1049,7 @@ config_free_all(void)
or_options_free(global_default_options);
global_default_options = NULL;
- config_free_lines(global_cmdline_options);
- global_cmdline_options = NULL;
-
- config_free_lines(global_cmdline_only_options);
- global_cmdline_only_options = NULL;
+ parsed_cmdline_free(global_cmdline);
if (configured_ports) {
SMARTLIST_FOREACH(configured_ports,
@@ -1080,12 +1060,10 @@ config_free_all(void)
tor_free(torrc_fname);
tor_free(torrc_defaults_fname);
- tor_free(global_dirfrontpagecontents);
cleanup_protocol_warning_severity_level();
- have_parsed_cmdline = 0;
- libevent_initialized = 0;
+ have_set_startup_options = false;
config_mgr_free(options_mgr);
}
@@ -1240,7 +1218,8 @@ add_default_fallback_dir_servers,(void))
* user if we changed any dangerous ones.
*/
static int
-validate_dir_servers(or_options_t *options, or_options_t *old_options)
+validate_dir_servers(const or_options_t *options,
+ const or_options_t *old_options)
{
config_line_t *cl;
@@ -1421,27 +1400,24 @@ create_keys_directory(const or_options_t *options)
/* Helps determine flags to pass to switch_id. */
static int have_low_ports = -1;
-/** Fetch the active option list, and take actions based on it. All of the
- * things we do should survive being done repeatedly. If present,
- * <b>old_options</b> contains the previous value of the options.
- *
- * Return 0 if all goes well, return -1 if things went badly.
- */
+/** Take case of initial startup tasks that must occur before any of the
+ * transactional option-related changes are allowed. */
static int
-options_act_reversible(const or_options_t *old_options, char **msg)
+options_act_once_on_startup(char **msg_out)
{
- smartlist_t *new_listeners = smartlist_new();
- or_options_t *options = get_options_mutable();
- int running_tor = options->command == CMD_RUN_TOR;
- int set_conn_limit = 0;
- int r = -1;
- int logs_marked = 0, logs_initialized = 0;
- int old_min_log_level = get_min_log_level();
+ if (have_set_startup_options)
+ return 0;
+
+ const or_options_t *options = get_options();
+ const bool running_tor = options->command == CMD_RUN_TOR;
+
+ if (!running_tor)
+ return 0;
/* Daemonize _first_, since we only want to open most of this stuff in
* the subprocess. Libevent bases can't be reliably inherited across
* processes. */
- if (running_tor && options->RunAsDaemon) {
+ if (options->RunAsDaemon) {
if (! start_daemon_has_been_called())
subsystems_prefork();
/* No need to roll back, since you can't change the value. */
@@ -1454,105 +1430,43 @@ options_act_reversible(const or_options_t *old_options, char **msg)
sd_notifyf(0, "MAINPID=%ld\n", (long int)getpid());
#endif
-#ifndef HAVE_SYS_UN_H
- if (options->ControlSocket || options->ControlSocketsGroupWritable) {
- *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported "
- "on this OS/with this build.");
- goto rollback;
- }
-#else /* defined(HAVE_SYS_UN_H) */
- if (options->ControlSocketsGroupWritable && !options->ControlSocket) {
- *msg = tor_strdup("Setting ControlSocketGroupWritable without setting"
- "a ControlSocket makes no sense.");
- goto rollback;
- }
-#endif /* !defined(HAVE_SYS_UN_H) */
-
- if (running_tor) {
- int n_ports=0;
- /* We need to set the connection limit before we can open the listeners. */
- if (! sandbox_is_active()) {
- if (set_max_file_descriptors((unsigned)options->ConnLimit,
- &options->ConnLimit_) < 0) {
- *msg = tor_strdup("Problem with ConnLimit value. "
- "See logs for details.");
- goto rollback;
- }
- set_conn_limit = 1;
- } else {
- tor_assert(old_options);
- options->ConnLimit_ = old_options->ConnLimit_;
- }
-
- /* Set up libevent. (We need to do this before we can register the
- * listeners as listeners.) */
- if (running_tor && !libevent_initialized) {
- init_libevent(options);
- libevent_initialized = 1;
+ /* Set up libevent. (We need to do this before we can register the
+ * listeners as listeners.) */
+ init_libevent(options);
- /* This has to come up after libevent is initialized. */
- control_initialize_event_queue();
-
- /*
- * Initialize the scheduler - this has to come after
- * options_init_from_torrc() sets up libevent - why yes, that seems
- * completely sensible to hide the libevent setup in the option parsing
- * code! It also needs to happen before init_keys(), so it needs to
- * happen here too. How yucky. */
- scheduler_init();
- }
-
- /* Adjust the port configuration so we can launch listeners. */
- if (parse_ports(options, 0, msg, &n_ports, NULL)) {
- if (!*msg)
- *msg = tor_strdup("Unexpected problem parsing port config");
- goto rollback;
- }
-
- /* Set the hibernation state appropriately.*/
- consider_hibernation(time(NULL));
-
- /* Launch the listeners. (We do this before we setuid, so we can bind to
- * ports under 1024.) We don't want to rebind if we're hibernating or
- * shutting down. If networking is disabled, this will close all but the
- * control listeners, but disable those. */
- if (!we_are_hibernating()) {
- if (retry_all_listeners(new_listeners, options->DisableNetwork) < 0) {
- *msg = tor_strdup("Failed to bind one of the listener ports.");
- goto rollback;
- }
- }
- if (options->DisableNetwork) {
- /* Aggressively close non-controller stuff, NOW */
- log_notice(LD_NET, "DisableNetwork is set. Tor will not make or accept "
- "non-control network connections. Shutting down all existing "
- "connections.");
- connection_mark_all_noncontrol_connections();
- /* We can't complete circuits until the network is re-enabled. */
- note_that_we_maybe_cant_complete_circuits();
- }
- }
-
-#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
- /* Open /dev/pf before dropping privileges. */
- if (options->TransPort_set &&
- options->TransProxyType_parsed == TPT_DEFAULT) {
- if (get_pf_socket() < 0) {
- *msg = tor_strdup("Unable to open /dev/pf for transparent proxy.");
- goto rollback;
- }
- }
-#endif /* defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) */
+ /* This has to come up after libevent is initialized. */
+ control_initialize_event_queue();
- /* Attempt to lock all current and future memory with mlockall() only once */
+ /*
+ * Initialize the scheduler - this has to come after
+ * options_init_from_torrc() sets up libevent - why yes, that seems
+ * completely sensible to hide the libevent setup in the option parsing
+ * code! It also needs to happen before init_keys(), so it needs to
+ * happen here too. How yucky. */
+ scheduler_init();
+
+ /* Attempt to lock all current and future memory with mlockall() only once.
+ * This must happen before setuid. */
if (options->DisableAllSwap) {
if (tor_mlockall() == -1) {
- *msg = tor_strdup("DisableAllSwap failure. Do you have proper "
+ *msg_out = tor_strdup("DisableAllSwap failure. Do you have proper "
"permissions?");
- goto done;
+ return -1;
}
}
+ have_set_startup_options = true;
+ return 0;
+}
+
+/**
+ * Change our user ID if we're configured to do so.
+ **/
+static int
+options_switch_id(char **msg_out)
+{
+ const or_options_t *options = get_options();
+
/* Setuid/setgid as appropriate */
if (options->User) {
tor_assert(have_low_ports != -1);
@@ -1566,11 +1480,52 @@ options_act_reversible(const or_options_t *old_options, char **msg)
}
if (switch_id(options->User, switch_id_flags) != 0) {
/* No need to roll back, since you can't change the value. */
- *msg = tor_strdup("Problem with User value. See logs for details.");
- goto done;
+ *msg_out = tor_strdup("Problem with User value. See logs for details.");
+ return -1;
}
}
+ return 0;
+}
+
+/**
+ * Helper. Given a data directory (<b>datadir</b>) and another directory
+ * (<b>subdir</b>) with respective group-writable permissions
+ * <b>datadir_gr</b> and <b>subdir_gr</b>, compute whether the subdir should
+ * be group-writeable.
+ **/
+static int
+compute_group_readable_flag(const char *datadir,
+ const char *subdir,
+ int datadir_gr,
+ int subdir_gr)
+{
+ if (subdir_gr != -1) {
+ /* The user specified a default for "subdir", so we always obey it. */
+ return subdir_gr;
+ }
+
+ /* The user left the subdir_gr option on "auto." */
+ if (0 == strcmp(subdir, datadir)) {
+ /* The directories are the same, so we use the group-readable flag from
+ * the datadirectory */
+ return datadir_gr;
+ } else {
+ /* The directores are different, so we default to "not group-readable" */
+ return 0;
+ }
+}
+
+/**
+ * Create our DataDirectory, CacheDirectory, and KeyDirectory, and
+ * set their permissions correctly.
+ */
+STATIC int
+options_create_directories(char **msg_out)
+{
+ const or_options_t *options = get_options();
+ const bool running_tor = options->command == CMD_RUN_TOR;
+
/* Ensure data directory is private; create if possible. */
/* It's okay to do this in "options_act_reversible()" even though it isn't
* actually reversible, since you can't change the DataDirectory while
@@ -1579,58 +1534,288 @@ options_act_reversible(const or_options_t *old_options, char **msg)
options->DataDirectory,
options->DataDirectoryGroupReadable,
options->User,
- msg) < 0) {
- goto done;
+ msg_out) < 0) {
+ return -1;
}
+
+ /* We need to handle the group-readable flag for the cache directory and key
+ * directory specially, since they may be the same as the data directory */
+ const int key_dir_group_readable = compute_group_readable_flag(
+ options->DataDirectory,
+ options->KeyDirectory,
+ options->DataDirectoryGroupReadable,
+ options->KeyDirectoryGroupReadable);
+
if (check_and_create_data_directory(running_tor /* create */,
options->KeyDirectory,
- options->KeyDirectoryGroupReadable,
+ key_dir_group_readable,
options->User,
- msg) < 0) {
- goto done;
+ msg_out) < 0) {
+ return -1;
}
- /* We need to handle the group-readable flag for the cache directory
- * specially, since the directory defaults to being the same as the
- * DataDirectory. */
- int cache_dir_group_readable;
- if (options->CacheDirectoryGroupReadable != -1) {
- /* If the user specified a value, use their setting */
- cache_dir_group_readable = options->CacheDirectoryGroupReadable;
- } else if (!strcmp(options->CacheDirectory, options->DataDirectory)) {
- /* If the user left the value as "auto", and the cache is the same as the
- * datadirectory, use the datadirectory setting.
- */
- cache_dir_group_readable = options->DataDirectoryGroupReadable;
- } else {
- /* Otherwise, "auto" means "not group readable". */
- cache_dir_group_readable = 0;
- }
+ const int cache_dir_group_readable = compute_group_readable_flag(
+ options->DataDirectory,
+ options->CacheDirectory,
+ options->DataDirectoryGroupReadable,
+ options->CacheDirectoryGroupReadable);
+
if (check_and_create_data_directory(running_tor /* create */,
options->CacheDirectory,
cache_dir_group_readable,
options->User,
- msg) < 0) {
- goto done;
+ msg_out) < 0) {
+ return -1;
}
- /* Bail out at this point if we're not going to be a client or server:
- * we don't run Tor itself. */
- if (!running_tor)
- goto commit;
+ return 0;
+}
+
+/** Structure to represent an incomplete configuration of a set of
+ * listeners.
+ *
+ * This structure is generated by options_start_listener_transaction(), and is
+ * either committed by options_commit_listener_transaction() or rolled back by
+ * options_rollback_listener_transaction(). */
+typedef struct listener_transaction_t {
+ bool set_conn_limit; /**< True if we've set the connection limit */
+ unsigned old_conn_limit; /**< If nonzero, previous connlimit value. */
+ smartlist_t *new_listeners; /**< List of new listeners that we opened. */
+} listener_transaction_t;
+
+/**
+ * Start configuring our listeners based on the current value of
+ * get_options().
+ *
+ * The value <b>old_options</b> holds either the previous options object,
+ * or NULL if we're starting for the first time.
+ *
+ * On success, return a listener_transaction_t that we can either roll back or
+ * commit.
+ *
+ * On failure return NULL and write a message into a newly allocated string in
+ * *<b>msg_out</b>.
+ **/
+static listener_transaction_t *
+options_start_listener_transaction(const or_options_t *old_options,
+ char **msg_out)
+{
+ listener_transaction_t *xn = tor_malloc_zero(sizeof(listener_transaction_t));
+ xn->new_listeners = smartlist_new();
+ or_options_t *options = get_options_mutable();
+ const bool running_tor = options->command == CMD_RUN_TOR;
+
+ if (! running_tor) {
+ return xn;
+ }
+
+ int n_ports=0;
+ /* We need to set the connection limit before we can open the listeners. */
+ if (! sandbox_is_active()) {
+ if (set_max_file_descriptors((unsigned)options->ConnLimit,
+ &options->ConnLimit_) < 0) {
+ *msg_out = tor_strdup("Problem with ConnLimit value. "
+ "See logs for details.");
+ goto rollback;
+ }
+ xn->set_conn_limit = true;
+ if (old_options)
+ xn->old_conn_limit = (unsigned)old_options->ConnLimit;
+ } else {
+ tor_assert(old_options);
+ options->ConnLimit_ = old_options->ConnLimit_;
+ }
+
+ /* Adjust the port configuration so we can launch listeners. */
+ /* 31851: some ports are relay-only */
+ if (parse_ports(options, 0, msg_out, &n_ports, NULL)) {
+ if (!*msg_out)
+ *msg_out = tor_strdup("Unexpected problem parsing port config");
+ goto rollback;
+ }
+
+ /* Set the hibernation state appropriately.*/
+ consider_hibernation(time(NULL));
+
+ /* Launch the listeners. (We do this before we setuid, so we can bind to
+ * ports under 1024.) We don't want to rebind if we're hibernating or
+ * shutting down. If networking is disabled, this will close all but the
+ * control listeners, but disable those. */
+ /* 31851: some listeners are relay-only */
+ if (!we_are_hibernating()) {
+ if (retry_all_listeners(xn->new_listeners,
+ options->DisableNetwork) < 0) {
+ *msg_out = tor_strdup("Failed to bind one of the listener ports.");
+ goto rollback;
+ }
+ }
+ if (options->DisableNetwork) {
+ /* Aggressively close non-controller stuff, NOW */
+ log_notice(LD_NET, "DisableNetwork is set. Tor will not make or accept "
+ "non-control network connections. Shutting down all existing "
+ "connections.");
+ connection_mark_all_noncontrol_connections();
+ /* We can't complete circuits until the network is re-enabled. */
+ note_that_we_maybe_cant_complete_circuits();
+ }
+
+#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
+ /* Open /dev/pf before (possibly) dropping privileges. */
+ if (options->TransPort_set &&
+ options->TransProxyType_parsed == TPT_DEFAULT) {
+ if (get_pf_socket() < 0) {
+ *msg_out = tor_strdup("Unable to open /dev/pf for transparent proxy.");
+ goto rollback;
+ }
+ }
+#endif /* defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) */
+
+ return xn;
+
+ rollback:
+ options_rollback_listener_transaction(xn);
+ return NULL;
+}
+
+/**
+ * Finish configuring the listeners that started to get configured with
+ * <b>xn</b>. Frees <b>xn</b>.
+ **/
+static void
+options_commit_listener_transaction(listener_transaction_t *xn)
+{
+ tor_assert(xn);
+ if (xn->set_conn_limit) {
+ or_options_t *options = get_options_mutable();
+ /*
+ * If we adjusted the conn limit, recompute the OOS threshold too
+ *
+ * How many possible sockets to keep in reserve? If we have lots of
+ * possible sockets, keep this below a limit and set ConnLimit_high_thresh
+ * very close to ConnLimit_, but if ConnLimit_ is low, shrink it in
+ * proportion.
+ *
+ * Somewhat arbitrarily, set socks_in_reserve to 5% of ConnLimit_, but
+ * cap it at 64.
+ */
+ int socks_in_reserve = options->ConnLimit_ / 20;
+ if (socks_in_reserve > 64) socks_in_reserve = 64;
+
+ options->ConnLimit_high_thresh = options->ConnLimit_ - socks_in_reserve;
+ options->ConnLimit_low_thresh = (options->ConnLimit_ / 4) * 3;
+ log_info(LD_GENERAL,
+ "Recomputed OOS thresholds: ConnLimit %d, ConnLimit_ %d, "
+ "ConnLimit_high_thresh %d, ConnLimit_low_thresh %d",
+ options->ConnLimit, options->ConnLimit_,
+ options->ConnLimit_high_thresh,
+ options->ConnLimit_low_thresh);
+
+ /* Give the OOS handler a chance with the new thresholds */
+ connection_check_oos(get_n_open_sockets(), 0);
+ }
+
+ smartlist_free(xn->new_listeners);
+ tor_free(xn);
+}
+
+/**
+ * Revert the listener configuration changes that that started to get
+ * configured with <b>xn</b>. Frees <b>xn</b>.
+ **/
+static void
+options_rollback_listener_transaction(listener_transaction_t *xn)
+{
+ if (! xn)
+ return;
+
+ or_options_t *options = get_options_mutable();
+
+ if (xn->set_conn_limit && xn->old_conn_limit)
+ set_max_file_descriptors(xn->old_conn_limit, &options->ConnLimit_);
+
+ SMARTLIST_FOREACH(xn->new_listeners, connection_t *, conn,
+ {
+ log_notice(LD_NET, "Closing partially-constructed %s on %s:%d",
+ conn_type_to_string(conn->type), conn->address, conn->port);
+ connection_close_immediate(conn);
+ connection_mark_for_close(conn);
+ });
+
+ smartlist_free(xn->new_listeners);
+ tor_free(xn);
+}
+
+/** Structure to represent an incomplete configuration of a set of logs.
+ *
+ * This structure is generated by options_start_log_transaction(), and is
+ * either committed by options_commit_log_transaction() or rolled back by
+ * options_rollback_log_transaction(). */
+typedef struct log_transaction_t {
+ /** Previous lowest severity of any configured log. */
+ int old_min_log_level;
+ /** True if we have marked the previous logs to be closed */
+ bool logs_marked;
+ /** True if we initialized the new set of logs */
+ bool logs_initialized;
+ /** True if our safelogging configuration is different from what it was
+ * previously (or if we are starting for the first time). */
+ bool safelogging_changed;
+} log_transaction_t;
+
+/**
+ * Start configuring our logs based on the current value of get_options().
+ *
+ * The value <b>old_options</b> holds either the previous options object,
+ * or NULL if we're starting for the first time.
+ *
+ * On success, return a log_transaction_t that we can either roll back or
+ * commit.
+ *
+ * On failure return NULL and write a message into a newly allocated string in
+ * *<b>msg_out</b>.
+ **/
+STATIC log_transaction_t *
+options_start_log_transaction(const or_options_t *old_options,
+ char **msg_out)
+{
+ const or_options_t *options = get_options();
+ const bool running_tor = options->command == CMD_RUN_TOR;
+
+ log_transaction_t *xn = tor_malloc_zero(sizeof(log_transaction_t));
+ xn->old_min_log_level = get_min_log_level();
+ xn->safelogging_changed = !old_options ||
+ old_options->SafeLogging_ != options->SafeLogging_;
+
+ if (! running_tor)
+ goto done;
mark_logs_temp(); /* Close current logs once new logs are open. */
- logs_marked = 1;
+ xn->logs_marked = true;
/* Configure the tor_log(s) */
if (options_init_logs(old_options, options, 0)<0) {
- *msg = tor_strdup("Failed to init Log options. See logs for details.");
- goto rollback;
+ *msg_out = tor_strdup("Failed to init Log options. See logs for details.");
+ options_rollback_log_transaction(xn);
+ xn = NULL;
+ goto done;
}
- logs_initialized = 1;
- commit:
- r = 0;
- if (logs_marked) {
+ xn->logs_initialized = true;
+
+ done:
+ return xn;
+}
+
+/**
+ * Finish configuring the logs that started to get configured with <b>xn</b>.
+ * Frees <b>xn</b>.
+ **/
+STATIC void
+options_commit_log_transaction(log_transaction_t *xn)
+{
+ const or_options_t *options = get_options();
+ tor_assert(xn);
+
+ if (xn->logs_marked) {
log_severity_list_t *severity =
tor_malloc_zero(sizeof(log_severity_list_t));
close_temp_logs();
@@ -1640,7 +1825,8 @@ options_act_reversible(const or_options_t *old_options, char **msg)
tor_free(severity);
tor_log_update_sigsafe_err_fds();
}
- if (logs_initialized) {
+
+ if (xn->logs_initialized) {
flush_log_messages_from_startup();
}
@@ -1649,12 +1835,12 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int bad_safelog = 0, bad_severity = 0, new_badness = 0;
if (options->SafeLogging_ != SAFELOG_SCRUB_ALL) {
bad_safelog = 1;
- if (!old_options || old_options->SafeLogging_ != options->SafeLogging_)
+ if (xn->safelogging_changed)
new_badness = 1;
}
if (get_min_log_level() >= LOG_INFO) {
bad_severity = 1;
- if (get_min_log_level() != old_min_log_level)
+ if (get_min_log_level() != xn->old_min_log_level)
new_badness = 1;
}
if (bad_safelog && bad_severity)
@@ -1670,59 +1856,105 @@ options_act_reversible(const or_options_t *old_options, char **msg)
"Overwrite the log afterwards.", badness);
}
- if (set_conn_limit) {
- /*
- * If we adjusted the conn limit, recompute the OOS threshold too
- *
- * How many possible sockets to keep in reserve? If we have lots of
- * possible sockets, keep this below a limit and set ConnLimit_high_thresh
- * very close to ConnLimit_, but if ConnLimit_ is low, shrink it in
- * proportion.
- *
- * Somewhat arbitrarily, set socks_in_reserve to 5% of ConnLimit_, but
- * cap it at 64.
- */
- int socks_in_reserve = options->ConnLimit_ / 20;
- if (socks_in_reserve > 64) socks_in_reserve = 64;
+ tor_free(xn);
+}
- options->ConnLimit_high_thresh = options->ConnLimit_ - socks_in_reserve;
- options->ConnLimit_low_thresh = (options->ConnLimit_ / 4) * 3;
- log_info(LD_GENERAL,
- "Recomputed OOS thresholds: ConnLimit %d, ConnLimit_ %d, "
- "ConnLimit_high_thresh %d, ConnLimit_low_thresh %d",
- options->ConnLimit, options->ConnLimit_,
- options->ConnLimit_high_thresh,
- options->ConnLimit_low_thresh);
+/**
+ * Revert the log configuration changes that that started to get configured
+ * with <b>xn</b>. Frees <b>xn</b>.
+ **/
+STATIC void
+options_rollback_log_transaction(log_transaction_t *xn)
+{
+ if (!xn)
+ return;
- /* Give the OOS handler a chance with the new thresholds */
- connection_check_oos(get_n_open_sockets(), 0);
+ if (xn->logs_marked) {
+ rollback_log_changes();
+ control_adjust_event_log_severity();
}
+ tor_free(xn);
+}
+
+/**
+ * Fetch the active option list, and take actions based on it. All of
+ * the things we do in this function should survive being done
+ * repeatedly, OR be done only once when starting Tor. If present,
+ * <b>old_options</b> contains the previous value of the options.
+ *
+ * This function is only truly "reversible" _after_ the first time it
+ * is run. The first time that it runs, it performs some irreversible
+ * tasks in the correct sequence between the reversible option changes.
+ *
+ * Option changes should only be marked as "reversible" if they cannot
+ * be validated before switching them, but they can be switched back if
+ * some other validation fails.
+ *
+ * Return 0 if all goes well, return -1 if things went badly.
+ */
+MOCK_IMPL(STATIC int,
+options_act_reversible,(const or_options_t *old_options, char **msg))
+{
+ const bool first_time = ! have_set_startup_options;
+ log_transaction_t *log_transaction = NULL;
+ listener_transaction_t *listener_transaction = NULL;
+ int r = -1;
+
+ /* The ordering of actions in this function is not free, sadly.
+ *
+ * First of all, we _must_ daemonize before we take all kinds of
+ * initialization actions, since they need to happen in the
+ * subprocess.
+ */
+ if (options_act_once_on_startup(msg) < 0)
+ goto rollback;
+
+ /* Once we've handled most of once-off initialization, we need to
+ * open our listeners before we switch IDs. (If we open listeners first,
+ * we might not be able to bind to low ports.)
+ */
+ listener_transaction = options_start_listener_transaction(old_options, msg);
+ if (listener_transaction == NULL)
+ goto rollback;
+
+ if (first_time) {
+ if (options_switch_id(msg) < 0)
+ goto rollback;
+ }
+
+ /* On the other hand, we need to touch the file system _after_ we
+ * switch IDs: otherwise, we'll be making directories and opening files
+ * with the wrong permissions.
+ */
+ if (first_time) {
+ if (options_create_directories(msg) < 0)
+ goto rollback;
+ }
+
+ /* Bail out at this point if we're not going to be a client or server:
+ * we don't run Tor itself. */
+ log_transaction = options_start_log_transaction(old_options, msg);
+ if (log_transaction == NULL)
+ goto rollback;
+
+ // Commit!
+ r = 0;
+
+ options_commit_log_transaction(log_transaction);
+
+ options_commit_listener_transaction(listener_transaction);
+
goto done;
rollback:
r = -1;
tor_assert(*msg);
- if (logs_marked) {
- rollback_log_changes();
- control_adjust_event_log_severity();
- }
-
- if (set_conn_limit && old_options)
- set_max_file_descriptors((unsigned)old_options->ConnLimit,
- &options->ConnLimit_);
-
- SMARTLIST_FOREACH(new_listeners, connection_t *, conn,
- {
- log_notice(LD_NET, "Closing partially-constructed %s on %s:%d",
- conn_type_to_string(conn->type), conn->address, conn->port);
- connection_close_immediate(conn);
- connection_mark_for_close(conn);
- });
+ options_rollback_log_transaction(log_transaction);
+ options_rollback_listener_transaction(listener_transaction);
done:
- smartlist_free(new_listeners);
return r;
}
@@ -1753,32 +1985,6 @@ options_need_geoip_info(const or_options_t *options, const char **reason_out)
return bridge_usage || routerset_usage;
}
-/** Return the bandwidthrate that we are going to report to the authorities
- * based on the config options. */
-uint32_t
-get_effective_bwrate(const or_options_t *options)
-{
- uint64_t bw = options->BandwidthRate;
- if (bw > options->MaxAdvertisedBandwidth)
- bw = options->MaxAdvertisedBandwidth;
- if (options->RelayBandwidthRate > 0 && bw > options->RelayBandwidthRate)
- bw = options->RelayBandwidthRate;
- /* ensure_bandwidth_cap() makes sure that this cast can't overflow. */
- return (uint32_t)bw;
-}
-
-/** Return the bandwidthburst that we are going to report to the authorities
- * based on the config options. */
-uint32_t
-get_effective_bwburst(const or_options_t *options)
-{
- uint64_t bw = options->BandwidthBurst;
- if (options->RelayBandwidthBurst > 0 && bw > options->RelayBandwidthBurst)
- bw = options->RelayBandwidthBurst;
- /* ensure_bandwidth_cap() makes sure that this cast can't overflow. */
- return (uint32_t)bw;
-}
-
/* Used in the various options_transition_affects* functions. */
#define YES_IF_CHANGED_BOOL(opt) \
if (!CFG_EQ_BOOL(old_options, new_options, opt)) return 1;
@@ -1821,32 +2027,6 @@ options_transition_affects_guards(const or_options_t *old_options,
return 0;
}
-/**
- * Return true if changing the configuration from <b>old</b> to <b>new</b>
- * affects the timing of the voting subsystem
- */
-static int
-options_transition_affects_dirauth_timing(const or_options_t *old_options,
- const or_options_t *new_options)
-{
- tor_assert(old_options);
- tor_assert(new_options);
-
- if (authdir_mode_v3(old_options) != authdir_mode_v3(new_options))
- return 1;
- if (! authdir_mode_v3(new_options))
- return 0;
- YES_IF_CHANGED_INT(V3AuthVotingInterval);
- YES_IF_CHANGED_INT(V3AuthVoteDelay);
- YES_IF_CHANGED_INT(V3AuthDistDelay);
- YES_IF_CHANGED_INT(TestingV3AuthInitialVotingInterval);
- YES_IF_CHANGED_INT(TestingV3AuthInitialVoteDelay);
- YES_IF_CHANGED_INT(TestingV3AuthInitialDistDelay);
- YES_IF_CHANGED_INT(TestingV3AuthVotingStartOffset);
-
- return 0;
-}
-
/** Fetch the active option list, and take actions based on it. All of the
* things we do should survive being done repeatedly. If present,
* <b>old_options</b> contains the previous value of the options.
@@ -1854,17 +2034,16 @@ options_transition_affects_dirauth_timing(const or_options_t *old_options,
* Return 0 if all goes well, return -1 if it's time to die.
*
* Note: We haven't moved all the "act on new configuration" logic
- * here yet. Some is still in do_hup() and other places.
+ * the options_act* functions yet. Some is still in do_hup() and other
+ * places.
*/
-STATIC int
-options_act(const or_options_t *old_options)
+MOCK_IMPL(STATIC int,
+options_act,(const or_options_t *old_options))
{
config_line_t *cl;
or_options_t *options = get_options_mutable();
int running_tor = options->command == CMD_RUN_TOR;
char *msg=NULL;
- const int transition_affects_workers =
- old_options && options_transition_affects_workers(old_options, options);
const int transition_affects_guards =
old_options && options_transition_affects_guards(old_options, options);
@@ -1922,19 +2101,6 @@ options_act(const or_options_t *old_options)
"in a non-anonymous mode. It will provide NO ANONYMITY.");
}
- /* If we are a bridge with a pluggable transport proxy but no
- Extended ORPort, inform the user that they are missing out. */
- if (server_mode(options) && options->ServerTransportPlugin &&
- !options->ExtORPort_lines) {
- log_notice(LD_CONFIG, "We use pluggable transports but the Extended "
- "ORPort is disabled. Tor and your pluggable transports proxy "
- "communicate with each other via the Extended ORPort so it "
- "is suggested you enable it: it will also allow your Bridge "
- "to collect statistics about its clients that use pluggable "
- "transports. Please enable it using the ExtORPort torrc option "
- "(e.g. set 'ExtORPort auto').");
- }
-
if (options->Bridges) {
mark_bridge_list();
for (cl = options->Bridges; cl; cl = cl->next) {
@@ -1984,22 +2150,17 @@ options_act(const or_options_t *old_options)
if (! or_state_loaded() && running_tor) {
if (or_state_load())
return -1;
- rep_hist_load_mtbf_data(time(NULL));
- }
-
- /* If we have an ExtORPort, initialize its auth cookie. */
- if (running_tor &&
- init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
- log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
- return -1;
+ if (options_act_dirauth_mtbf(options) < 0)
+ return -1;
}
+ /* 31851: some of the code in these functions is relay-only */
mark_transport_list();
pt_prepare_proxy_list_for_config_read();
if (!options->DisableNetwork) {
if (options->ClientTransportPlugin) {
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
- if (parse_transport_line(options, cl->value, 0, 0) < 0) {
+ if (pt_parse_transport_line(options, cl->value, 0, 0) < 0) {
// LCOV_EXCL_START
log_warn(LD_BUG,
"Previously validated ClientTransportPlugin line "
@@ -2009,20 +2170,11 @@ options_act(const or_options_t *old_options)
}
}
}
-
- if (options->ServerTransportPlugin && server_mode(options)) {
- for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
- if (parse_transport_line(options, cl->value, 0, 1) < 0) {
- // LCOV_EXCL_START
- log_warn(LD_BUG,
- "Previously validated ServerTransportPlugin line "
- "could not be added!");
- return -1;
- // LCOV_EXCL_STOP
- }
- }
- }
}
+
+ if (options_act_server_transport(old_options) < 0)
+ return -1;
+
sweep_transport_list();
sweep_proxy_list();
@@ -2043,16 +2195,8 @@ options_act(const or_options_t *old_options)
finish_daemon(options->DataDirectory);
}
- /* We want to reinit keys as needed before we do much of anything else:
- keys are important, and other things can depend on them. */
- if (transition_affects_workers ||
- (options->V3AuthoritativeDir && (!old_options ||
- !old_options->V3AuthoritativeDir))) {
- if (init_keys() < 0) {
- log_warn(LD_BUG,"Error initializing keys; exiting");
- return -1;
- }
- }
+ if (options_act_relay(old_options) < 0)
+ return -1;
/* Write our PID to the PID file. If we do not have write permissions we
* will log a warning and exit. */
@@ -2076,15 +2220,6 @@ options_act(const or_options_t *old_options)
return -1;
}
- if (server_mode(options)) {
- static int cdm_initialized = 0;
- if (cdm_initialized == 0) {
- cdm_initialized = 1;
- consdiffmgr_configure(NULL);
- consdiffmgr_validate();
- }
- }
-
if (init_control_cookie_authentication(options->CookieAuthentication) < 0) {
log_warn(LD_CONFIG,"Error creating control cookie authentication file.");
return -1;
@@ -2102,15 +2237,8 @@ options_act(const or_options_t *old_options)
* might be a change of scheduler or parameter. */
scheduler_conf_changed();
- /* Set up accounting */
- if (accounting_parse_options(options, 0)<0) {
- // LCOV_EXCL_START
- log_warn(LD_BUG,"Error in previously validated accounting options");
+ if (options_act_relay_accounting(old_options) < 0)
return -1;
- // LCOV_EXCL_STOP
- }
- if (accounting_is_enabled(options))
- configure_accounting(time(NULL));
/* Change the cell EWMA settings */
cmux_ewma_set_options(options, networkstatus_get_latest_consensus());
@@ -2134,6 +2262,7 @@ options_act(const or_options_t *old_options)
tor_free(http_authenticator);
}
+ /* 31851: OutboundBindAddressExit is relay-only */
if (parse_outbound_addresses(options, 0, &msg) < 0) {
// LCOV_EXCL_START
log_warn(LD_BUG, "Failed parsing previously validated outbound "
@@ -2220,65 +2349,17 @@ options_act(const or_options_t *old_options)
if (revise_automap_entries)
addressmap_clear_invalid_automaps(options);
-/* How long should we delay counting bridge stats after becoming a bridge?
- * We use this so we don't count clients who used our bridge thinking it is
- * a relay. If you change this, don't forget to change the log message
- * below. It's 4 hours (the time it takes to stop being used by clients)
- * plus some extra time for clock skew. */
-#define RELAY_BRIDGE_STATS_DELAY (6 * 60 * 60)
-
- if (! bool_eq(options->BridgeRelay, old_options->BridgeRelay)) {
- int was_relay = 0;
- if (options->BridgeRelay) {
- time_t int_start = time(NULL);
- if (config_lines_eq(old_options->ORPort_lines,options->ORPort_lines)) {
- int_start += RELAY_BRIDGE_STATS_DELAY;
- was_relay = 1;
- }
- geoip_bridge_stats_init(int_start);
- log_info(LD_CONFIG, "We are acting as a bridge now. Starting new "
- "GeoIP stats interval%s.", was_relay ? " in 6 "
- "hours from now" : "");
- } else {
- geoip_bridge_stats_term();
- log_info(LD_GENERAL, "We are no longer acting as a bridge. "
- "Forgetting GeoIP stats.");
- }
- }
-
- if (transition_affects_workers) {
- log_info(LD_GENERAL,
- "Worker-related options changed. Rotating workers.");
- const int server_mode_turned_on =
- server_mode(options) && !server_mode(old_options);
- const int dir_server_mode_turned_on =
- dir_server_mode(options) && !dir_server_mode(old_options);
-
- if (server_mode_turned_on || dir_server_mode_turned_on) {
- cpu_init();
- }
+ if (options_act_bridge_stats(old_options) < 0)
+ return -1;
- if (server_mode_turned_on) {
- ip_address_changed(0);
- if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL)))
- inform_testing_reachability();
- }
- cpuworkers_rotate_keyinfo();
- if (dns_reset())
- return -1;
- } else {
- if (dns_reset())
- return -1;
- }
+ if (dns_reset())
+ return -1;
- if (options->PerConnBWRate != old_options->PerConnBWRate ||
- options->PerConnBWBurst != old_options->PerConnBWBurst)
- connection_or_update_token_buckets(get_connection_array(), options);
+ if (options_act_relay_bandwidth(old_options) < 0)
+ return -1;
if (options->BandwidthRate != old_options->BandwidthRate ||
- options->BandwidthBurst != old_options->BandwidthBurst ||
- options->RelayBandwidthRate != old_options->RelayBandwidthRate ||
- options->RelayBandwidthBurst != old_options->RelayBandwidthBurst)
+ options->BandwidthBurst != old_options->BandwidthBurst)
connection_bucket_adjust(options);
if (options->MainloopStats != old_options->MainloopStats) {
@@ -2286,132 +2367,43 @@ options_act(const or_options_t *old_options)
}
}
+ /* 31851: These options are relay-only, but we need to disable them if we
+ * are in client mode. In 29211, we will disable all relay options in
+ * client mode. */
/* Only collect directory-request statistics on relays and bridges. */
options->DirReqStatistics = options->DirReqStatistics_option &&
server_mode(options);
options->HiddenServiceStatistics =
options->HiddenServiceStatistics_option && server_mode(options);
- if (options->CellStatistics || options->DirReqStatistics ||
- options->EntryStatistics || options->ExitPortStatistics ||
- options->ConnDirectionStatistics ||
- options->HiddenServiceStatistics ||
- options->BridgeAuthoritativeDir) {
- time_t now = time(NULL);
- int print_notice = 0;
-
- /* Only collect other relay-only statistics on relays. */
- if (!public_server_mode(options)) {
- options->CellStatistics = 0;
- options->EntryStatistics = 0;
- options->ConnDirectionStatistics = 0;
- options->ExitPortStatistics = 0;
- }
-
- if ((!old_options || !old_options->CellStatistics) &&
- options->CellStatistics) {
- rep_hist_buffer_stats_init(now);
- print_notice = 1;
- }
- if ((!old_options || !old_options->DirReqStatistics) &&
- options->DirReqStatistics) {
- if (geoip_is_loaded(AF_INET)) {
- geoip_dirreq_stats_init(now);
- print_notice = 1;
- } else {
- /* disable statistics collection since we have no geoip file */
- options->DirReqStatistics = 0;
- if (options->ORPort_set)
- log_notice(LD_CONFIG, "Configured to measure directory request "
- "statistics, but no GeoIP database found. "
- "Please specify a GeoIP database using the "
- "GeoIPFile option.");
- }
- }
- if ((!old_options || !old_options->EntryStatistics) &&
- options->EntryStatistics && !should_record_bridge_info(options)) {
- /* If we get here, we've started recording bridge info when we didn't
- * do so before. Note that "should_record_bridge_info()" will
- * always be false at this point, because of the earlier block
- * that cleared EntryStatistics when public_server_mode() was false.
- * We're leaving it in as defensive programming. */
- if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) {
- geoip_entry_stats_init(now);
- print_notice = 1;
- } else {
- options->EntryStatistics = 0;
- log_notice(LD_CONFIG, "Configured to measure entry node "
- "statistics, but no GeoIP database found. "
- "Please specify a GeoIP database using the "
- "GeoIPFile option.");
- }
- }
- if ((!old_options || !old_options->ExitPortStatistics) &&
- options->ExitPortStatistics) {
- rep_hist_exit_stats_init(now);
- print_notice = 1;
- }
- if ((!old_options || !old_options->ConnDirectionStatistics) &&
- options->ConnDirectionStatistics) {
- rep_hist_conn_stats_init(now);
- }
- if ((!old_options || !old_options->HiddenServiceStatistics) &&
- options->HiddenServiceStatistics) {
- log_info(LD_CONFIG, "Configured to measure hidden service statistics.");
- rep_hist_hs_stats_init(now);
- }
- if ((!old_options || !old_options->BridgeAuthoritativeDir) &&
- options->BridgeAuthoritativeDir) {
- rep_hist_desc_stats_init(now);
- print_notice = 1;
- }
- if (print_notice)
- log_notice(LD_CONFIG, "Configured to measure statistics. Look for "
- "the *-stats files that will first be written to the "
- "data directory in 24 hours from now.");
- }
-
- /* If we used to have statistics enabled but we just disabled them,
- stop gathering them. */
- if (old_options && old_options->CellStatistics &&
- !options->CellStatistics)
- rep_hist_buffer_stats_term();
- if (old_options && old_options->DirReqStatistics &&
- !options->DirReqStatistics)
- geoip_dirreq_stats_term();
- if (old_options && old_options->EntryStatistics &&
- !options->EntryStatistics)
- geoip_entry_stats_term();
- if (old_options && old_options->HiddenServiceStatistics &&
- !options->HiddenServiceStatistics)
- rep_hist_hs_stats_term();
- if (old_options && old_options->ExitPortStatistics &&
- !options->ExitPortStatistics)
- rep_hist_exit_stats_term();
- if (old_options && old_options->ConnDirectionStatistics &&
- !options->ConnDirectionStatistics)
- rep_hist_conn_stats_term();
- if (old_options && old_options->BridgeAuthoritativeDir &&
- !options->BridgeAuthoritativeDir)
- rep_hist_desc_stats_term();
-
- /* Since our options changed, we might need to regenerate and upload our
- * server descriptor.
- */
- if (!old_options ||
- options_transition_affects_descriptor(old_options, options))
- mark_my_descriptor_dirty("config change");
+ /* Only collect other relay-only statistics on relays. */
+ if (!public_server_mode(options)) {
+ options->CellStatistics = 0;
+ options->EntryStatistics = 0;
+ options->ConnDirectionStatistics = 0;
+ options->ExitPortStatistics = 0;
+ }
+
+ bool print_notice = 0;
+ if (options_act_relay_stats(old_options, &print_notice) < 0)
+ return -1;
+ if (options_act_dirauth_stats(old_options, &print_notice) < 0)
+ return -1;
+ if (print_notice)
+ options_act_relay_stats_msg();
+
+ if (options_act_relay_desc(old_options) < 0)
+ return -1;
+
+ if (options_act_dirauth(old_options) < 0)
+ return -1;
/* We may need to reschedule some directory stuff if our status changed. */
if (old_options) {
- if (options_transition_affects_dirauth_timing(old_options, options)) {
- voting_schedule_recalculate_timing(options, time(NULL));
- reschedule_dirvote(options);
- }
- if (!bool_eq(directory_fetches_dir_info_early(options),
- directory_fetches_dir_info_early(old_options)) ||
- !bool_eq(directory_fetches_dir_info_later(options),
- directory_fetches_dir_info_later(old_options)) ||
+ if (!bool_eq(dirclient_fetches_dir_info_early(options),
+ dirclient_fetches_dir_info_early(old_options)) ||
+ !bool_eq(dirclient_fetches_dir_info_later(options),
+ dirclient_fetches_dir_info_later(old_options)) ||
!config_lines_eq(old_options->Bridges, options->Bridges)) {
/* Make sure update_router_have_minimum_dir_info() gets called. */
router_dir_info_changed();
@@ -2421,87 +2413,113 @@ options_act(const or_options_t *old_options)
}
}
- /* DoS mitigation subsystem only applies to public relay. */
- if (public_server_mode(options)) {
- /* If we are configured as a relay, initialize the subsystem. Even on HUP,
- * this is safe to call as it will load data from the current options
- * or/and the consensus. */
- dos_init();
- } else if (old_options && public_server_mode(old_options)) {
- /* Going from relay to non relay, clean it up. */
- dos_free_all();
- }
-
- /* Load the webpage we're going to serve every time someone asks for '/' on
- our DirPort. */
- tor_free(global_dirfrontpagecontents);
- if (options->DirPortFrontPage) {
- global_dirfrontpagecontents =
- read_file_to_str(options->DirPortFrontPage, 0, NULL);
- if (!global_dirfrontpagecontents) {
- log_warn(LD_CONFIG,
- "DirPortFrontPage file '%s' not found. Continuing anyway.",
- options->DirPortFrontPage);
- }
- }
+ if (options_act_relay_dos(old_options) < 0)
+ return -1;
+ if (options_act_relay_dir(old_options) < 0)
+ return -1;
return 0;
}
+/**
+ * Enumeration to describe the syntax for a command-line option.
+ **/
typedef enum {
- TAKES_NO_ARGUMENT = 0,
+ /** Describe an option that does not take an argument. */
+ ARGUMENT_NONE = 0,
+ /** Describes an option that takes a single argument. */
ARGUMENT_NECESSARY = 1,
+ /** Describes an option that takes a single optional argument. */
ARGUMENT_OPTIONAL = 2
} takes_argument_t;
+/** Table describing arguments that Tor accepts on the command line,
+ * other than those that are the same as in torrc. */
static const struct {
+ /** The string that the user has to provide. */
const char *name;
+ /** Does this option accept an argument? */
takes_argument_t takes_argument;
+ /** If not CMD_RUN_TOR, what should Tor do when it starts? */
+ tor_cmdline_mode_t command;
+ /** If nonzero, set the quiet level to this. 1 is "hush", 2 is "quiet" */
+ int quiet;
} CMDLINE_ONLY_OPTIONS[] = {
- { "-f", ARGUMENT_NECESSARY },
- { "--allow-missing-torrc", TAKES_NO_ARGUMENT },
- { "--defaults-torrc", ARGUMENT_NECESSARY },
- { "--hash-password", ARGUMENT_NECESSARY },
- { "--dump-config", ARGUMENT_OPTIONAL },
- { "--list-fingerprint", TAKES_NO_ARGUMENT },
- { "--keygen", TAKES_NO_ARGUMENT },
- { "--key-expiration", ARGUMENT_OPTIONAL },
- { "--newpass", TAKES_NO_ARGUMENT },
- { "--no-passphrase", TAKES_NO_ARGUMENT },
- { "--passphrase-fd", ARGUMENT_NECESSARY },
- { "--verify-config", TAKES_NO_ARGUMENT },
- { "--ignore-missing-torrc", TAKES_NO_ARGUMENT },
- { "--quiet", TAKES_NO_ARGUMENT },
- { "--hush", TAKES_NO_ARGUMENT },
- { "--version", TAKES_NO_ARGUMENT },
- { "--list-modules", TAKES_NO_ARGUMENT },
- { "--library-versions", TAKES_NO_ARGUMENT },
- { "-h", TAKES_NO_ARGUMENT },
- { "--help", TAKES_NO_ARGUMENT },
- { "--list-torrc-options", TAKES_NO_ARGUMENT },
- { "--list-deprecated-options",TAKES_NO_ARGUMENT },
- { "--nt-service", TAKES_NO_ARGUMENT },
- { "-nt-service", TAKES_NO_ARGUMENT },
- { NULL, 0 },
+ { .name="-f",
+ .takes_argument=ARGUMENT_NECESSARY },
+ { .name="--allow-missing-torrc" },
+ { .name="--defaults-torrc",
+ .takes_argument=ARGUMENT_NECESSARY },
+ { .name="--hash-password",
+ .takes_argument=ARGUMENT_NECESSARY,
+ .command=CMD_HASH_PASSWORD,
+ .quiet=QUIET_HUSH },
+ { .name="--dump-config",
+ .takes_argument=ARGUMENT_OPTIONAL,
+ .command=CMD_DUMP_CONFIG,
+ .quiet=QUIET_SILENT },
+ { .name="--list-fingerprint",
+ .command=CMD_LIST_FINGERPRINT },
+ { .name="--keygen",
+ .command=CMD_KEYGEN },
+ { .name="--key-expiration",
+ .takes_argument=ARGUMENT_OPTIONAL,
+ .command=CMD_KEY_EXPIRATION },
+ { .name="--newpass" },
+ { .name="--no-passphrase" },
+ { .name="--passphrase-fd",
+ .takes_argument=ARGUMENT_NECESSARY },
+ { .name="--verify-config",
+ .command=CMD_VERIFY_CONFIG },
+ { .name="--ignore-missing-torrc" },
+ { .name="--quiet",
+ .quiet=QUIET_SILENT },
+ { .name="--hush",
+ .quiet=QUIET_HUSH },
+ { .name="--version",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
+ { .name="--list-modules",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
+ { .name="--library-versions",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
+ { .name="-h",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
+ { .name="--help",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
+ { .name="--list-torrc-options",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
+ { .name="--list-deprecated-options",
+ .command=CMD_IMMEDIATE },
+ { .name="--nt-service" },
+ { .name="-nt-service" },
+ { .name="--dbg-dump-subsystem-list",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
+ { .name=NULL },
};
/** Helper: Read a list of configuration options from the command line. If
- * successful, or if ignore_errors is set, put them in *<b>result</b>, put the
- * commandline-only options in *<b>cmdline_result</b>, and return 0;
- * otherwise, return -1 and leave *<b>result</b> and <b>cmdline_result</b>
- * alone. */
-int
-config_parse_commandline(int argc, char **argv, int ignore_errors,
- config_line_t **result,
- config_line_t **cmdline_result)
+ * successful, return a newly allocated parsed_cmdline_t; otherwise return
+ * NULL.
+ *
+ * If <b>ignore_errors</b> is set, try to recover from all recoverable
+ * errors and return the best command line we can.
+ */
+parsed_cmdline_t *
+config_parse_commandline(int argc, char **argv, int ignore_errors)
{
+ parsed_cmdline_t *result = tor_malloc_zero(sizeof(parsed_cmdline_t));
+ result->command = CMD_RUN_TOR;
config_line_t *param = NULL;
- config_line_t *front = NULL;
- config_line_t **new = &front;
-
- config_line_t *front_cmdline = NULL;
- config_line_t **new_cmdline = &front_cmdline;
+ config_line_t **new_cmdline = &result->cmdline_opts;
+ config_line_t **new = &result->other_opts;
char *s, *arg;
int i = 1;
@@ -2511,11 +2529,19 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
takes_argument_t want_arg = ARGUMENT_NECESSARY;
int is_cmdline = 0;
int j;
+ bool is_a_command = false;
for (j = 0; CMDLINE_ONLY_OPTIONS[j].name != NULL; ++j) {
if (!strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].name)) {
is_cmdline = 1;
want_arg = CMDLINE_ONLY_OPTIONS[j].takes_argument;
+ if (CMDLINE_ONLY_OPTIONS[j].command != CMD_RUN_TOR) {
+ is_a_command = true;
+ result->command = CMDLINE_ONLY_OPTIONS[j].command;
+ }
+ quiet_level_t quiet = CMDLINE_ONLY_OPTIONS[j].quiet;
+ if (quiet > result->quiet_level)
+ result->quiet_level = quiet;
break;
}
}
@@ -2546,14 +2572,13 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
} else {
log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
argv[i]);
- config_free_lines(front);
- config_free_lines(front_cmdline);
- return -1;
+ parsed_cmdline_free(result);
+ return NULL;
}
} else if (want_arg == ARGUMENT_OPTIONAL && is_last) {
arg = tor_strdup("");
} else {
- arg = (want_arg != TAKES_NO_ARGUMENT) ? tor_strdup(argv[i+1]) :
+ arg = (want_arg != ARGUMENT_NONE) ? tor_strdup(argv[i+1]) :
tor_strdup("");
}
@@ -2566,6 +2591,10 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
log_debug(LD_CONFIG, "command line: parsed keyword '%s', value '%s'",
param->key, param->value);
+ if (is_a_command) {
+ result->command_arg = param->value;
+ }
+
if (is_cmdline) {
*new_cmdline = param;
new_cmdline = &((*new_cmdline)->next);
@@ -2576,9 +2605,19 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
i += want_arg ? 2 : 1;
}
- *cmdline_result = front_cmdline;
- *result = front;
- return 0;
+
+ return result;
+}
+
+/** Release all storage held by <b>cmdline</b>. */
+void
+parsed_cmdline_free_(parsed_cmdline_t *cmdline)
+{
+ if (!cmdline)
+ return;
+ config_free_lines(cmdline->cmdline_opts);
+ config_free_lines(cmdline->other_opts);
+ tor_free(cmdline);
}
/** Return true iff key is a valid configuration option. */
@@ -2624,37 +2663,9 @@ options_trial_assign(config_line_t *list, unsigned flags, char **msg)
or_options_free(trial_options);
return r;
}
+ const or_options_t *cur_options = get_options();
- setopt_err_t rv;
- or_options_t *cur_options = get_options_mutable();
-
- in_option_validation = 1;
-
- if (options_validate(cur_options, trial_options,
- global_default_options, 1, msg) < 0) {
- or_options_free(trial_options);
- rv = SETOPT_ERR_PARSE; /*XXX make this a separate return value. */
- goto done;
- }
-
- if (options_transition_allowed(cur_options, trial_options, msg) < 0) {
- or_options_free(trial_options);
- rv = SETOPT_ERR_TRANSITION;
- goto done;
- }
- in_option_validation = 0;
-
- if (set_options(trial_options, msg)<0) {
- or_options_free(trial_options);
- rv = SETOPT_ERR_SETTING;
- goto done;
- }
-
- /* we liked it. put it in place. */
- rv = SETOPT_OK;
- done:
- in_option_validation = 0;
- return rv;
+ return options_validate_and_set(cur_options, trial_options, msg);
}
/** Print a usage message for tor. */
@@ -2664,7 +2675,7 @@ print_usage(void)
printf(
"Copyright (c) 2001-2004, Roger Dingledine\n"
"Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n"
-"Copyright (c) 2007-2019, The Tor Project, Inc.\n\n"
+"Copyright (c) 2007-2020, The Tor Project, Inc.\n\n"
"tor -f <torrc> [args]\n"
"See man page for options, or https://www.torproject.org/ for "
"documentation.\n");
@@ -2704,24 +2715,11 @@ list_deprecated_options(void)
static void
list_enabled_modules(void)
{
+ printf("%s: %s\n", "relay", have_module_relay() ? "yes" : "no");
printf("%s: %s\n", "dirauth", have_module_dirauth() ? "yes" : "no");
-}
-
-/** Last value actually set by resolve_my_address. */
-static uint32_t last_resolved_addr = 0;
-
-/** Accessor for last_resolved_addr from outside this file. */
-uint32_t
-get_last_resolved_addr(void)
-{
- return last_resolved_addr;
-}
-
-/** Reset last_resolved_addr from outside this file. */
-void
-reset_last_resolved_addr(void)
-{
- last_resolved_addr = 0;
+ // We don't list dircache, because it cannot be enabled or disabled
+ // independently from relay. Listing it here would proliferate
+ // test variants in test_parseconf.sh to no useful purpose.
}
/* Return true if <b>options</b> is using the default authorities, and false
@@ -2732,282 +2730,13 @@ using_default_dir_authorities(const or_options_t *options)
return (!options->DirAuthorities && !options->AlternateDirAuthority);
}
-/**
- * Attempt getting our non-local (as judged by tor_addr_is_internal()
- * function) IP address using following techniques, listed in
- * order from best (most desirable, try first) to worst (least
- * desirable, try if everything else fails).
- *
- * First, attempt using <b>options-\>Address</b> to get our
- * non-local IP address.
- *
- * If <b>options-\>Address</b> represents a non-local IP address,
- * consider it ours.
- *
- * If <b>options-\>Address</b> is a DNS name that resolves to
- * a non-local IP address, consider this IP address ours.
- *
- * If <b>options-\>Address</b> is NULL, fall back to getting local
- * hostname and using it in above-described ways to try and
- * get our IP address.
- *
- * In case local hostname cannot be resolved to a non-local IP
- * address, try getting an IP address of network interface
- * in hopes it will be non-local one.
- *
- * Fail if one or more of the following is true:
- * - DNS name in <b>options-\>Address</b> cannot be resolved.
- * - <b>options-\>Address</b> is a local host address.
- * - Attempt at getting local hostname fails.
- * - Attempt at getting network interface address fails.
- *
- * Return 0 if all is well, or -1 if we can't find a suitable
- * public IP address.
- *
- * If we are returning 0:
- * - Put our public IP address (in host order) into *<b>addr_out</b>.
- * - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
- * string describing how we arrived at our answer.
- * - "CONFIGURED" - parsed from IP address string in
- * <b>options-\>Address</b>
- * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
- * - "GETHOSTNAME" - resolved from a local hostname.
- * - "INTERFACE" - retrieved from a network interface.
- * - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
- * get our address, set *<b>hostname_out</b> to a newly allocated string
- * holding that hostname. (If we didn't get our address by resolving a
- * hostname, set *<b>hostname_out</b> to NULL.)
- *
- * XXXX ipv6
- */
-int
-resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out)
-{
- struct in_addr in;
- uint32_t addr; /* host order */
- char hostname[256];
- const char *method_used;
- const char *hostname_used;
- int explicit_ip=1;
- int explicit_hostname=1;
- int from_interface=0;
- char *addr_string = NULL;
- const char *address = options->Address;
- int notice_severity = warn_severity <= LOG_NOTICE ?
- LOG_NOTICE : warn_severity;
-
- tor_addr_t myaddr;
- tor_assert(addr_out);
-
- /*
- * Step one: Fill in 'hostname' to be our best guess.
- */
-
- if (address && *address) {
- strlcpy(hostname, address, sizeof(hostname));
- } else { /* then we need to guess our address */
- explicit_ip = 0; /* it's implicit */
- explicit_hostname = 0; /* it's implicit */
-
- if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
- log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
- return -1;
- }
- log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname);
- }
-
- /*
- * Step two: Now that we know 'hostname', parse it or resolve it. If
- * it doesn't parse or resolve, look at the interface address. Set 'addr'
- * to be our (host-order) 32-bit answer.
- */
-
- if (tor_inet_aton(hostname, &in) == 0) {
- /* then we have to resolve it */
- explicit_ip = 0;
- if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */
- uint32_t interface_ip; /* host order */
-
- if (explicit_hostname) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not resolve local Address '%s'. Failing.", hostname);
- return -1;
- }
- log_fn(notice_severity, LD_CONFIG,
- "Could not resolve guessed local hostname '%s'. "
- "Trying something else.", hostname);
- if (get_interface_address(warn_severity, &interface_ip)) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not get local interface IP address. Failing.");
- return -1;
- }
- from_interface = 1;
- addr = interface_ip;
- log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
- "local interface. Using that.", fmt_addr32(addr));
- strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
- } else { /* resolved hostname into addr */
- tor_addr_from_ipv4h(&myaddr, addr);
-
- if (!explicit_hostname &&
- tor_addr_is_internal(&myaddr, 0)) {
- tor_addr_t interface_ip;
-
- log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
- "resolves to a private IP address (%s). Trying something "
- "else.", hostname, fmt_addr32(addr));
-
- if (get_interface_address6(warn_severity, AF_INET, &interface_ip)<0) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not get local interface IP address. Too bad.");
- } else if (tor_addr_is_internal(&interface_ip, 0)) {
- log_fn(notice_severity, LD_CONFIG,
- "Interface IP address '%s' is a private address too. "
- "Ignoring.", fmt_addr(&interface_ip));
- } else {
- from_interface = 1;
- addr = tor_addr_to_ipv4h(&interface_ip);
- log_fn(notice_severity, LD_CONFIG,
- "Learned IP address '%s' for local interface."
- " Using that.", fmt_addr32(addr));
- strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
- }
- }
- }
- } else {
- addr = ntohl(in.s_addr); /* set addr so that addr_string is not
- * illformed */
- }
-
- /*
- * Step three: Check whether 'addr' is an internal IP address, and error
- * out if it is and we don't want that.
- */
-
- tor_addr_from_ipv4h(&myaddr,addr);
-
- addr_string = tor_dup_ip(addr);
- if (tor_addr_is_internal(&myaddr, 0)) {
- /* make sure we're ok with publishing an internal IP */
- if (using_default_dir_authorities(options)) {
- /* if they are using the default authorities, disallow internal IPs
- * always. */
- log_fn(warn_severity, LD_CONFIG,
- "Address '%s' resolves to private IP address '%s'. "
- "Tor servers that use the default DirAuthorities must have "
- "public IP addresses.", hostname, addr_string);
- tor_free(addr_string);
- return -1;
- }
- if (!explicit_ip) {
- /* even if they've set their own authorities, require an explicit IP if
- * they're using an internal address. */
- log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
- "IP address '%s'. Please set the Address config option to be "
- "the IP address you want to use.", hostname, addr_string);
- tor_free(addr_string);
- return -1;
- }
- }
-
- /*
- * Step four: We have a winner! 'addr' is our answer for sure, and
- * 'addr_string' is its string form. Fill out the various fields to
- * say how we decided it.
- */
-
- log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string);
-
- if (explicit_ip) {
- method_used = "CONFIGURED";
- hostname_used = NULL;
- } else if (explicit_hostname) {
- method_used = "RESOLVED";
- hostname_used = hostname;
- } else if (from_interface) {
- method_used = "INTERFACE";
- hostname_used = NULL;
- } else {
- method_used = "GETHOSTNAME";
- hostname_used = hostname;
- }
-
- *addr_out = addr;
- if (method_out)
- *method_out = method_used;
- if (hostname_out)
- *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
-
- /*
- * Step five: Check if the answer has changed since last time (or if
- * there was no last time), and if so call various functions to keep
- * us up-to-date.
- */
-
- if (last_resolved_addr && last_resolved_addr != *addr_out) {
- /* Leave this as a notice, regardless of the requested severity,
- * at least until dynamic IP address support becomes bulletproof. */
- log_notice(LD_NET,
- "Your IP address seems to have changed to %s "
- "(METHOD=%s%s%s). Updating.",
- addr_string, method_used,
- hostname_used ? " HOSTNAME=" : "",
- hostname_used ? hostname_used : "");
- ip_address_changed(0);
- }
-
- if (last_resolved_addr != *addr_out) {
- control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
- addr_string, method_used,
- hostname_used ? " HOSTNAME=" : "",
- hostname_used ? hostname_used : "");
- }
- last_resolved_addr = *addr_out;
-
- /*
- * And finally, clean up and return success.
- */
-
- tor_free(addr_string);
- return 0;
-}
-
-/** Return true iff <b>addr</b> is judged to be on the same network as us, or
- * on a private network.
- */
-MOCK_IMPL(int,
-is_local_addr, (const tor_addr_t *addr))
-{
- if (tor_addr_is_internal(addr, 0))
- return 1;
- /* Check whether ip is on the same /24 as we are. */
- if (get_options()->EnforceDistinctSubnets == 0)
- return 0;
- if (tor_addr_family(addr) == AF_INET) {
- uint32_t ip = tor_addr_to_ipv4h(addr);
-
- /* It's possible that this next check will hit before the first time
- * resolve_my_address actually succeeds. (For clients, it is likely that
- * resolve_my_address will never be called at all). In those cases,
- * last_resolved_addr will be 0, and so checking to see whether ip is on
- * the same /24 as last_resolved_addr will be the same as checking whether
- * it was on net 0, which is already done by tor_addr_is_internal.
- */
- if ((last_resolved_addr & (uint32_t)0xffffff00ul)
- == (ip & (uint32_t)0xffffff00ul))
- return 1;
- }
- return 0;
-}
-
/** Return a new empty or_options_t. Used for testing. */
or_options_t *
options_new(void)
{
- return config_new(get_options_mgr());
+ or_options_t *options = config_new(get_options_mgr());
+ options->command = CMD_RUN_TOR;
+ return options;
}
/** Set <b>options</b> to hold reasonable defaults for most options.
@@ -3085,8 +2814,8 @@ validate_ports_csv(smartlist_t *sl, const char *name, char **msg)
* a complaint into *<b>msg</b> using string <b>desc</b>, and return -1.
* Else return 0.
*/
-static int
-ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg)
+int
+config_ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg)
{
if (*value > ROUTER_MAX_DECLARED_BANDWIDTH) {
/* This handles an understandable special case where somebody says "2gb"
@@ -3102,48 +2831,6 @@ ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg)
return 0;
}
-/** Parse an authority type from <b>options</b>-\>PublishServerDescriptor
- * and write it to <b>options</b>-\>PublishServerDescriptor_. Treat "1"
- * as "v3" unless BridgeRelay is 1, in which case treat it as "bridge".
- * Treat "0" as "".
- * Return 0 on success or -1 if not a recognized authority type (in which
- * case the value of PublishServerDescriptor_ is undefined). */
-static int
-compute_publishserverdescriptor(or_options_t *options)
-{
- smartlist_t *list = options->PublishServerDescriptor;
- dirinfo_type_t *auth = &options->PublishServerDescriptor_;
- *auth = NO_DIRINFO;
- if (!list) /* empty list, answer is none */
- return 0;
- SMARTLIST_FOREACH_BEGIN(list, const char *, string) {
- if (!strcasecmp(string, "v1"))
- log_warn(LD_CONFIG, "PublishServerDescriptor v1 has no effect, because "
- "there are no v1 directory authorities anymore.");
- else if (!strcmp(string, "1"))
- if (options->BridgeRelay)
- *auth |= BRIDGE_DIRINFO;
- else
- *auth |= V3_DIRINFO;
- else if (!strcasecmp(string, "v2"))
- log_warn(LD_CONFIG, "PublishServerDescriptor v2 has no effect, because "
- "there are no v2 directory authorities anymore.");
- else if (!strcasecmp(string, "v3"))
- *auth |= V3_DIRINFO;
- else if (!strcasecmp(string, "bridge"))
- *auth |= BRIDGE_DIRINFO;
- else if (!strcasecmp(string, "hidserv"))
- log_warn(LD_CONFIG,
- "PublishServerDescriptor hidserv is invalid. See "
- "PublishHidServDescriptors.");
- else if (!strcasecmp(string, "") || !strcmp(string, "0"))
- /* no authority */;
- else
- return -1;
- } SMARTLIST_FOREACH_END(string);
- return 0;
-}
-
/** Lowest allowable value for RendPostPeriod; if this is too low, hidden
* services can overload the directory system. */
#define MIN_REND_POST_PERIOD (10*60)
@@ -3176,17 +2863,68 @@ compute_publishserverdescriptor(or_options_t *options)
* */
#define RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT (10)
-static int
-options_validate_cb(void *old_options, void *options, void *default_options,
- int from_setconf, char **msg)
+/**
+ * Validate <b>new_options</b>. If it is valid, and it is a reasonable
+ * replacement for <b>old_options</b>, replace the previous value of the
+ * global options, and return return SETOPT_OK.
+ *
+ * If it is not valid, then free <b>new_options</b>, set *<b>msg_out</b> to a
+ * newly allocated error message, and return an error code.
+ */
+static setopt_err_t
+options_validate_and_set(const or_options_t *old_options,
+ or_options_t *new_options,
+ char **msg_out)
{
+ setopt_err_t rv;
+ validation_status_t vs;
+
in_option_validation = 1;
- int rv = options_validate(old_options, options, default_options,
- from_setconf, msg);
+ vs = config_validate(get_options_mgr(), old_options, new_options, msg_out);
+
+ if (vs == VSTAT_TRANSITION_ERR) {
+ rv = SETOPT_ERR_TRANSITION;
+ goto err;
+ } else if (vs < 0) {
+ rv = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ in_option_validation = 0;
+
+ if (set_options(new_options, msg_out)) {
+ rv = SETOPT_ERR_SETTING;
+ goto err;
+ }
+
+ rv = SETOPT_OK;
+ new_options = NULL; /* prevent free */
+ err:
in_option_validation = 0;
+ tor_assert(new_options == NULL || rv != SETOPT_OK);
+ or_options_free(new_options);
return rv;
}
+#ifdef TOR_UNIT_TESTS
+/**
+ * Return 0 if every setting in <b>options</b> is reasonable, is a
+ * permissible transition from <b>old_options</b>, and none of the
+ * testing-only settings differ from <b>default_options</b> unless in
+ * testing mode. Else return -1. Should have no side effects, except for
+ * normalizing the contents of <b>options</b>.
+ *
+ * On error, tor_strdup an error explanation into *<b>msg</b>.
+ */
+int
+options_validate(const or_options_t *old_options, or_options_t *options,
+ char **msg)
+{
+ validation_status_t vs;
+ vs = config_validate(get_options_mgr(), old_options, options, msg);
+ return vs < 0 ? -1 : 0;
+}
+#endif /* defined(TOR_UNIT_TESTS) */
+
#define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
#if defined(__GNUC__) && __GNUC__ <= 3
@@ -3207,7 +2945,7 @@ options_validate_cb(void *old_options, void *options, void *default_options,
*/
static int
warn_if_option_path_is_relative(const char *option,
- char *filepath)
+ const char *filepath)
{
if (filepath && path_is_relative(filepath)) {
char *abs_path = make_path_absolute(filepath);
@@ -3220,34 +2958,29 @@ warn_if_option_path_is_relative(const char *option,
}
/** Scan <b>options</b> for occurrences of relative file/directory
- * path and log a warning whenever it is found.
+ * paths and log a warning whenever one is found.
*
* Return 1 if there were relative paths; 0 otherwise.
*/
static int
-warn_about_relative_paths(or_options_t *options)
+warn_about_relative_paths(const or_options_t *options)
{
tor_assert(options);
int n = 0;
+ const config_mgr_t *mgr = get_options_mgr();
- n += warn_if_option_path_is_relative("CookieAuthFile",
- options->CookieAuthFile);
- n += warn_if_option_path_is_relative("ExtORPortCookieAuthFile",
- options->ExtORPortCookieAuthFile);
- n += warn_if_option_path_is_relative("DirPortFrontPage",
- options->DirPortFrontPage);
- n += warn_if_option_path_is_relative("V3BandwidthsFile",
- options->V3BandwidthsFile);
- n += warn_if_option_path_is_relative("ControlPortWriteToFile",
- options->ControlPortWriteToFile);
- n += warn_if_option_path_is_relative("GeoIPFile",options->GeoIPFile);
- n += warn_if_option_path_is_relative("GeoIPv6File",options->GeoIPv6File);
- n += warn_if_option_path_is_relative("Log",options->DebugLogFile);
- n += warn_if_option_path_is_relative("AccelDir",options->AccelDir);
- n += warn_if_option_path_is_relative("DataDirectory",options->DataDirectory);
- n += warn_if_option_path_is_relative("PidFile",options->PidFile);
- n += warn_if_option_path_is_relative("ClientOnionAuthDir",
- options->ClientOnionAuthDir);
+ smartlist_t *vars = config_mgr_list_vars(mgr);
+ SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, cv) {
+ config_line_t *line;
+ if (cv->member.type != CONFIG_TYPE_FILENAME)
+ continue;
+ const char *name = cv->member.name;
+ line = config_get_assigned_option(mgr, options, name, 0);
+ if (line)
+ n += warn_if_option_path_is_relative(name, line->value);
+ config_free_lines(line);
+ } SMARTLIST_FOREACH_END(cv);
+ smartlist_free(vars);
for (config_line_t *hs_line = options->RendConfigLines; hs_line;
hs_line = hs_line->next) {
@@ -3274,6 +3007,10 @@ options_validate_scheduler(or_options_t *options, char **msg)
"can be used or set at least one value.");
}
/* Ok, we do have scheduler types, validate them. */
+ if (options->SchedulerTypes_) {
+ SMARTLIST_FOREACH(options->SchedulerTypes_, int *, iptr, tor_free(iptr));
+ smartlist_free(options->SchedulerTypes_);
+ }
options->SchedulerTypes_ = smartlist_new();
SMARTLIST_FOREACH_BEGIN(options->Schedulers, const char *, type) {
int *sched_type;
@@ -3366,25 +3103,20 @@ options_validate_single_onion(or_options_t *options, char **msg)
return 0;
}
-/** Return 0 if every setting in <b>options</b> is reasonable, is a
- * permissible transition from <b>old_options</b>, and none of the
- * testing-only settings differ from <b>default_options</b> unless in
- * testing mode. Else return -1. Should have no side effects, except for
- * normalizing the contents of <b>options</b>.
- *
- * On error, tor_strdup an error explanation into *<b>msg</b>.
- *
- * XXX
- * If <b>from_setconf</b>, we were called by the controller, and our
- * Log line should stay empty. If it's 0, then give us a default log
- * if there are no logs defined.
+/**
+ * Legacy validation/normalization callback for or_options_t. See
+ * legacy_validate_fn_t for more information.
*/
-STATIC int
-options_validate(or_options_t *old_options, or_options_t *options,
- or_options_t *default_options, int from_setconf, char **msg)
+static int
+options_validate_cb(const void *old_options_, void *options_, char **msg)
{
+ if (old_options_)
+ CHECK_OPTIONS_MAGIC(old_options_);
+ CHECK_OPTIONS_MAGIC(options_);
+ const or_options_t *old_options = old_options_;
+ or_options_t *options = options_;
+
config_line_t *cl;
- const char *uname = get_uname();
int n_ports=0;
int world_writable_control_socket=0;
@@ -3395,22 +3127,30 @@ options_validate(or_options_t *old_options, or_options_t *options,
&world_writable_control_socket) < 0)
return -1;
+#ifndef HAVE_SYS_UN_H
+ if (options->ControlSocket || options->ControlSocketsGroupWritable) {
+ *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported "
+ "on this OS/with this build.");
+ return -1;
+ }
+#else /* defined(HAVE_SYS_UN_H) */
+ if (options->ControlSocketsGroupWritable && !options->ControlSocket) {
+ *msg = tor_strdup("Setting ControlSocketGroupWritable without setting "
+ "a ControlSocket makes no sense.");
+ return -1;
+ }
+#endif /* !defined(HAVE_SYS_UN_H) */
+
/* Set UseEntryGuards from the configured value, before we check it below.
* We change UseEntryGuards when it's incompatible with other options,
* but leave UseEntryGuards_option with the original value.
* Always use the value of UseEntryGuards, not UseEntryGuards_option. */
options->UseEntryGuards = options->UseEntryGuards_option;
- if (server_mode(options) &&
- (!strcmpstart(uname, "Windows 95") ||
- !strcmpstart(uname, "Windows 98") ||
- !strcmpstart(uname, "Windows Me"))) {
- log_warn(LD_CONFIG, "Tor is running as a server, but you are "
- "running %s; this probably won't work. See "
- "https://www.torproject.org/docs/faq.html#BestOSForRelay "
- "for details.", uname);
- }
+ if (options_validate_relay_os(old_options, options, msg) < 0)
+ return -1;
+ /* 31851: OutboundBindAddressExit is unused in client mode */
if (parse_outbound_addresses(options, 1, msg) < 0)
return -1;
@@ -3425,61 +3165,16 @@ options_validate(or_options_t *old_options, or_options_t *options,
"with relative paths.");
}
- if (options->Nickname == NULL) {
- if (server_mode(options)) {
- options->Nickname = tor_strdup(UNNAMED_ROUTER_NICKNAME);
- }
- } else {
- if (!is_legal_nickname(options->Nickname)) {
- tor_asprintf(msg,
- "Nickname '%s', nicknames must be between 1 and 19 characters "
- "inclusive, and must contain only the characters [a-zA-Z0-9].",
- options->Nickname);
- return -1;
- }
- }
-
- if (server_mode(options) && !options->ContactInfo) {
- log_warn(LD_CONFIG,
- "Your ContactInfo config option is not set. Please strongly "
- "consider setting it, so we can contact you if your relay is "
- "misconfigured, end-of-life, or something else goes wrong. "
- "It is also possible that your relay might get rejected from "
- "the network due to a missing valid contact address.");
- }
-
- const char *ContactInfo = options->ContactInfo;
- if (ContactInfo && !string_is_utf8(ContactInfo, strlen(ContactInfo)))
- REJECT("ContactInfo config option must be UTF-8.");
+ if (options_validate_relay_info(old_options, options, msg) < 0)
+ return -1;
+ /* 31851: this function is currently a no-op in client mode */
check_network_configuration(server_mode(options));
- /* Special case on first boot if no Log options are given. */
- if (!options->Logs && !options->RunAsDaemon && !from_setconf) {
- if (quiet_level == 0)
- config_line_append(&options->Logs, "Log", "notice stdout");
- else if (quiet_level == 1)
- config_line_append(&options->Logs, "Log", "warn stdout");
- }
-
/* Validate the tor_log(s) */
if (options_init_logs(old_options, options, 1)<0)
REJECT("Failed to validate Log options. See logs for details.");
- if (authdir_mode(options)) {
- /* confirm that our address isn't broken, so we can complain now */
- uint32_t tmp;
- if (resolve_my_address(LOG_WARN, options, &tmp, NULL, NULL) < 0)
- REJECT("Failed to resolve/guess local address. See logs for details.");
- }
-
- if (server_mode(options) && options->RendConfigLines)
- log_warn(LD_CONFIG,
- "Tor is currently configured as a relay and a hidden service. "
- "That's not very secure: you should probably run your hidden service "
- "in a separate Tor process, at least -- see "
- "https://trac.torproject.org/8742");
-
/* XXXX require that the only port not be DirPort? */
/* XXXX require that at least one port be listened-upon. */
if (n_ports == 0 && !options->RendConfigLines)
@@ -3494,13 +3189,13 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (!strcasecmp(options->TransProxyType, "default")) {
options->TransProxyType_parsed = TPT_DEFAULT;
} else if (!strcasecmp(options->TransProxyType, "pf-divert")) {
-#if !defined(OpenBSD) && !defined( DARWIN )
+#if !defined(OpenBSD) && !defined(DARWIN)
/* Later versions of OS X have pf */
REJECT("pf-divert is a OpenBSD-specific "
"and OS X/Darwin-specific feature.");
#else
options->TransProxyType_parsed = TPT_PF_DIVERT;
-#endif /* !defined(OpenBSD) && !defined( DARWIN ) */
+#endif /* !defined(OpenBSD) && !defined(DARWIN) */
} else if (!strcasecmp(options->TransProxyType, "tproxy")) {
#if !defined(__linux__)
REJECT("TPROXY is a Linux-specific feature.");
@@ -3558,65 +3253,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
"features to be broken in unpredictable ways.");
}
- if (options->AuthoritativeDir) {
- if (!options->ContactInfo && !options->TestingTorNetwork)
- REJECT("Authoritative directory servers must set ContactInfo");
- if (!options->RecommendedClientVersions)
- options->RecommendedClientVersions =
- config_lines_dup(options->RecommendedVersions);
- if (!options->RecommendedServerVersions)
- options->RecommendedServerVersions =
- config_lines_dup(options->RecommendedVersions);
- if (options->VersioningAuthoritativeDir &&
- (!options->RecommendedClientVersions ||
- !options->RecommendedServerVersions))
- REJECT("Versioning authoritative dir servers must set "
- "Recommended*Versions.");
-
-#ifdef HAVE_MODULE_DIRAUTH
- char *t;
- /* Call these functions to produce warnings only. */
- t = format_recommended_version_list(options->RecommendedClientVersions, 1);
- tor_free(t);
- t = format_recommended_version_list(options->RecommendedServerVersions, 1);
- tor_free(t);
-#endif /* defined(HAVE_MODULE_DIRAUTH) */
-
- if (options->UseEntryGuards) {
- log_info(LD_CONFIG, "Authoritative directory servers can't set "
- "UseEntryGuards. Disabling.");
- options->UseEntryGuards = 0;
- }
- if (!options->DownloadExtraInfo && authdir_mode_v3(options)) {
- log_info(LD_CONFIG, "Authoritative directories always try to download "
- "extra-info documents. Setting DownloadExtraInfo.");
- options->DownloadExtraInfo = 1;
- }
- if (!(options->BridgeAuthoritativeDir ||
- options->V3AuthoritativeDir))
- REJECT("AuthoritativeDir is set, but none of "
- "(Bridge/V3)AuthoritativeDir is set.");
-#ifdef HAVE_MODULE_DIRAUTH
- /* If we have a v3bandwidthsfile and it's broken, complain on startup */
- if (options->V3BandwidthsFile && !old_options) {
- dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL,
- NULL);
- }
- /* same for guardfraction file */
- if (options->GuardfractionFile && !old_options) {
- dirserv_read_guardfraction_file(options->GuardfractionFile, NULL);
- }
-#endif /* defined(HAVE_MODULE_DIRAUTH) */
- }
-
- if (options->AuthoritativeDir && !options->DirPort_set)
- REJECT("Running as authoritative directory, but no DirPort set.");
-
- if (options->AuthoritativeDir && !options->ORPort_set)
- REJECT("Running as authoritative directory, but no ORPort set.");
-
- if (options->AuthoritativeDir && options->ClientOnly)
- REJECT("Running as authoritative directory, but ClientOnly also set.");
+ if (options_validate_dirauth_mode(old_options, options, msg) < 0)
+ return -1;
if (options->FetchDirInfoExtraEarly && !options->FetchDirInfoEarly)
REJECT("FetchDirInfoExtraEarly requires that you also set "
@@ -3755,57 +3393,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
return -1;
}
- if (compute_publishserverdescriptor(options) < 0) {
- tor_asprintf(msg, "Unrecognized value in PublishServerDescriptor");
+ if (options_validate_publish_server(old_options, options, msg) < 0)
return -1;
- }
-
- if ((options->BridgeRelay
- || options->PublishServerDescriptor_ & BRIDGE_DIRINFO)
- && (options->PublishServerDescriptor_ & V3_DIRINFO)) {
- REJECT("Bridges are not supposed to publish router descriptors to the "
- "directory authorities. Please correct your "
- "PublishServerDescriptor line.");
- }
-
- if (options->BridgeRelay && options->DirPort_set) {
- log_warn(LD_CONFIG, "Can't set a DirPort on a bridge relay; disabling "
- "DirPort");
- config_free_lines(options->DirPort_lines);
- options->DirPort_lines = NULL;
- options->DirPort_set = 0;
- }
-
- if (server_mode(options) && options->ConnectionPadding != -1) {
- REJECT("Relays must use 'auto' for the ConnectionPadding setting.");
- }
-
- if (server_mode(options) && options->ReducedConnectionPadding != 0) {
- REJECT("Relays cannot set ReducedConnectionPadding. ");
- }
-
- if (server_mode(options) && options->CircuitPadding == 0) {
- REJECT("Relays cannot set CircuitPadding to 0. ");
- }
- if (server_mode(options) && options->ReducedCircuitPadding == 1) {
- REJECT("Relays cannot set ReducedCircuitPadding. ");
- }
-
- if (options->BridgeDistribution) {
- if (!options->BridgeRelay) {
- REJECT("You set BridgeDistribution, but you didn't set BridgeRelay!");
- }
- if (check_bridge_distribution_setting(options->BridgeDistribution) < 0) {
- REJECT("Invalid BridgeDistribution value.");
- }
- }
-
- if (options->MinUptimeHidServDirectoryV2 < 0) {
- log_warn(LD_CONFIG, "MinUptimeHidServDirectoryV2 option must be at "
- "least 0 seconds. Changing to 0.");
- options->MinUptimeHidServDirectoryV2 = 0;
- }
+ if (options_validate_relay_padding(old_options, options, msg) < 0)
+ return -1;
const int min_rendpostperiod =
options->TestingTorNetwork ?
@@ -3844,7 +3436,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
"UseEntryGuards is disabled, but you have configured one or more "
"hidden services on this Tor instance. Your hidden services "
"will be very easy to locate using a well-known attack -- see "
- "http://freehaven.net/anonbib/#hs-attack06 for details.");
+ "https://freehaven.net/anonbib/#hs-attack06 for details.");
}
if (options->NumPrimaryGuards && options->NumEntryGuards &&
@@ -3979,134 +3571,24 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->KeepalivePeriod < 1)
REJECT("KeepalivePeriod option must be positive.");
- if (ensure_bandwidth_cap(&options->BandwidthRate,
+ if (config_ensure_bandwidth_cap(&options->BandwidthRate,
"BandwidthRate", msg) < 0)
return -1;
- if (ensure_bandwidth_cap(&options->BandwidthBurst,
+ if (config_ensure_bandwidth_cap(&options->BandwidthBurst,
"BandwidthBurst", msg) < 0)
return -1;
- if (ensure_bandwidth_cap(&options->MaxAdvertisedBandwidth,
- "MaxAdvertisedBandwidth", msg) < 0)
- return -1;
- if (ensure_bandwidth_cap(&options->RelayBandwidthRate,
- "RelayBandwidthRate", msg) < 0)
- return -1;
- if (ensure_bandwidth_cap(&options->RelayBandwidthBurst,
- "RelayBandwidthBurst", msg) < 0)
- return -1;
- if (ensure_bandwidth_cap(&options->PerConnBWRate,
- "PerConnBWRate", msg) < 0)
- return -1;
- if (ensure_bandwidth_cap(&options->PerConnBWBurst,
- "PerConnBWBurst", msg) < 0)
- return -1;
- if (ensure_bandwidth_cap(&options->AuthDirFastGuarantee,
- "AuthDirFastGuarantee", msg) < 0)
- return -1;
- if (ensure_bandwidth_cap(&options->AuthDirGuardBWGuarantee,
- "AuthDirGuardBWGuarantee", msg) < 0)
- return -1;
- if (options->RelayBandwidthRate && !options->RelayBandwidthBurst)
- options->RelayBandwidthBurst = options->RelayBandwidthRate;
- if (options->RelayBandwidthBurst && !options->RelayBandwidthRate)
- options->RelayBandwidthRate = options->RelayBandwidthBurst;
-
- if (server_mode(options)) {
- const unsigned required_min_bw =
- public_server_mode(options) ?
- RELAY_REQUIRED_MIN_BANDWIDTH : BRIDGE_REQUIRED_MIN_BANDWIDTH;
- const char * const optbridge =
- public_server_mode(options) ? "" : "bridge ";
- if (options->BandwidthRate < required_min_bw) {
- tor_asprintf(msg,
- "BandwidthRate is set to %d bytes/second. "
- "For %sservers, it must be at least %u.",
- (int)options->BandwidthRate, optbridge,
- required_min_bw);
- return -1;
- } else if (options->MaxAdvertisedBandwidth <
- required_min_bw/2) {
- tor_asprintf(msg,
- "MaxAdvertisedBandwidth is set to %d bytes/second. "
- "For %sservers, it must be at least %u.",
- (int)options->MaxAdvertisedBandwidth, optbridge,
- required_min_bw/2);
- return -1;
- }
- if (options->RelayBandwidthRate &&
- options->RelayBandwidthRate < required_min_bw) {
- tor_asprintf(msg,
- "RelayBandwidthRate is set to %d bytes/second. "
- "For %sservers, it must be at least %u.",
- (int)options->RelayBandwidthRate, optbridge,
- required_min_bw);
- return -1;
- }
- }
-
- if (options->RelayBandwidthRate > options->RelayBandwidthBurst)
- REJECT("RelayBandwidthBurst must be at least equal "
- "to RelayBandwidthRate.");
+ if (options_validate_relay_bandwidth(old_options, options, msg) < 0)
+ return -1;
if (options->BandwidthRate > options->BandwidthBurst)
REJECT("BandwidthBurst must be at least equal to BandwidthRate.");
- /* if they set relaybandwidth* really high but left bandwidth*
- * at the default, raise the defaults. */
- if (options->RelayBandwidthRate > options->BandwidthRate)
- options->BandwidthRate = options->RelayBandwidthRate;
- if (options->RelayBandwidthBurst > options->BandwidthBurst)
- options->BandwidthBurst = options->RelayBandwidthBurst;
-
- if (accounting_parse_options(options, 1)<0)
- REJECT("Failed to parse accounting options. See logs for details.");
-
- if (options->AccountingMax) {
- if (options->RendConfigLines && server_mode(options)) {
- log_warn(LD_CONFIG, "Using accounting with a hidden service and an "
- "ORPort is risky: your hidden service(s) and your public "
- "address will all turn off at the same time, which may alert "
- "observers that they are being run by the same party.");
- } else if (config_count_key(options->RendConfigLines,
- "HiddenServiceDir") > 1) {
- log_warn(LD_CONFIG, "Using accounting with multiple hidden services is "
- "risky: they will all turn off at the same time, which may "
- "alert observers that they are being run by the same party.");
- }
- }
-
- options->AccountingRule = ACCT_MAX;
- if (options->AccountingRule_option) {
- if (!strcmp(options->AccountingRule_option, "sum"))
- options->AccountingRule = ACCT_SUM;
- else if (!strcmp(options->AccountingRule_option, "max"))
- options->AccountingRule = ACCT_MAX;
- else if (!strcmp(options->AccountingRule_option, "in"))
- options->AccountingRule = ACCT_IN;
- else if (!strcmp(options->AccountingRule_option, "out"))
- options->AccountingRule = ACCT_OUT;
- else
- REJECT("AccountingRule must be 'sum', 'max', 'in', or 'out'");
- }
-
- if (options->DirPort_set && !options->DirCache) {
- REJECT("DirPort configured but DirCache disabled. DirPort requires "
- "DirCache.");
- }
-
- if (options->BridgeRelay && !options->DirCache) {
- REJECT("We're a bridge but DirCache is disabled. BridgeRelay requires "
- "DirCache.");
- }
+ if (options_validate_relay_accounting(old_options, options, msg) < 0)
+ return -1;
- if (server_mode(options)) {
- char *dircache_msg = NULL;
- if (have_enough_mem_for_dircache(options, 0, &dircache_msg)) {
- log_warn(LD_CONFIG, "%s", dircache_msg);
- tor_free(dircache_msg);
- }
- }
+ if (options_validate_relay_mode(old_options, options, msg) < 0)
+ return -1;
if (options->HTTPProxy) { /* parse it now */
if (tor_addr_port_lookup(options->HTTPProxy,
@@ -4156,19 +3638,28 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
+ if (options->TCPProxy) {
+ int res = parse_tcp_proxy_line(options->TCPProxy, options, msg);
+ if (res < 0) {
+ return res;
+ }
+ }
+
/* Check if more than one exclusive proxy type has been enabled. */
if (!!options->Socks4Proxy + !!options->Socks5Proxy +
- !!options->HTTPSProxy > 1)
+ !!options->HTTPSProxy + !!options->TCPProxy > 1)
REJECT("You have configured more than one proxy type. "
- "(Socks4Proxy|Socks5Proxy|HTTPSProxy)");
+ "(Socks4Proxy|Socks5Proxy|HTTPSProxy|TCPProxy)");
/* Check if the proxies will give surprising behavior. */
if (options->HTTPProxy && !(options->Socks4Proxy ||
options->Socks5Proxy ||
- options->HTTPSProxy)) {
- log_warn(LD_CONFIG, "HTTPProxy configured, but no SOCKS proxy or "
- "HTTPS proxy configured. Watch out: this configuration will "
- "proxy unencrypted directory connections only.");
+ options->HTTPSProxy ||
+ options->TCPProxy)) {
+ log_warn(LD_CONFIG, "HTTPProxy configured, but no SOCKS proxy, "
+ "HTTPS proxy, or any other TCP proxy configured. Watch out: "
+ "this configuration will proxy unencrypted directory "
+ "connections only.");
}
if (options->Socks5ProxyUsername) {
@@ -4236,19 +3727,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
"have it group-readable.");
}
- if (options->MyFamily_lines && options->BridgeRelay) {
- log_warn(LD_CONFIG, "Listing a family for a bridge relay is not "
- "supported: it can reveal bridge fingerprints to censors. "
- "You should also make sure you aren't listing this bridge's "
- "fingerprint in any other MyFamily.");
- }
- if (options->MyFamily_lines && !options->ContactInfo) {
- log_warn(LD_CONFIG, "MyFamily is set but ContactInfo is not configured. "
- "ContactInfo should always be set when MyFamily option is too.");
- }
- if (normalize_nickname_list(&options->MyFamily,
- options->MyFamily_lines, "MyFamily", msg))
- return -1;
for (cl = options->NodeFamilies; cl; cl = cl->next) {
routerset_t *rs = routerset_new();
if (routerset_parse(rs, cl->value, cl->key)) {
@@ -4283,50 +3761,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
- if (parse_transport_line(options, cl->value, 1, 0) < 0)
+ if (pt_parse_transport_line(options, cl->value, 1, 0) < 0)
REJECT("Invalid client transport line. See logs for details.");
}
- for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
- if (parse_transport_line(options, cl->value, 1, 1) < 0)
- REJECT("Invalid server transport line. See logs for details.");
- }
-
- if (options->ServerTransportPlugin && !server_mode(options)) {
- log_notice(LD_GENERAL, "Tor is not configured as a relay but you specified"
- " a ServerTransportPlugin line (%s). The ServerTransportPlugin "
- "line will be ignored.",
- escaped(options->ServerTransportPlugin->value));
- }
-
- for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
- /** If get_bindaddr_from_transport_listen_line() fails with
- 'transport' being NULL, it means that something went wrong
- while parsing the ServerTransportListenAddr line. */
- char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL);
- if (!bindaddr)
- REJECT("ServerTransportListenAddr did not parse. See logs for details.");
- tor_free(bindaddr);
- }
-
- if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) {
- log_notice(LD_GENERAL, "You need at least a single managed-proxy to "
- "specify a transport listen address. The "
- "ServerTransportListenAddr line will be ignored.");
- }
-
- for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
- /** If get_options_from_transport_options_line() fails with
- 'transport' being NULL, it means that something went wrong
- while parsing the ServerTransportOptions line. */
- smartlist_t *options_sl =
- get_options_from_transport_options_line(cl->value, NULL);
- if (!options_sl)
- REJECT("ServerTransportOptions did not parse. See logs for details.");
-
- SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp));
- smartlist_free(options_sl);
- }
+ if (options_validate_server_transport(old_options, options, msg) < 0)
+ return -1;
if (options->ConstrainedSockets) {
/* If the user wants to constrain socket buffer use, make sure the desired
@@ -4340,85 +3780,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
MIN_CONSTRAINED_TCP_BUFFER, MAX_CONSTRAINED_TCP_BUFFER);
return -1;
}
- if (options->DirPort_set) {
- /* Providing cached directory entries while system TCP buffers are scarce
- * will exacerbate the socket errors. Suggest that this be disabled. */
- COMPLAIN("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.");
- }
- }
-
- if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
- options->V3AuthVotingInterval/2) {
- /*
- This doesn't work, but it seems like it should:
- what code is preventing the interval being less than twice the lead-up?
- if (options->TestingTorNetwork) {
- if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
- options->V3AuthVotingInterval) {
- REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than "
- "V3AuthVotingInterval");
- } else {
- COMPLAIN("V3AuthVoteDelay plus V3AuthDistDelay is more than half "
- "V3AuthVotingInterval. This may lead to "
- "consensus instability, particularly if clocks drift.");
- }
- } else {
- */
- REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
- "V3AuthVotingInterval");
- /*
- }
- */
- }
-
- if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) {
- if (options->TestingTorNetwork) {
- if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS_TESTING) {
- REJECT("V3AuthVoteDelay is way too low.");
- } else {
- COMPLAIN("V3AuthVoteDelay is very low. "
- "This may lead to failure to vote for a consensus.");
- }
- } else {
- REJECT("V3AuthVoteDelay is way too low.");
- }
}
- if (options->V3AuthDistDelay < MIN_DIST_SECONDS) {
- if (options->TestingTorNetwork) {
- if (options->V3AuthDistDelay < MIN_DIST_SECONDS_TESTING) {
- REJECT("V3AuthDistDelay is way too low.");
- } else {
- COMPLAIN("V3AuthDistDelay is very low. "
- "This may lead to missing votes in a consensus.");
- }
- } else {
- REJECT("V3AuthDistDelay is way too low.");
- }
- }
-
- if (options->V3AuthNIntervalsValid < 2)
- REJECT("V3AuthNIntervalsValid must be at least 2.");
-
- if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) {
- if (options->TestingTorNetwork) {
- if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL_TESTING) {
- REJECT("V3AuthVotingInterval is insanely low.");
- } else {
- COMPLAIN("V3AuthVotingInterval is very low. "
- "This may lead to failure to synchronise for a consensus.");
- }
- } else {
- REJECT("V3AuthVotingInterval is insanely low.");
- }
- } else if (options->V3AuthVotingInterval > 24*60*60) {
- REJECT("V3AuthVotingInterval is insanely high.");
- } else if (((24*60*60) % options->V3AuthVotingInterval) != 0) {
- COMPLAIN("V3AuthVotingInterval does not divide evenly into 24 hours.");
- }
+ if (options_validate_dirauth_schedule(old_options, options, msg) < 0)
+ return -1;
if (hs_config_service_all(options, 1) < 0)
REJECT("Failed to configure rendezvous options. See logs for details.");
@@ -4446,88 +3811,51 @@ options_validate(or_options_t *old_options, or_options_t *options,
#define CHECK_DEFAULT(arg) \
STMT_BEGIN \
- if (!options->TestingTorNetwork && \
- !options->UsingTestNetworkDefaults_ && \
- !config_is_same(get_options_mgr(),options, \
- default_options,#arg)) { \
+ if (!config_is_same(get_options_mgr(),options, \
+ dflt_options,#arg)) { \
+ or_options_free(dflt_options); \
REJECT(#arg " may only be changed in testing Tor " \
"networks!"); \
- } STMT_END
- CHECK_DEFAULT(TestingV3AuthInitialVotingInterval);
- CHECK_DEFAULT(TestingV3AuthInitialVoteDelay);
- CHECK_DEFAULT(TestingV3AuthInitialDistDelay);
- CHECK_DEFAULT(TestingV3AuthVotingStartOffset);
- CHECK_DEFAULT(TestingAuthDirTimeToLearnReachability);
- CHECK_DEFAULT(TestingEstimatedDescriptorPropagationTime);
- CHECK_DEFAULT(TestingServerDownloadInitialDelay);
- CHECK_DEFAULT(TestingClientDownloadInitialDelay);
- CHECK_DEFAULT(TestingServerConsensusDownloadInitialDelay);
- CHECK_DEFAULT(TestingClientConsensusDownloadInitialDelay);
- CHECK_DEFAULT(TestingBridgeDownloadInitialDelay);
- CHECK_DEFAULT(TestingBridgeBootstrapDownloadInitialDelay);
- CHECK_DEFAULT(TestingClientMaxIntervalWithoutRequest);
- CHECK_DEFAULT(TestingDirConnectionMaxStall);
- CHECK_DEFAULT(TestingAuthKeyLifetime);
- CHECK_DEFAULT(TestingLinkCertLifetime);
- CHECK_DEFAULT(TestingSigningKeySlop);
- CHECK_DEFAULT(TestingAuthKeySlop);
- CHECK_DEFAULT(TestingLinkKeySlop);
+ } \
+ STMT_END
+
+ /* Check for options that can only be changed from the defaults in testing
+ networks. */
+ if (! options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
+ or_options_t *dflt_options = options_new();
+ options_init(dflt_options);
+ /* 31851: some of these options are dirauth or relay only */
+ CHECK_DEFAULT(TestingV3AuthInitialVotingInterval);
+ CHECK_DEFAULT(TestingV3AuthInitialVoteDelay);
+ CHECK_DEFAULT(TestingV3AuthInitialDistDelay);
+ CHECK_DEFAULT(TestingV3AuthVotingStartOffset);
+ CHECK_DEFAULT(TestingAuthDirTimeToLearnReachability);
+ CHECK_DEFAULT(TestingServerDownloadInitialDelay);
+ CHECK_DEFAULT(TestingClientDownloadInitialDelay);
+ CHECK_DEFAULT(TestingServerConsensusDownloadInitialDelay);
+ CHECK_DEFAULT(TestingClientConsensusDownloadInitialDelay);
+ CHECK_DEFAULT(TestingBridgeDownloadInitialDelay);
+ CHECK_DEFAULT(TestingBridgeBootstrapDownloadInitialDelay);
+ CHECK_DEFAULT(TestingClientMaxIntervalWithoutRequest);
+ CHECK_DEFAULT(TestingDirConnectionMaxStall);
+ CHECK_DEFAULT(TestingAuthKeyLifetime);
+ CHECK_DEFAULT(TestingLinkCertLifetime);
+ CHECK_DEFAULT(TestingSigningKeySlop);
+ CHECK_DEFAULT(TestingAuthKeySlop);
+ CHECK_DEFAULT(TestingLinkKeySlop);
+ or_options_free(dflt_options);
+ }
#undef CHECK_DEFAULT
if (!options->ClientDNSRejectInternalAddresses &&
!(options->DirAuthorities ||
(options->AlternateDirAuthority && options->AlternateBridgeAuthority)))
REJECT("ClientDNSRejectInternalAddresses used for default network.");
- if (options->SigningKeyLifetime < options->TestingSigningKeySlop*2)
- REJECT("SigningKeyLifetime is too short.");
- if (options->TestingLinkCertLifetime < options->TestingAuthKeySlop*2)
- REJECT("LinkCertLifetime is too short.");
- if (options->TestingAuthKeyLifetime < options->TestingLinkKeySlop*2)
- REJECT("TestingAuthKeyLifetime is too short.");
-
- if (options->TestingV3AuthInitialVotingInterval
- < MIN_VOTE_INTERVAL_TESTING_INITIAL) {
- REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
- } else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) {
- REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into "
- "30 minutes.");
- }
-
- if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS_TESTING) {
- REJECT("TestingV3AuthInitialVoteDelay is way too low.");
- }
-
- if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS_TESTING) {
- REJECT("TestingV3AuthInitialDistDelay is way too low.");
- }
-
- if (options->TestingV3AuthInitialVoteDelay +
- options->TestingV3AuthInitialDistDelay >=
- options->TestingV3AuthInitialVotingInterval) {
- REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay "
- "must be less than TestingV3AuthInitialVotingInterval");
- }
-
- if (options->TestingV3AuthVotingStartOffset >
- MIN(options->TestingV3AuthInitialVotingInterval,
- options->V3AuthVotingInterval)) {
- REJECT("TestingV3AuthVotingStartOffset is higher than the voting "
- "interval.");
- } else if (options->TestingV3AuthVotingStartOffset < 0) {
- REJECT("TestingV3AuthVotingStartOffset must be non-negative.");
- }
-
- if (options->TestingAuthDirTimeToLearnReachability < 0) {
- REJECT("TestingAuthDirTimeToLearnReachability must be non-negative.");
- } else if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) {
- COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high.");
- }
- if (options->TestingEstimatedDescriptorPropagationTime < 0) {
- REJECT("TestingEstimatedDescriptorPropagationTime must be non-negative.");
- } else if (options->TestingEstimatedDescriptorPropagationTime > 60*60) {
- COMPLAIN("TestingEstimatedDescriptorPropagationTime is insanely high.");
- }
+ if (options_validate_relay_testing(old_options, options, msg) < 0)
+ return -1;
+ if (options_validate_dirauth_testing(old_options, options, msg) < 0)
+ return -1;
if (options->TestingClientMaxIntervalWithoutRequest < 1) {
REJECT("TestingClientMaxIntervalWithoutRequest is way too low.");
@@ -4569,27 +3897,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
"testing Tor network!");
}
- if (options->AccelName && !options->HardwareAccel)
- options->HardwareAccel = 1;
- if (options->AccelDir && !options->AccelName)
- REJECT("Can't use hardware crypto accelerator dir without engine name.");
-
- if (options->PublishServerDescriptor)
- SMARTLIST_FOREACH(options->PublishServerDescriptor, const char *, pubdes, {
- if (!strcmp(pubdes, "1") || !strcmp(pubdes, "0"))
- if (smartlist_len(options->PublishServerDescriptor) > 1) {
- COMPLAIN("You have passed a list of multiple arguments to the "
- "PublishServerDescriptor option that includes 0 or 1. "
- "0 or 1 should only be used as the sole argument. "
- "This configuration will be rejected in a future release.");
- break;
- }
- });
-
- if (options->BridgeRelay == 1 && ! options->ORPort_set)
- REJECT("BridgeRelay is 1, ORPort is not set. This is an invalid "
- "combination.");
-
if (options_validate_scheduler(options, msg) < 0) {
return -1;
}
@@ -4681,50 +3988,6 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
}
}
-/* If we have less than 300 MB suggest disabling dircache */
-#define DIRCACHE_MIN_MEM_MB 300
-#define DIRCACHE_MIN_MEM_BYTES (DIRCACHE_MIN_MEM_MB*ONE_MEGABYTE)
-#define STRINGIFY(val) #val
-
-/** Create a warning message for emitting if we are a dircache but may not have
- * enough system memory, or if we are not a dircache but probably should be.
- * Return -1 when a message is returned in *msg*, else return 0. */
-STATIC int
-have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem,
- char **msg)
-{
- *msg = NULL;
- /* XXX We should possibly be looking at MaxMemInQueues here
- * unconditionally. Or we should believe total_mem unconditionally. */
- if (total_mem == 0) {
- if (get_total_system_memory(&total_mem) < 0) {
- total_mem = options->MaxMemInQueues >= SIZE_MAX ?
- SIZE_MAX : (size_t)options->MaxMemInQueues;
- }
- }
- if (options->DirCache) {
- if (total_mem < DIRCACHE_MIN_MEM_BYTES) {
- if (options->BridgeRelay) {
- tor_asprintf(msg, "Running a Bridge with less than %d MB of memory "
- "is not recommended.", DIRCACHE_MIN_MEM_MB);
- } else {
- tor_asprintf(msg, "Being a directory cache (default) with less than "
- "%d MB of memory is not recommended and may consume "
- "most of the available resources. Consider disabling "
- "this functionality by setting the DirCache option "
- "to 0.", DIRCACHE_MIN_MEM_MB);
- }
- }
- } else {
- if (total_mem >= DIRCACHE_MIN_MEM_BYTES) {
- *msg = tor_strdup("DirCache is disabled and we are configured as a "
- "relay. We will not become a Guard.");
- }
- }
- return *msg == NULL ? 0 : -1;
-}
-#undef STRINGIFY
-
/** Helper: return true iff s1 and s2 are both NULL, or both non-NULL
* equal strings. */
static int
@@ -4733,13 +3996,19 @@ opt_streq(const char *s1, const char *s2)
return 0 == strcmp_opt(s1, s2);
}
-/** Check if any of the previous options have changed but aren't allowed to. */
+/** Check if any config options have changed but aren't allowed to. */
static int
-options_transition_allowed(const or_options_t *old,
- const or_options_t *new_val,
- char **msg)
+options_check_transition_cb(const void *old_,
+ const void *new_val_,
+ char **msg)
{
- if (!old)
+ CHECK_OPTIONS_MAGIC(old_);
+ CHECK_OPTIONS_MAGIC(new_val_);
+
+ const or_options_t *old = old_;
+ const or_options_t *new_val = new_val_;
+
+ if (BUG(!old))
return 0;
#define BAD_CHANGE_TO(opt, how) do { \
@@ -4748,36 +4017,6 @@ options_transition_allowed(const or_options_t *old,
return -1; \
} while (0)
-#define NO_CHANGE_BOOL(opt) \
- if (! CFG_EQ_BOOL(old, new_val, opt)) BAD_CHANGE_TO(opt,"")
-#define NO_CHANGE_INT(opt) \
- if (! CFG_EQ_INT(old, new_val, opt)) BAD_CHANGE_TO(opt,"")
-#define NO_CHANGE_STRING(opt) \
- if (! CFG_EQ_STRING(old, new_val, opt)) BAD_CHANGE_TO(opt,"")
-
- NO_CHANGE_STRING(PidFile);
- NO_CHANGE_BOOL(RunAsDaemon);
- NO_CHANGE_BOOL(Sandbox);
- NO_CHANGE_STRING(DataDirectory);
- NO_CHANGE_STRING(KeyDirectory);
- NO_CHANGE_STRING(CacheDirectory);
- NO_CHANGE_STRING(User);
- NO_CHANGE_BOOL(KeepBindCapabilities);
- NO_CHANGE_STRING(SyslogIdentityTag);
- NO_CHANGE_STRING(AndroidIdentityTag);
- NO_CHANGE_BOOL(HardwareAccel);
- NO_CHANGE_STRING(AccelName);
- NO_CHANGE_STRING(AccelDir);
- NO_CHANGE_BOOL(TestingTorNetwork);
- NO_CHANGE_BOOL(DisableAllSwap);
- NO_CHANGE_INT(TokenBucketRefillInterval);
- NO_CHANGE_BOOL(HiddenServiceSingleHopMode);
- NO_CHANGE_BOOL(HiddenServiceNonAnonymousMode);
- NO_CHANGE_BOOL(DisableDebuggerAttachment);
- NO_CHANGE_BOOL(NoExec);
- NO_CHANGE_INT(OwningControllerFD);
- NO_CHANGE_BOOL(DisableSignalHandlers);
-
if (sandbox_is_active()) {
#define SB_NOCHANGE_STR(opt) \
if (! CFG_EQ_STRING(old, new_val, opt)) \
@@ -4814,71 +4053,6 @@ options_transition_allowed(const or_options_t *old,
return 0;
}
-/** Return 1 if any change from <b>old_options</b> to <b>new_options</b>
- * will require us to rotate the CPU and DNS workers; else return 0. */
-static int
-options_transition_affects_workers(const or_options_t *old_options,
- const or_options_t *new_options)
-{
- YES_IF_CHANGED_STRING(DataDirectory);
- YES_IF_CHANGED_INT(NumCPUs);
- YES_IF_CHANGED_LINELIST(ORPort_lines);
- YES_IF_CHANGED_BOOL(ServerDNSSearchDomains);
- YES_IF_CHANGED_BOOL(SafeLogging_);
- YES_IF_CHANGED_BOOL(ClientOnly);
- YES_IF_CHANGED_BOOL(LogMessageDomains);
- YES_IF_CHANGED_LINELIST(Logs);
-
- if (server_mode(old_options) != server_mode(new_options) ||
- public_server_mode(old_options) != public_server_mode(new_options) ||
- dir_server_mode(old_options) != dir_server_mode(new_options))
- return 1;
-
- /* Nothing that changed matters. */
- return 0;
-}
-
-/** Return 1 if any change from <b>old_options</b> to <b>new_options</b>
- * will require us to generate a new descriptor; else return 0. */
-static int
-options_transition_affects_descriptor(const or_options_t *old_options,
- const or_options_t *new_options)
-{
- /* XXX We can be smarter here. If your DirPort isn't being
- * published and you just turned it off, no need to republish. Etc. */
-
- YES_IF_CHANGED_STRING(DataDirectory);
- YES_IF_CHANGED_STRING(Nickname);
- YES_IF_CHANGED_STRING(Address);
- YES_IF_CHANGED_LINELIST(ExitPolicy);
- YES_IF_CHANGED_BOOL(ExitRelay);
- YES_IF_CHANGED_BOOL(ExitPolicyRejectPrivate);
- YES_IF_CHANGED_BOOL(ExitPolicyRejectLocalInterfaces);
- YES_IF_CHANGED_BOOL(IPv6Exit);
- YES_IF_CHANGED_LINELIST(ORPort_lines);
- YES_IF_CHANGED_LINELIST(DirPort_lines);
- YES_IF_CHANGED_LINELIST(DirPort_lines);
- YES_IF_CHANGED_BOOL(ClientOnly);
- YES_IF_CHANGED_BOOL(DisableNetwork);
- YES_IF_CHANGED_BOOL(PublishServerDescriptor_);
- YES_IF_CHANGED_STRING(ContactInfo);
- YES_IF_CHANGED_STRING(BridgeDistribution);
- YES_IF_CHANGED_LINELIST(MyFamily);
- YES_IF_CHANGED_STRING(AccountingStart);
- YES_IF_CHANGED_INT(AccountingMax);
- YES_IF_CHANGED_INT(AccountingRule);
- YES_IF_CHANGED_BOOL(DirCache);
- YES_IF_CHANGED_BOOL(AssumeReachable);
-
- if (get_effective_bwrate(old_options) != get_effective_bwrate(new_options) ||
- get_effective_bwburst(old_options) !=
- get_effective_bwburst(new_options) ||
- public_server_mode(old_options) != public_server_mode(new_options))
- return 1;
-
- return 0;
-}
-
#ifdef _WIN32
/** Return the directory on windows where we expect to find our application
* data. */
@@ -4963,85 +4137,6 @@ get_default_conf_file(int defaults_file)
#endif /* defined(DISABLE_SYSTEM_TORRC) || ... */
}
-/** Verify whether lst is a list of strings containing valid-looking
- * comma-separated nicknames, or NULL. Will normalise <b>lst</b> to prefix '$'
- * to any nickname or fingerprint that needs it. Also splits comma-separated
- * list elements into multiple elements. Return 0 on success.
- * Warn and return -1 on failure.
- */
-static int
-normalize_nickname_list(config_line_t **normalized_out,
- const config_line_t *lst, const char *name,
- char **msg)
-{
- if (!lst)
- return 0;
-
- config_line_t *new_nicknames = NULL;
- config_line_t **new_nicknames_next = &new_nicknames;
-
- const config_line_t *cl;
- for (cl = lst; cl; cl = cl->next) {
- const char *line = cl->value;
- if (!line)
- continue;
-
- int valid_line = 1;
- smartlist_t *sl = smartlist_new();
- smartlist_split_string(sl, line, ",",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK|SPLIT_STRIP_SPACE, 0);
- SMARTLIST_FOREACH_BEGIN(sl, char *, s)
- {
- char *normalized = NULL;
- if (!is_legal_nickname_or_hexdigest(s)) {
- // check if first char is dollar
- if (s[0] != '$') {
- // Try again but with a dollar symbol prepended
- char *prepended;
- tor_asprintf(&prepended, "$%s", s);
-
- if (is_legal_nickname_or_hexdigest(prepended)) {
- // The nickname is valid when it's prepended, set it as the
- // normalized version
- normalized = prepended;
- } else {
- // Still not valid, free and fallback to error message
- tor_free(prepended);
- }
- }
-
- if (!normalized) {
- tor_asprintf(msg, "Invalid nickname '%s' in %s line", s, name);
- valid_line = 0;
- break;
- }
- } else {
- normalized = tor_strdup(s);
- }
-
- config_line_t *next = tor_malloc_zero(sizeof(*next));
- next->key = tor_strdup(cl->key);
- next->value = normalized;
- next->next = NULL;
-
- *new_nicknames_next = next;
- new_nicknames_next = &next->next;
- } SMARTLIST_FOREACH_END(s);
-
- SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
- smartlist_free(sl);
-
- if (!valid_line) {
- config_free_lines(new_nicknames);
- return -1;
- }
- }
-
- *normalized_out = new_nicknames;
-
- return 0;
-}
-
/** Learn config file name from command line arguments, or use the default.
*
* If <b>defaults_file</b> is true, we're looking for torrc-defaults;
@@ -5054,12 +4149,12 @@ normalize_nickname_list(config_line_t **normalized_out,
* filename if it doesn't exist.
*/
static char *
-find_torrc_filename(config_line_t *cmd_arg,
+find_torrc_filename(const config_line_t *cmd_arg,
int defaults_file,
int *using_default_fname, int *ignore_missing_torrc)
{
char *fname=NULL;
- config_line_t *p_index;
+ const config_line_t *p_index;
const char *fname_opt = defaults_file ? "--defaults-torrc" : "-f";
const char *ignore_opt = defaults_file ? NULL : "--ignore-missing-torrc";
@@ -5138,7 +4233,7 @@ load_torrc_from_stdin(void)
* Return the contents of the file on success, and NULL on failure.
*/
static char *
-load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file)
+load_torrc_from_disk(const config_line_t *cmd_arg, int defaults_file)
{
char *fname=NULL;
char *cf = NULL;
@@ -5193,24 +4288,20 @@ int
options_init_from_torrc(int argc, char **argv)
{
char *cf=NULL, *cf_defaults=NULL;
- int command;
int retval = -1;
- char *command_arg = NULL;
char *errmsg=NULL;
- config_line_t *p_index = NULL;
- config_line_t *cmdline_only_options = NULL;
+ const config_line_t *cmdline_only_options;
/* Go through command-line variables */
- if (! have_parsed_cmdline) {
+ if (global_cmdline == NULL) {
/* Or we could redo the list every time we pass this place.
* It does not really matter */
- if (config_parse_commandline(argc, argv, 0, &global_cmdline_options,
- &global_cmdline_only_options) < 0) {
+ global_cmdline = config_parse_commandline(argc, argv, 0);
+ if (global_cmdline == NULL) {
goto err;
}
- have_parsed_cmdline = 1;
}
- cmdline_only_options = global_cmdline_only_options;
+ cmdline_only_options = global_cmdline->cmdline_opts;
if (config_line_find(cmdline_only_options, "-h") ||
config_line_find(cmdline_only_options, "--help")) {
@@ -5227,6 +4318,10 @@ options_init_from_torrc(int argc, char **argv)
list_deprecated_options();
return 1;
}
+ if (config_line_find(cmdline_only_options, "--dbg-dump-subsystem-list")) {
+ subsystems_dump_list();
+ return 1;
+ }
if (config_line_find(cmdline_only_options, "--version")) {
printf("Tor version %s.\n",get_version());
@@ -5273,25 +4368,10 @@ options_init_from_torrc(int argc, char **argv)
return 1;
}
- command = CMD_RUN_TOR;
- for (p_index = cmdline_only_options; p_index; p_index = p_index->next) {
- if (!strcmp(p_index->key,"--keygen")) {
- command = CMD_KEYGEN;
- } else if (!strcmp(p_index->key, "--key-expiration")) {
- command = CMD_KEY_EXPIRATION;
- command_arg = p_index->value;
- } else if (!strcmp(p_index->key,"--list-fingerprint")) {
- command = CMD_LIST_FINGERPRINT;
- } else if (!strcmp(p_index->key, "--hash-password")) {
- command = CMD_HASH_PASSWORD;
- command_arg = p_index->value;
- } else if (!strcmp(p_index->key, "--dump-config")) {
- command = CMD_DUMP_CONFIG;
- command_arg = p_index->value;
- } else if (!strcmp(p_index->key, "--verify-config")) {
- command = CMD_VERIFY_CONFIG;
- }
- }
+ int command = global_cmdline->command;
+ const char *command_arg = global_cmdline->command_arg;
+ /* "immediate" has already been handled by this point. */
+ tor_assert(command != CMD_IMMEDIATE);
if (command == CMD_HASH_PASSWORD) {
cf_defaults = tor_strdup("");
@@ -5459,8 +4539,15 @@ options_init_from_string(const char *cf_defaults, const char *cf,
}
/* Go through command-line variables too */
- retval = config_assign(get_options_mgr(), newoptions,
- global_cmdline_options, CAL_WARN_DEPRECATIONS, msg);
+ {
+ config_line_t *other_opts = NULL;
+ if (global_cmdline) {
+ other_opts = global_cmdline->other_opts;
+ }
+ retval = config_assign(get_options_mgr(), newoptions,
+ other_opts,
+ CAL_WARN_DEPRECATIONS, msg);
+ }
if (retval < 0) {
err = SETOPT_ERR_PARSE;
goto err;
@@ -5468,6 +4555,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->IncludeUsed = cf_has_include;
newoptions->FilesOpenedByIncludes = opened_files;
+ opened_files = NULL; // prevent double-free.
/* If this is a testing network configuration, change defaults
* for a list of dependent config options, and try this function again. */
@@ -5478,28 +4566,12 @@ options_init_from_string(const char *cf_defaults, const char *cf,
goto err;
}
- newoptions->IncludeUsed = cf_has_include;
- in_option_validation = 1;
- newoptions->FilesOpenedByIncludes = opened_files;
-
- /* Validate newoptions */
- if (options_validate(oldoptions, newoptions, newdefaultoptions,
- 0, msg) < 0) {
- err = SETOPT_ERR_PARSE; /*XXX make this a separate return value.*/
+ err = options_validate_and_set(oldoptions, newoptions, msg);
+ if (err < 0) {
+ newoptions = NULL; // This was already freed in options_validate_and_set.
goto err;
}
- if (options_transition_allowed(oldoptions, newoptions, msg) < 0) {
- err = SETOPT_ERR_TRANSITION;
- goto err;
- }
- in_option_validation = 0;
-
- if (set_options(newoptions, msg)) {
- err = SETOPT_ERR_SETTING;
- goto err; /* frees and replaces old options */
- }
-
or_options_free(global_default_options);
global_default_options = newdefaultoptions;
@@ -5511,10 +4583,8 @@ options_init_from_string(const char *cf_defaults, const char *cf,
SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
smartlist_free(opened_files);
}
- // may have been set to opened_files, avoid double free
- newoptions->FilesOpenedByIncludes = NULL;
- or_options_free(newoptions);
or_options_free(newdefaultoptions);
+ or_options_free(newoptions);
if (*msg) {
char *old_msg = *msg;
tor_asprintf(msg, "Failed to parse/validate config: %s", old_msg);
@@ -5647,22 +4717,14 @@ open_and_add_file_log(const log_severity_list_t *severity,
}
/**
- * Initialize the logs based on the configuration file.
- */
+ * Try to set our global log granularity from `options->LogGranularity`,
+ * adjusting it as needed so that we are an even divisor of a second, or an
+ * even multiple of seconds. Return 0 on success, -1 on failure.
+ **/
static int
-options_init_logs(const or_options_t *old_options, or_options_t *options,
- int validate_only)
+options_init_log_granularity(const or_options_t *options,
+ int validate_only)
{
- config_line_t *opt;
- int ok;
- smartlist_t *elts;
- int run_as_daemon =
-#ifdef _WIN32
- 0;
-#else
- options->RunAsDaemon;
-#endif
-
if (options->LogTimeGranularity <= 0) {
log_warn(LD_CONFIG, "Log time granularity '%d' has to be positive.",
options->LogTimeGranularity);
@@ -5692,9 +4754,38 @@ options_init_logs(const or_options_t *old_options, or_options_t *options,
set_log_time_granularity(options->LogTimeGranularity);
}
+ return 0;
+}
+
+/**
+ * Initialize the logs based on the configuration file.
+ */
+STATIC int
+options_init_logs(const or_options_t *old_options, const or_options_t *options,
+ int validate_only)
+{
+ config_line_t *opt;
+ int ok;
+ smartlist_t *elts;
+ int run_as_daemon =
+#ifdef _WIN32
+ 0;
+#else
+ options->RunAsDaemon;
+#endif
+
+ if (options_init_log_granularity(options, validate_only) < 0)
+ return -1;
+
ok = 1;
elts = smartlist_new();
+ if (options->Logs == NULL && !run_as_daemon && !validate_only) {
+ /* When no logs are given, the default behavior is to log nothing (if
+ RunAsDaemon is set) or to log based on the quiet level otherwise. */
+ add_default_log_for_quiet_level(quiet_level);
+ }
+
for (opt = options->Logs; opt; opt = opt->next) {
log_severity_list_t *severity;
const char *cfg = opt->value;
@@ -5968,6 +5059,68 @@ parse_bridge_line(const char *line)
return bridge_line;
}
+/** Parse the contents of a TCPProxy line from <b>line</b> and put it
+ * in <b>options</b>. Return 0 if the line is well-formed, and -1 if it
+ * isn't.
+ *
+ * This will mutate only options->TCPProxyProtocol, options->TCPProxyAddr,
+ * and options->TCPProxyPort.
+ *
+ * On error, tor_strdup an error explanation into *<b>msg</b>.
+ */
+STATIC int
+parse_tcp_proxy_line(const char *line, or_options_t *options, char **msg)
+{
+ int ret = 0;
+ tor_assert(line);
+ tor_assert(options);
+ tor_assert(msg);
+
+ smartlist_t *sl = smartlist_new();
+ /* Split between the protocol and the address/port. */
+ smartlist_split_string(sl, line, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
+
+ /* The address/port is not specified. */
+ if (smartlist_len(sl) < 2) {
+ *msg = tor_strdup("TCPProxy has no address/port. Please fix.");
+ goto err;
+ }
+
+ char *protocol_string = smartlist_get(sl, 0);
+ char *addrport_string = smartlist_get(sl, 1);
+
+ /* The only currently supported protocol is 'haproxy'. */
+ if (strcasecmp(protocol_string, "haproxy")) {
+ *msg = tor_strdup("TCPProxy protocol is not supported. Currently "
+ "the only supported protocol is 'haproxy'. "
+ "Please fix.");
+ goto err;
+ } else {
+ /* Otherwise, set the correct protocol. */
+ options->TCPProxyProtocol = TCP_PROXY_PROTOCOL_HAPROXY;
+ }
+
+ /* Parse the address/port. */
+ if (tor_addr_port_lookup(addrport_string, &options->TCPProxyAddr,
+ &options->TCPProxyPort) < 0) {
+ *msg = tor_strdup("TCPProxy address/port failed to parse or resolve. "
+ "Please fix.");
+ goto err;
+ }
+
+ /* Success. */
+ ret = 0;
+ goto end;
+
+ err:
+ ret = -1;
+ end:
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+ return ret;
+}
+
/** Read the contents of a ClientTransportPlugin or ServerTransportPlugin
* line from <b>line</b>, depending on the value of <b>server</b>. Return 0
* if the line is well-formed, and -1 if it isn't.
@@ -5978,9 +5131,8 @@ parse_bridge_line(const char *line)
* our internal transport list.
* - If it's a managed proxy line, launch the managed proxy.
*/
-
-STATIC int
-parse_transport_line(const or_options_t *options,
+int
+pt_parse_transport_line(const or_options_t *options,
const char *line, int validate_only,
int server)
{
@@ -6116,9 +5268,10 @@ parse_transport_line(const or_options_t *options,
/* ClientTransportPlugins connecting through a proxy is managed only. */
if (!server && (options->Socks4Proxy || options->Socks5Proxy ||
- options->HTTPSProxy)) {
+ options->HTTPSProxy || options->TCPProxy)) {
log_warn(LD_CONFIG, "You have configured an external proxy with another "
- "proxy type. (Socks4Proxy|Socks5Proxy|HTTPSProxy)");
+ "proxy type. (Socks4Proxy|Socks5Proxy|HTTPSProxy|"
+ "TCPProxy)");
goto err;
}
@@ -6173,157 +5326,6 @@ parse_transport_line(const or_options_t *options,
return r;
}
-/** Given a ServerTransportListenAddr <b>line</b>, return its
- * <address:port> string. Return NULL if the line was not
- * well-formed.
- *
- * If <b>transport</b> is set, return NULL if the line is not
- * referring to <b>transport</b>.
- *
- * The returned string is allocated on the heap and it's the
- * responsibility of the caller to free it. */
-static char *
-get_bindaddr_from_transport_listen_line(const char *line,const char *transport)
-{
- smartlist_t *items = NULL;
- const char *parsed_transport = NULL;
- char *addrport = NULL;
- tor_addr_t addr;
- uint16_t port = 0;
-
- items = smartlist_new();
- smartlist_split_string(items, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
-
- if (smartlist_len(items) < 2) {
- log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line.");
- goto err;
- }
-
- parsed_transport = smartlist_get(items, 0);
- addrport = tor_strdup(smartlist_get(items, 1));
-
- /* If 'transport' is given, check if it matches the one on the line */
- if (transport && strcmp(transport, parsed_transport))
- goto err;
-
- /* Validate addrport */
- if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) {
- log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
- "address '%s'", addrport);
- goto err;
- }
-
- goto done;
-
- err:
- tor_free(addrport);
- addrport = NULL;
-
- done:
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
-
- return addrport;
-}
-
-/** Given a ServerTransportOptions <b>line</b>, return a smartlist
- * with the options. Return NULL if the line was not well-formed.
- *
- * If <b>transport</b> is set, return NULL if the line is not
- * referring to <b>transport</b>.
- *
- * The returned smartlist and its strings are allocated on the heap
- * and it's the responsibility of the caller to free it. */
-smartlist_t *
-get_options_from_transport_options_line(const char *line,const char *transport)
-{
- smartlist_t *items = smartlist_new();
- smartlist_t *options = smartlist_new();
- const char *parsed_transport = NULL;
-
- smartlist_split_string(items, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
-
- if (smartlist_len(items) < 2) {
- log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line.");
- goto err;
- }
-
- parsed_transport = smartlist_get(items, 0);
- /* If 'transport' is given, check if it matches the one on the line */
- if (transport && strcmp(transport, parsed_transport))
- goto err;
-
- SMARTLIST_FOREACH_BEGIN(items, const char *, option) {
- if (option_sl_idx == 0) /* skip the transport field (first field)*/
- continue;
-
- /* validate that it's a k=v value */
- if (!string_is_key_value(LOG_WARN, option)) {
- log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option));
- goto err;
- }
-
- /* add it to the options smartlist */
- smartlist_add_strdup(options, option);
- log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option));
- } SMARTLIST_FOREACH_END(option);
-
- goto done;
-
- err:
- SMARTLIST_FOREACH(options, char*, s, tor_free(s));
- smartlist_free(options);
- options = NULL;
-
- done:
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
-
- return options;
-}
-
-/** Given the name of a pluggable transport in <b>transport</b>, check
- * the configuration file to see if the user has explicitly asked for
- * it to listen on a specific port. Return a <address:port> string if
- * so, otherwise NULL. */
-char *
-get_transport_bindaddr_from_config(const char *transport)
-{
- config_line_t *cl;
- const or_options_t *options = get_options();
-
- for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
- char *bindaddr =
- get_bindaddr_from_transport_listen_line(cl->value, transport);
- if (bindaddr)
- return bindaddr;
- }
-
- return NULL;
-}
-
-/** Given the name of a pluggable transport in <b>transport</b>, check
- * the configuration file to see if the user has asked us to pass any
- * parameters to the pluggable transport. Return a smartlist
- * containing the parameters, otherwise NULL. */
-smartlist_t *
-get_options_for_server_transport(const char *transport)
-{
- config_line_t *cl;
- const or_options_t *options = get_options();
-
- for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
- smartlist_t *options_sl =
- get_options_from_transport_options_line(cl->value, transport);
- if (options_sl)
- return options_sl;
- }
-
- return NULL;
-}
-
/** 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>
@@ -6594,22 +5596,33 @@ parse_dir_fallback_line(const char *line,
return r;
}
-/** Allocate and return a new port_cfg_t with reasonable defaults. */
-STATIC port_cfg_t *
+/** Allocate and return a new port_cfg_t with reasonable defaults.
+ *
+ * <b>namelen</b> is the length of the unix socket name
+ * (typically the filesystem path), not including the trailing NUL.
+ * It should be 0 for ports that are not zunix sockets. */
+port_cfg_t *
port_cfg_new(size_t namelen)
{
tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1);
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1);
+
+ /* entry_cfg flags */
cfg->entry_cfg.ipv4_traffic = 1;
cfg->entry_cfg.ipv6_traffic = 1;
+ cfg->entry_cfg.prefer_ipv6 = 0;
cfg->entry_cfg.dns_request = 1;
cfg->entry_cfg.onion_traffic = 1;
cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
+ cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
+ cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
+
+ /* Other flags default to 0 due to tor_malloc_zero */
return cfg;
}
/** Free all storage held in <b>port</b> */
-STATIC void
+void
port_cfg_free_(port_cfg_t *port)
{
tor_free(port);
@@ -6643,27 +5656,6 @@ warn_nonlocal_client_ports(const smartlist_t *ports,
} SMARTLIST_FOREACH_END(port);
}
-/** Warn for every Extended ORPort port in <b>ports</b> that is on a
- * publicly routable address. */
-static void
-warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname)
-{
- SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
- if (port->type != CONN_TYPE_EXT_OR_LISTENER)
- continue;
- if (port->is_unix_addr)
- continue;
- /* XXX maybe warn even if address is RFC1918? */
- if (!tor_addr_is_internal(&port->addr, 1)) {
- log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. "
- "This is not advised; this address is supposed to only be "
- "exposed on localhost so that your pluggable transport "
- "proxies can connect to it.",
- fmt_addrport(&port->addr, port->port), portname);
- }
- } SMARTLIST_FOREACH_END(port);
-}
-
/** Given a list of port_cfg_t in <b>ports</b>, warn if any controller port
* there is listening on any non-loopback address. If <b>forbid_nonlocal</b>
* is true, then emit a stronger warning and remove the port from the list.
@@ -6734,7 +5726,7 @@ port_cfg_line_extract_addrport(const char *line,
size_t sz;
*is_unix_out = 1;
*addrport_out = NULL;
- line += strlen(unix_socket_prefix); /*No q: Keep the quote */
+ line += strlen(unix_socket_prefix); /* No 'unix:', but keep the quote */
*rest_out = unescape_string(line, addrport_out, &sz);
if (!*rest_out || (*addrport_out && sz != strlen(*addrport_out))) {
tor_free(*addrport_out);
@@ -6777,55 +5769,6 @@ warn_client_dns_cache(const char *option, int disabling)
}
/**
- * Validate the configured bridge distribution method from a BridgeDistribution
- * config line.
- *
- * The input <b>bd</b>, is a string taken from the BridgeDistribution config
- * line (if present). If the option wasn't set, return 0 immediately. The
- * BridgeDistribution option is then validated. Currently valid, recognised
- * options are:
- *
- * - "none"
- * - "any"
- * - "https"
- * - "email"
- * - "moat"
- * - "hyphae"
- *
- * If the option string is unrecognised, a warning will be logged and 0 is
- * returned. If the option string contains an invalid character, -1 is
- * returned.
- **/
-STATIC int
-check_bridge_distribution_setting(const char *bd)
-{
- if (bd == NULL)
- return 0;
-
- const char *RECOGNIZED[] = {
- "none", "any", "https", "email", "moat", "hyphae"
- };
- unsigned i;
- for (i = 0; i < ARRAY_LENGTH(RECOGNIZED); ++i) {
- if (!strcasecmp(bd, RECOGNIZED[i]))
- return 0;
- }
-
- const char *cp = bd;
- // Method = (KeywordChar | "_") +
- while (TOR_ISALNUM(*cp) || *cp == '-' || *cp == '_')
- ++cp;
-
- if (*cp == 0) {
- log_warn(LD_CONFIG, "Unrecognized BridgeDistribution value %s. I'll "
- "assume you know what you are doing...", escaped(bd));
- return 0; // we reached the end of the string; all is well
- } else {
- return -1; // we found a bad character in the string.
- }
-}
-
-/**
* Parse port configuration for a single port type.
*
* Read entries of the "FooPort" type from the list <b>ports</b>. Syntax is
@@ -6855,8 +5798,8 @@ check_bridge_distribution_setting(const char *bd)
* <b>out</b> for every port that the client should listen on. Return 0
* on success, -1 on failure.
*/
-STATIC int
-parse_port_config(smartlist_t *out,
+int
+port_parse_config(smartlist_t *out,
const config_line_t *ports,
const char *portname,
int listener_type,
@@ -6878,11 +5821,12 @@ parse_port_config(smartlist_t *out,
const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET;
int got_zero_port=0, got_nonzero_port=0;
char *unix_socket_path = NULL;
+ port_cfg_t *cfg = NULL;
/* If there's no FooPort, then maybe make a default one. */
if (! ports) {
if (defaultport && defaultaddr && out) {
- port_cfg_t *cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0);
+ cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0);
cfg->type = listener_type;
if (is_unix_socket) {
tor_addr_make_unspec(&cfg->addr);
@@ -6892,8 +5836,6 @@ parse_port_config(smartlist_t *out,
cfg->port = defaultport;
tor_addr_parse(&cfg->addr, defaultaddr);
}
- cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
- cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg);
}
return 0;
@@ -6907,28 +5849,12 @@ parse_port_config(smartlist_t *out,
for (; ports; ports = ports->next) {
tor_addr_t addr;
tor_addr_make_unspec(&addr);
-
- int port;
- int sessiongroup = SESSION_GROUP_UNSET;
- unsigned isolation = ISO_DEFAULT;
- int prefer_no_auth = 0;
- int socks_iso_keep_alive = 0;
-
+ int port, ok,
+ has_used_unix_socket_only_option = 0,
+ is_unix_tagged_addr = 0;
uint16_t ptmp=0;
- int ok;
- /* This must be kept in sync with port_cfg_new's defaults */
- int no_listen = 0, no_advertise = 0, all_addrs = 0,
- bind_ipv4_only = 0, bind_ipv6_only = 0,
- ipv4_traffic = 1, ipv6_traffic = 1, prefer_ipv6 = 0, dns_request = 1,
- onion_traffic = 1,
- cache_ipv4 = 0, use_cached_ipv4 = 0,
- cache_ipv6 = 0, use_cached_ipv6 = 0,
- prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0,
- relax_dirmode_check = 0,
- has_used_unix_socket_only_option = 0;
-
- int is_unix_tagged_addr = 0;
const char *rest_of_line = NULL;
+
if (port_cfg_line_extract_addrport(ports->value,
&addrport, &is_unix_tagged_addr, &rest_of_line)<0) {
log_warn(LD_CONFIG, "Invalid %sPort line with unparsable address",
@@ -7004,17 +5930,20 @@ parse_port_config(smartlist_t *out,
}
}
+ /* Default port_cfg_t object initialization */
+ cfg = port_cfg_new(unix_socket_path ? strlen(unix_socket_path) : 0);
+
if (unix_socket_path && default_to_group_writable)
- group_writable = 1;
+ cfg->is_group_writable = 1;
/* Now parse the rest of the options, if any. */
if (use_server_options) {
/* This is a server port; parse advertising options */
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
if (!strcasecmp(elt, "NoAdvertise")) {
- no_advertise = 1;
+ cfg->server_cfg.no_advertise = 1;
} else if (!strcasecmp(elt, "NoListen")) {
- no_listen = 1;
+ cfg->server_cfg.no_listen = 1;
#if 0
/* not implemented yet. */
} else if (!strcasecmp(elt, "AllAddrs")) {
@@ -7022,33 +5951,36 @@ parse_port_config(smartlist_t *out,
all_addrs = 1;
#endif /* 0 */
} else if (!strcasecmp(elt, "IPv4Only")) {
- bind_ipv4_only = 1;
+ cfg->server_cfg.bind_ipv4_only = 1;
} else if (!strcasecmp(elt, "IPv6Only")) {
- bind_ipv6_only = 1;
+ cfg->server_cfg.bind_ipv6_only = 1;
} else {
log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'",
portname, escaped(elt));
}
} SMARTLIST_FOREACH_END(elt);
- if (no_advertise && no_listen) {
+ if (cfg->server_cfg.no_advertise && cfg->server_cfg.no_listen) {
log_warn(LD_CONFIG, "Tried to set both NoListen and NoAdvertise "
"on %sPort line '%s'",
portname, escaped(ports->value));
goto err;
}
- if (bind_ipv4_only && bind_ipv6_only) {
+ if (cfg->server_cfg.bind_ipv4_only &&
+ cfg->server_cfg.bind_ipv6_only) {
log_warn(LD_CONFIG, "Tried to set both IPv4Only and IPv6Only "
"on %sPort line '%s'",
portname, escaped(ports->value));
goto err;
}
- if (bind_ipv4_only && tor_addr_family(&addr) != AF_INET) {
+ if (cfg->server_cfg.bind_ipv4_only &&
+ tor_addr_family(&addr) != AF_INET) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
portname);
goto err;
}
- if (bind_ipv6_only && tor_addr_family(&addr) != AF_INET6) {
+ if (cfg->server_cfg.bind_ipv6_only &&
+ tor_addr_family(&addr) != AF_INET6) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
portname);
goto err;
@@ -7067,12 +5999,12 @@ parse_port_config(smartlist_t *out,
portname, escaped(elt));
goto err;
}
- if (sessiongroup >= 0) {
+ if (cfg->entry_cfg.session_group >= 0) {
log_warn(LD_CONFIG, "Multiple SessionGroup options on %sPort",
portname);
goto err;
}
- sessiongroup = group;
+ cfg->entry_cfg.session_group = group;
continue;
}
@@ -7082,15 +6014,15 @@ parse_port_config(smartlist_t *out,
}
if (!strcasecmp(elt, "GroupWritable")) {
- group_writable = !no;
+ cfg->is_group_writable = !no;
has_used_unix_socket_only_option = 1;
continue;
} else if (!strcasecmp(elt, "WorldWritable")) {
- world_writable = !no;
+ cfg->is_world_writable = !no;
has_used_unix_socket_only_option = 1;
continue;
} else if (!strcasecmp(elt, "RelaxDirModeCheck")) {
- relax_dirmode_check = !no;
+ cfg->relax_dirmode_check = !no;
has_used_unix_socket_only_option = 1;
continue;
}
@@ -7103,19 +6035,19 @@ parse_port_config(smartlist_t *out,
if (takes_hostnames) {
if (!strcasecmp(elt, "IPv4Traffic")) {
- ipv4_traffic = ! no;
+ cfg->entry_cfg.ipv4_traffic = ! no;
continue;
} else if (!strcasecmp(elt, "IPv6Traffic")) {
- ipv6_traffic = ! no;
+ cfg->entry_cfg.ipv6_traffic = ! no;
continue;
} else if (!strcasecmp(elt, "PreferIPv6")) {
- prefer_ipv6 = ! no;
+ cfg->entry_cfg.prefer_ipv6 = ! no;
continue;
} else if (!strcasecmp(elt, "DNSRequest")) {
- dns_request = ! no;
+ cfg->entry_cfg.dns_request = ! no;
continue;
} else if (!strcasecmp(elt, "OnionTraffic")) {
- onion_traffic = ! no;
+ cfg->entry_cfg.onion_traffic = ! no;
continue;
} else if (!strcasecmp(elt, "OnionTrafficOnly")) {
/* Only connect to .onion addresses. Equivalent to
@@ -7126,43 +6058,50 @@ parse_port_config(smartlist_t *out,
"DNSRequest, IPv4Traffic, and/or IPv6Traffic instead.",
portname, escaped(elt));
} else {
- ipv4_traffic = ipv6_traffic = dns_request = 0;
+ cfg->entry_cfg.ipv4_traffic = 0;
+ cfg->entry_cfg.ipv6_traffic = 0;
+ cfg->entry_cfg.dns_request = 0;
}
continue;
}
}
if (!strcasecmp(elt, "CacheIPv4DNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- cache_ipv4 = ! no;
+ cfg->entry_cfg.cache_ipv4_answers = ! no;
continue;
} else if (!strcasecmp(elt, "CacheIPv6DNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- cache_ipv6 = ! no;
+ cfg->entry_cfg.cache_ipv6_answers = ! no;
continue;
} else if (!strcasecmp(elt, "CacheDNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- cache_ipv4 = cache_ipv6 = ! no;
+ cfg->entry_cfg.cache_ipv4_answers = ! no;
+ cfg->entry_cfg.cache_ipv6_answers = ! no;
continue;
} else if (!strcasecmp(elt, "UseIPv4Cache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- use_cached_ipv4 = ! no;
+ cfg->entry_cfg.use_cached_ipv4_answers = ! no;
continue;
} else if (!strcasecmp(elt, "UseIPv6Cache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- use_cached_ipv6 = ! no;
+ cfg->entry_cfg.use_cached_ipv6_answers = ! no;
continue;
} else if (!strcasecmp(elt, "UseDNSCache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- use_cached_ipv4 = use_cached_ipv6 = ! no;
+ cfg->entry_cfg.use_cached_ipv4_answers = ! no;
+ cfg->entry_cfg.use_cached_ipv6_answers = ! no;
continue;
} else if (!strcasecmp(elt, "PreferIPv6Automap")) {
- prefer_ipv6_automap = ! no;
+ cfg->entry_cfg.prefer_ipv6_virtaddr = ! no;
continue;
} else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) {
- prefer_no_auth = ! no;
+ cfg->entry_cfg.socks_prefer_no_auth = ! no;
continue;
} else if (!strcasecmp(elt, "KeepAliveIsolateSOCKSAuth")) {
- socks_iso_keep_alive = ! no;
+ cfg->entry_cfg.socks_iso_keep_alive = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "ExtendedErrors")) {
+ cfg->entry_cfg.extended_socks5_codes = ! no;
continue;
}
@@ -7185,9 +6124,9 @@ parse_port_config(smartlist_t *out,
}
if (no) {
- isolation &= ~isoflag;
+ cfg->entry_cfg.isolation_flags &= ~isoflag;
} else {
- isolation |= isoflag;
+ cfg->entry_cfg.isolation_flags |= isoflag;
}
} SMARTLIST_FOREACH_END(elt);
}
@@ -7197,51 +6136,51 @@ parse_port_config(smartlist_t *out,
else
got_zero_port = 1;
- if (dns_request == 0 && listener_type == CONN_TYPE_AP_DNS_LISTENER) {
+ if (cfg->entry_cfg.dns_request == 0 &&
+ listener_type == CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with DNS disabled; that "
"won't work.", portname);
goto err;
}
-
- if (ipv4_traffic == 0 && ipv6_traffic == 0 && onion_traffic == 0
- && listener_type != CONN_TYPE_AP_DNS_LISTENER) {
+ if (cfg->entry_cfg.ipv4_traffic == 0 &&
+ cfg->entry_cfg.ipv6_traffic == 0 &&
+ cfg->entry_cfg.onion_traffic == 0 &&
+ listener_type != CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with all of IPv4 and "
"IPv6 and .onion disabled; that won't work.", portname);
goto err;
}
-
- if (dns_request == 1 && ipv4_traffic == 0 && ipv6_traffic == 0
- && listener_type != CONN_TYPE_AP_DNS_LISTENER) {
+ if (cfg->entry_cfg.dns_request == 1 &&
+ cfg->entry_cfg.ipv4_traffic == 0 &&
+ cfg->entry_cfg.ipv6_traffic == 0 &&
+ listener_type != CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with DNSRequest enabled, "
"but IPv4 and IPv6 disabled; DNS-based sites won't work.",
portname);
goto err;
}
-
- if ( has_used_unix_socket_only_option && ! unix_socket_path) {
+ if (has_used_unix_socket_only_option && !unix_socket_path) {
log_warn(LD_CONFIG, "You have a %sPort entry with GroupWritable, "
"WorldWritable, or RelaxDirModeCheck, but it is not a "
"unix socket.", portname);
goto err;
}
-
- if (!(isolation & ISO_SOCKSAUTH) && socks_iso_keep_alive) {
+ if (!(cfg->entry_cfg.isolation_flags & ISO_SOCKSAUTH) &&
+ cfg->entry_cfg.socks_iso_keep_alive) {
log_warn(LD_CONFIG, "You have a %sPort entry with both "
"NoIsolateSOCKSAuth and KeepAliveIsolateSOCKSAuth set.",
portname);
goto err;
}
-
- if (unix_socket_path && (isolation & ISO_CLIENTADDR)) {
+ if (unix_socket_path &&
+ (cfg->entry_cfg.isolation_flags & ISO_CLIENTADDR)) {
/* `IsolateClientAddr` is nonsensical in the context of AF_LOCAL.
* just silently remove the isolation flag.
*/
- isolation &= ~ISO_CLIENTADDR;
+ cfg->entry_cfg.isolation_flags &= ~ISO_CLIENTADDR;
}
-
if (out && port) {
size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0;
- port_cfg_t *cfg = port_cfg_new(namelen);
if (unix_socket_path) {
tor_addr_make_unspec(&cfg->addr);
memcpy(cfg->unix_addr, unix_socket_path, namelen + 1);
@@ -7252,32 +6191,13 @@ parse_port_config(smartlist_t *out,
cfg->port = port;
}
cfg->type = listener_type;
- cfg->is_world_writable = world_writable;
- cfg->is_group_writable = group_writable;
- cfg->relax_dirmode_check = relax_dirmode_check;
- cfg->entry_cfg.isolation_flags = isolation;
- cfg->entry_cfg.session_group = sessiongroup;
- cfg->server_cfg.no_advertise = no_advertise;
- cfg->server_cfg.no_listen = no_listen;
- cfg->server_cfg.all_addrs = all_addrs;
- cfg->server_cfg.bind_ipv4_only = bind_ipv4_only;
- cfg->server_cfg.bind_ipv6_only = bind_ipv6_only;
- cfg->entry_cfg.ipv4_traffic = ipv4_traffic;
- cfg->entry_cfg.ipv6_traffic = ipv6_traffic;
- cfg->entry_cfg.prefer_ipv6 = prefer_ipv6;
- cfg->entry_cfg.dns_request = dns_request;
- cfg->entry_cfg.onion_traffic = onion_traffic;
- cfg->entry_cfg.cache_ipv4_answers = cache_ipv4;
- cfg->entry_cfg.cache_ipv6_answers = cache_ipv6;
- cfg->entry_cfg.use_cached_ipv4_answers = use_cached_ipv4;
- cfg->entry_cfg.use_cached_ipv6_answers = use_cached_ipv6;
- cfg->entry_cfg.prefer_ipv6_virtaddr = prefer_ipv6_automap;
- cfg->entry_cfg.socks_prefer_no_auth = prefer_no_auth;
- if (! (isolation & ISO_SOCKSAUTH))
+ if (! (cfg->entry_cfg.isolation_flags & ISO_SOCKSAUTH))
cfg->entry_cfg.socks_prefer_no_auth = 1;
- cfg->entry_cfg.socks_iso_keep_alive = socks_iso_keep_alive;
-
smartlist_add(out, cfg);
+ /* out owns cfg now, don't re-use or free it */
+ cfg = NULL;
+ } else {
+ tor_free(cfg);
}
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts);
@@ -7289,7 +6209,7 @@ parse_port_config(smartlist_t *out,
if (is_control)
warn_nonlocal_controller_ports(out, forbid_nonlocal);
else if (is_ext_orport)
- warn_nonlocal_ext_orports(out, portname);
+ port_warn_nonlocal_ext_orports(out, portname);
else
warn_nonlocal_client_ports(out, portname, listener_type);
}
@@ -7303,18 +6223,30 @@ parse_port_config(smartlist_t *out,
retval = 0;
err:
+ /* There are two ways we can error out:
+ * 1. part way through the loop: cfg needs to be freed;
+ * 2. ending the loop normally: cfg is always NULL.
+ * In this case, cfg has either been:
+ * - added to out, then set to NULL, or
+ * - freed and set to NULL (because out is NULL, or port is 0).
+ */
+ tor_free(cfg);
+
+ /* Free the other variables from the loop.
+ * elts is always non-NULL here, but it may or may not be empty. */
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts);
tor_free(unix_socket_path);
tor_free(addrport);
+
return retval;
}
/** Return the number of ports which are actually going to listen with type
* <b>listenertype</b>. Do not count no_listen ports. Only count unix
* sockets if count_sockets is true. */
-static int
-count_real_listeners(const smartlist_t *ports, int listenertype,
+int
+port_count_real_listeners(const smartlist_t *ports, int listenertype,
int count_sockets)
{
int n = 0;
@@ -7338,7 +6270,7 @@ count_real_listeners(const smartlist_t *ports, int listenertype,
* If <b>validate_only</b> is false, set configured_client_ports to the
* new list of ports parsed from <b>options</b>.
**/
-static int
+STATIC int
parse_ports(or_options_t *options, int validate_only,
char **msg, int *n_ports_out,
int *world_writable_control_socket)
@@ -7352,7 +6284,7 @@ parse_ports(or_options_t *options, int validate_only,
const unsigned gw_flag = options->UnixSocksGroupWritable ?
CL_PORT_DFLT_GROUP_WRITABLE : 0;
- if (parse_port_config(ports,
+ if (port_parse_config(ports,
options->SocksPort_lines,
"Socks", CONN_TYPE_AP_LISTENER,
"127.0.0.1", 9050,
@@ -7361,7 +6293,7 @@ parse_ports(or_options_t *options, int validate_only,
*msg = tor_strdup("Invalid SocksPort configuration");
goto err;
}
- if (parse_port_config(ports,
+ if (port_parse_config(ports,
options->DNSPort_lines,
"DNS", CONN_TYPE_AP_DNS_LISTENER,
"127.0.0.1", 0,
@@ -7369,7 +6301,7 @@ parse_ports(or_options_t *options, int validate_only,
*msg = tor_strdup("Invalid DNSPort configuration");
goto err;
}
- if (parse_port_config(ports,
+ if (port_parse_config(ports,
options->TransPort_lines,
"Trans", CONN_TYPE_AP_TRANS_LISTENER,
"127.0.0.1", 0,
@@ -7377,7 +6309,7 @@ parse_ports(or_options_t *options, int validate_only,
*msg = tor_strdup("Invalid TransPort configuration");
goto err;
}
- if (parse_port_config(ports,
+ if (port_parse_config(ports,
options->NATDPort_lines,
"NATD", CONN_TYPE_AP_NATD_LISTENER,
"127.0.0.1", 0,
@@ -7385,7 +6317,7 @@ parse_ports(or_options_t *options, int validate_only,
*msg = tor_strdup("Invalid NatdPort configuration");
goto err;
}
- if (parse_port_config(ports,
+ if (port_parse_config(ports,
options->HTTPTunnelPort_lines,
"HTTP Tunnel", CONN_TYPE_AP_HTTP_CONNECT_LISTENER,
"127.0.0.1", 0,
@@ -7405,7 +6337,7 @@ parse_ports(or_options_t *options, int validate_only,
if (options->ControlSocketsGroupWritable)
control_port_flags |= CL_PORT_DFLT_GROUP_WRITABLE;
- if (parse_port_config(ports,
+ if (port_parse_config(ports,
options->ControlPort_lines,
"Control", CONN_TYPE_CONTROL_LISTENER,
"127.0.0.1", 0,
@@ -7414,7 +6346,7 @@ parse_ports(or_options_t *options, int validate_only,
goto err;
}
- if (parse_port_config(ports, options->ControlSocket,
+ if (port_parse_config(ports, options->ControlSocket,
"ControlSocket",
CONN_TYPE_CONTROL_LISTENER, NULL, 0,
control_port_flags | CL_PORT_IS_UNIXSOCKET) < 0) {
@@ -7422,40 +6354,9 @@ parse_ports(or_options_t *options, int validate_only,
goto err;
}
}
- if (! options->ClientOnly) {
- if (parse_port_config(ports,
- options->ORPort_lines,
- "OR", CONN_TYPE_OR_LISTENER,
- "0.0.0.0", 0,
- CL_PORT_SERVER_OPTIONS) < 0) {
- *msg = tor_strdup("Invalid ORPort configuration");
- goto err;
- }
- if (parse_port_config(ports,
- options->ExtORPort_lines,
- "ExtOR", CONN_TYPE_EXT_OR_LISTENER,
- "127.0.0.1", 0,
- CL_PORT_SERVER_OPTIONS|CL_PORT_WARN_NONLOCAL) < 0) {
- *msg = tor_strdup("Invalid ExtORPort configuration");
- goto err;
- }
- if (parse_port_config(ports,
- options->DirPort_lines,
- "Dir", CONN_TYPE_DIR_LISTENER,
- "0.0.0.0", 0,
- CL_PORT_SERVER_OPTIONS) < 0) {
- *msg = tor_strdup("Invalid DirPort configuration");
- goto err;
- }
- }
- int n_low_ports = 0;
- if (check_server_ports(ports, options, &n_low_ports) < 0) {
- *msg = tor_strdup("Misconfigured server ports");
+ if (port_parse_ports_relay(options, msg, ports, &have_low_ports) < 0)
goto err;
- }
- if (have_low_ports < 0)
- have_low_ports = (n_low_ports > 0);
*n_ports_out = smartlist_len(ports);
@@ -7463,25 +6364,20 @@ parse_ports(or_options_t *options, int validate_only,
/* Update the *Port_set options. The !! here is to force a boolean out of
an integer. */
- options->ORPort_set =
- !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER, 0);
+ port_update_port_set_relay(options, ports);
options->SocksPort_set =
- !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER, 1);
+ !! port_count_real_listeners(ports, CONN_TYPE_AP_LISTENER, 1);
options->TransPort_set =
- !! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER, 1);
+ !! port_count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER, 1);
options->NATDPort_set =
- !! count_real_listeners(ports, CONN_TYPE_AP_NATD_LISTENER, 1);
+ !! port_count_real_listeners(ports, CONN_TYPE_AP_NATD_LISTENER, 1);
options->HTTPTunnelPort_set =
- !! count_real_listeners(ports, CONN_TYPE_AP_HTTP_CONNECT_LISTENER, 1);
+ !! port_count_real_listeners(ports, CONN_TYPE_AP_HTTP_CONNECT_LISTENER, 1);
/* Use options->ControlSocket to test if a control socket is set */
options->ControlPort_set =
- !! count_real_listeners(ports, CONN_TYPE_CONTROL_LISTENER, 0);
- options->DirPort_set =
- !! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER, 0);
+ !! port_count_real_listeners(ports, CONN_TYPE_CONTROL_LISTENER, 0);
options->DNSPort_set =
- !! count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER, 1);
- options->ExtORPort_set =
- !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER, 0);
+ !! port_count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER, 1);
if (world_writable_control_socket) {
SMARTLIST_FOREACH(ports, port_cfg_t *, p,
@@ -7512,7 +6408,7 @@ parse_ports(or_options_t *options, int validate_only,
}
/* Does port bind to IPv4? */
-static int
+int
port_binds_ipv4(const port_cfg_t *port)
{
return tor_addr_family(&port->addr) == AF_INET ||
@@ -7521,7 +6417,7 @@ port_binds_ipv4(const port_cfg_t *port)
}
/* Does port bind to IPv6? */
-static int
+int
port_binds_ipv6(const port_cfg_t *port)
{
return tor_addr_family(&port->addr) == AF_INET6 ||
@@ -7529,94 +6425,6 @@ port_binds_ipv6(const port_cfg_t *port)
&& !port->server_cfg.bind_ipv4_only);
}
-/** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal
- * consistency and warn as appropriate. Set *<b>n_low_ports_out</b> to the
- * number of sub-1024 ports we will be binding. */
-static int
-check_server_ports(const smartlist_t *ports,
- const or_options_t *options,
- int *n_low_ports_out)
-{
- int n_orport_advertised = 0;
- int n_orport_advertised_ipv4 = 0;
- int n_orport_listeners = 0;
- int n_dirport_advertised = 0;
- int n_dirport_listeners = 0;
- int n_low_port = 0;
- int r = 0;
-
- SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
- if (port->type == CONN_TYPE_DIR_LISTENER) {
- if (! port->server_cfg.no_advertise)
- ++n_dirport_advertised;
- if (! port->server_cfg.no_listen)
- ++n_dirport_listeners;
- } else if (port->type == CONN_TYPE_OR_LISTENER) {
- if (! port->server_cfg.no_advertise) {
- ++n_orport_advertised;
- if (port_binds_ipv4(port))
- ++n_orport_advertised_ipv4;
- }
- if (! port->server_cfg.no_listen)
- ++n_orport_listeners;
- } else {
- continue;
- }
-#ifndef _WIN32
- if (!port->server_cfg.no_listen && port->port < 1024)
- ++n_low_port;
-#endif
- } SMARTLIST_FOREACH_END(port);
-
- if (n_orport_advertised && !n_orport_listeners) {
- log_warn(LD_CONFIG, "We are advertising an ORPort, but not actually "
- "listening on one.");
- r = -1;
- }
- if (n_orport_listeners && !n_orport_advertised) {
- log_warn(LD_CONFIG, "We are listening on an ORPort, but not advertising "
- "any ORPorts. This will keep us from building a %s "
- "descriptor, and make us impossible to use.",
- options->BridgeRelay ? "bridge" : "router");
- r = -1;
- }
- if (n_dirport_advertised && !n_dirport_listeners) {
- log_warn(LD_CONFIG, "We are advertising a DirPort, but not actually "
- "listening on one.");
- r = -1;
- }
- if (n_dirport_advertised > 1) {
- log_warn(LD_CONFIG, "Can't advertise more than one DirPort.");
- r = -1;
- }
- if (n_orport_advertised && !n_orport_advertised_ipv4 &&
- !options->BridgeRelay) {
- log_warn(LD_CONFIG, "Configured public relay to listen only on an IPv6 "
- "address. Tor needs to listen on an IPv4 address too.");
- r = -1;
- }
-
- if (n_low_port && options->AccountingMax &&
- (!have_capability_support() || options->KeepBindCapabilities == 0)) {
- const char *extra = "";
- if (options->KeepBindCapabilities == 0 && have_capability_support())
- extra = ", and you have disabled KeepBindCapabilities.";
- log_warn(LD_CONFIG,
- "You have set AccountingMax to use hibernation. You have also "
- "chosen a low DirPort or OrPort%s."
- "This combination can make Tor stop "
- "working when it tries to re-attach the port after a period of "
- "hibernation. Please choose a different port or turn off "
- "hibernation unless you know this combination will work on your "
- "platform.", extra);
- }
-
- if (n_low_ports_out)
- *n_low_ports_out = n_low_port;
-
- return r;
-}
-
/** Return a list of port_cfg_t for client ports parsed from the
* options. */
MOCK_IMPL(const smartlist_t *,
@@ -7986,7 +6794,7 @@ get_num_cpus(const or_options_t *options)
static void
init_libevent(const or_options_t *options)
{
- tor_libevent_cfg cfg;
+ tor_libevent_cfg_t cfg;
tor_assert(options);
@@ -8095,43 +6903,6 @@ write_to_data_subdir(const char* subdir, const char* fname,
return return_val;
}
-/** Return a smartlist of ports that must be forwarded by
- * tor-fw-helper. The smartlist contains the ports in a string format
- * that is understandable by tor-fw-helper. */
-smartlist_t *
-get_list_of_ports_to_forward(void)
-{
- smartlist_t *ports_to_forward = smartlist_new();
- int port = 0;
-
- /** XXX TODO tor-fw-helper does not support forwarding ports to
- other hosts than the local one. If the user is binding to a
- different IP address, tor-fw-helper won't work. */
- port = router_get_advertised_or_port(get_options()); /* Get ORPort */
- if (port)
- smartlist_add_asprintf(ports_to_forward, "%d:%d", port, port);
-
- port = router_get_advertised_dir_port(get_options(), 0); /* Get DirPort */
- if (port)
- smartlist_add_asprintf(ports_to_forward, "%d:%d", port, port);
-
- /* Get ports of transport proxies */
- {
- smartlist_t *transport_ports = get_transport_proxy_ports();
- if (transport_ports) {
- smartlist_add_all(ports_to_forward, transport_ports);
- smartlist_free(transport_ports);
- }
- }
-
- if (!smartlist_len(ports_to_forward)) {
- smartlist_free(ports_to_forward);
- ports_to_forward = NULL;
- }
-
- return ports_to_forward;
-}
-
/** Helper to implement GETINFO functions about configuration variables (not
* their values). Given a "config/names" question, set *<b>answer</b> to a
* new string describing the supported configuration variables and their
diff --git a/src/app/config/config.h b/src/app/config/config.h
index 44f09e5ee9..17caa0e3ff 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@
#include "app/config/or_options_st.h"
#include "lib/testsupport/testsupport.h"
+#include "app/config/quiet_level.h"
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(DARWIN)
#define KERNEL_MAY_SUPPORT_IPFW
@@ -30,7 +31,6 @@
#define MAX_DEFAULT_MEMORY_QUEUE_SIZE (UINT64_C(2) << 30)
#endif
-MOCK_DECL(const char*, get_dirportfrontpage, (void));
MOCK_DECL(const or_options_t *, get_options, (void));
MOCK_DECL(or_options_t *, get_options_mutable, (void));
int set_options(or_options_t *new_val, char **msg);
@@ -42,6 +42,8 @@ const char *escaped_safe_str(const char *address);
void init_protocol_warning_severity_level(void);
int get_protocol_warning_severity_level(void);
+#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level())
+
/** An error from options_trial_assign() or options_init_from_string(). */
typedef enum setopt_err_t {
SETOPT_OK = 0,
@@ -53,12 +55,6 @@ typedef enum setopt_err_t {
setopt_err_t options_trial_assign(struct config_line_t *list, unsigned flags,
char **msg);
-uint32_t get_last_resolved_addr(void);
-void reset_last_resolved_addr(void);
-int resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out);
-MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
void options_init(or_options_t *options);
#define OPTIONS_DUMP_MINIMAL 1
@@ -162,6 +158,8 @@ int write_to_data_subdir(const char* subdir, const char* fname,
int get_num_cpus(const or_options_t *options);
MOCK_DECL(const smartlist_t *,get_configured_ports,(void));
+int port_binds_ipv4(const port_cfg_t *port);
+int port_binds_ipv6(const port_cfg_t *port);
int get_first_advertised_port_by_type_af(int listener_type,
int address_family);
#define get_primary_or_port() \
@@ -180,26 +178,36 @@ char *get_first_listener_addrport_string(int listener_type);
int options_need_geoip_info(const or_options_t *options,
const char **reason_out);
-smartlist_t *get_list_of_ports_to_forward(void);
-
int getinfo_helper_config(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
-uint32_t get_effective_bwrate(const or_options_t *options);
-uint32_t get_effective_bwburst(const or_options_t *options);
-
-char *get_transport_bindaddr_from_config(const char *transport);
-
int init_cookie_authentication(const char *fname, const char *header,
int cookie_len, int group_readable,
uint8_t **cookie_out, int *cookie_is_set_out);
or_options_t *options_new(void);
-int config_parse_commandline(int argc, char **argv, int ignore_errors,
- struct config_line_t **result,
- struct config_line_t **cmdline_result);
+/** Options settings parsed from the command-line. */
+typedef struct {
+ /** List of options that can only be set from the command-line */
+ struct config_line_t *cmdline_opts;
+ /** List of other options, to be handled by the general Tor configuration
+ system. */
+ struct config_line_t *other_opts;
+ /** Subcommand that Tor has been told to run */
+ tor_cmdline_mode_t command;
+ /** Argument for the command mode, if any. */
+ const char *command_arg;
+ /** How quiet have we been told to be? */
+ quiet_level_t quiet_level;
+} parsed_cmdline_t;
+
+parsed_cmdline_t *config_parse_commandline(int argc, char **argv,
+ int ignore_errors);
+void parsed_cmdline_free_(parsed_cmdline_t *cmdline);
+#define parsed_cmdline_free(c) \
+ FREE_AND_NULL(parsed_cmdline_t, parsed_cmdline_free_, (c))
void config_register_addressmaps(const or_options_t *options);
/* XXXX move to connection_edge.h */
@@ -228,14 +236,16 @@ void bridge_line_free_(bridge_line_t *bridge_line);
#define bridge_line_free(line) \
FREE_AND_NULL(bridge_line_t, bridge_line_free_, (line))
bridge_line_t *parse_bridge_line(const char *line);
-smartlist_t *get_options_from_transport_options_line(const char *line,
- const char *transport);
-smartlist_t *get_options_for_server_transport(const char *transport);
/* Port helper functions. */
int options_any_client_port_set(const or_options_t *options);
-
-#ifdef CONFIG_PRIVATE
+int port_parse_config(smartlist_t *out,
+ const struct config_line_t *ports,
+ const char *portname,
+ int listener_type,
+ const char *defaultaddr,
+ int defaultport,
+ const unsigned flags);
#define CL_PORT_NO_STREAM_OPTIONS (1u<<0)
#define CL_PORT_WARN_NONLOCAL (1u<<1)
@@ -246,26 +256,34 @@ int options_any_client_port_set(const or_options_t *options);
#define CL_PORT_IS_UNIXSOCKET (1u<<6)
#define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7)
-STATIC int options_act(const or_options_t *old_options);
+port_cfg_t *port_cfg_new(size_t namelen);
+#define port_cfg_free(port) \
+ FREE_AND_NULL(port_cfg_t, port_cfg_free_, (port))
+void port_cfg_free_(port_cfg_t *port);
+
+int port_count_real_listeners(const smartlist_t *ports,
+ int listenertype,
+ int count_sockets);
+int pt_parse_transport_line(const or_options_t *options,
+ const char *line, int validate_only,
+ int server);
+int config_ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg);
+
+#ifdef CONFIG_PRIVATE
+
+MOCK_DECL(STATIC int, options_act,(const or_options_t *old_options));
+MOCK_DECL(STATIC int, options_act_reversible,(const or_options_t *old_options,
+ char **msg));
struct config_mgr_t;
STATIC const struct config_mgr_t *get_options_mgr(void);
-STATIC port_cfg_t *port_cfg_new(size_t namelen);
-#define port_cfg_free(port) \
- FREE_AND_NULL(port_cfg_t, port_cfg_free_, (port))
-STATIC void port_cfg_free_(port_cfg_t *port);
#define or_options_free(opt) \
FREE_AND_NULL(or_options_t, or_options_free_, (opt))
STATIC void or_options_free_(or_options_t *options);
STATIC int options_validate_single_onion(or_options_t *options,
char **msg);
-STATIC int options_validate(or_options_t *old_options,
- or_options_t *options,
- or_options_t *default_options,
- int from_setconf, char **msg);
-STATIC int parse_transport_line(const or_options_t *options,
- const char *line, int validate_only,
- int server);
+STATIC int parse_tcp_proxy_line(const char *line, or_options_t *options,
+ char **msg);
STATIC int consider_adding_dir_servers(const or_options_t *options,
const or_options_t *old_options);
STATIC void add_default_trusted_dir_authorities(dirinfo_type_t type);
@@ -274,23 +292,32 @@ STATIC int parse_dir_authority_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
STATIC int parse_dir_fallback_line(const char *line, int validate_only);
-STATIC int have_enough_mem_for_dircache(const or_options_t *options,
- size_t total_mem, char **msg);
-STATIC int parse_port_config(smartlist_t *out,
- const struct config_line_t *ports,
- const char *portname,
- int listener_type,
- const char *defaultaddr,
- int defaultport,
- const unsigned flags);
-
-STATIC int check_bridge_distribution_setting(const char *bd);
STATIC uint64_t compute_real_max_mem_in_queues(const uint64_t val,
int log_guess);
STATIC int open_and_add_file_log(const log_severity_list_t *severity,
const char *fname,
int truncate_log);
+STATIC int options_init_logs(const or_options_t *old_options,
+ const or_options_t *options, int validate_only);
+
+STATIC int options_create_directories(char **msg_out);
+struct log_transaction_t;
+STATIC struct log_transaction_t *options_start_log_transaction(
+ const or_options_t *old_options,
+ char **msg_out);
+STATIC void options_commit_log_transaction(struct log_transaction_t *xn);
+STATIC void options_rollback_log_transaction(struct log_transaction_t *xn);
+
+#ifdef TOR_UNIT_TESTS
+int options_validate(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg);
+#endif
+
+STATIC int parse_ports(or_options_t *options, int validate_only,
+ char **msg, int *n_ports_out,
+ int *world_writable_control_socket);
#endif /* defined(CONFIG_PRIVATE) */
diff --git a/src/app/config/include.am b/src/app/config/include.am
new file mode 100644
index 0000000000..14320a6b11
--- /dev/null
+++ b/src/app/config/include.am
@@ -0,0 +1,23 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/app/config/config.c \
+ src/app/config/quiet_level.c \
+ src/app/config/resolve_addr.c \
+ src/app/config/statefile.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/app/config/config.h \
+ src/app/config/or_options_st.h \
+ src/app/config/or_state_st.h \
+ src/app/config/quiet_level.h \
+ src/app/config/resolve_addr.h \
+ src/app/config/statefile.h \
+ src/app/config/tor_cmdline_mode.h
+
+
+noinst_HEADERS += \
+ src/app/config/auth_dirs.inc \
+ src/app/config/fallback_dirs.inc \
+ src/app/config/testnet.inc
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index e6be797017..bf58205f89 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,12 +13,15 @@
#ifndef TOR_OR_OPTIONS_ST_H
#define TOR_OR_OPTIONS_ST_H
+#include "core/or/or.h"
#include "lib/cc/torint.h"
#include "lib/net/address.h"
+#include "app/config/tor_cmdline_mode.h"
struct smartlist_t;
struct config_line_t;
struct config_suite_t;
+struct routerset_t;
/** Enumeration of outbound address configuration types:
* Exit-only, OR-only, or both */
@@ -26,17 +29,18 @@ typedef enum {OUTBOUND_ADDR_EXIT, OUTBOUND_ADDR_OR,
OUTBOUND_ADDR_EXIT_AND_OR,
OUTBOUND_ADDR_MAX} outbound_addr_t;
+/** Which protocol to use for TCPProxy. */
+typedef enum {
+ /** Use the HAProxy proxy protocol. */
+ TCP_PROXY_PROTOCOL_HAPROXY
+} tcp_proxy_protocol_t;
+
/** Configuration options for a Tor process. */
struct or_options_t {
uint32_t magic_;
/** What should the tor process actually do? */
- enum {
- CMD_RUN_TOR=0, CMD_LIST_FINGERPRINT, CMD_HASH_PASSWORD,
- CMD_VERIFY_CONFIG, CMD_RUN_UNITTESTS, CMD_DUMP_CONFIG,
- CMD_KEYGEN,
- CMD_KEY_EXPIRATION,
- } command;
+ tor_cmdline_mode_t command;
char *command_arg; /**< Argument for command-line option. */
struct config_line_t *Logs; /**< New-style list of configuration lines
@@ -70,28 +74,29 @@ struct or_options_t {
char *Address; /**< OR only: configured address for this onion router. */
char *PidFile; /**< Where to store PID of Tor process. */
- routerset_t *ExitNodes; /**< Structure containing nicknames, digests,
+ struct routerset_t *ExitNodes; /**< Structure containing nicknames, digests,
* country codes and IP address patterns of ORs to
* consider as exits. */
- routerset_t *MiddleNodes; /**< Structure containing nicknames, digests,
- * country codes and IP address patterns of ORs to
- * consider as middles. */
- routerset_t *EntryNodes;/**< Structure containing nicknames, digests,
+ struct routerset_t *MiddleNodes; /**< Structure containing nicknames,
+ * digests, country codes and IP address patterns
+ * of ORs to consider as middles. */
+ struct routerset_t *EntryNodes;/**< Structure containing nicknames, digests,
* country codes and IP address patterns of ORs to
* consider as entry points. */
int StrictNodes; /**< Boolean: When none of our EntryNodes or ExitNodes
* are up, or we need to access a node in ExcludeNodes,
* do we just fail instead? */
- routerset_t *ExcludeNodes;/**< Structure containing nicknames, digests,
- * country codes and IP address patterns of ORs
- * not to use in circuits. But see StrictNodes
- * above. */
- routerset_t *ExcludeExitNodes;/**< Structure containing nicknames, digests,
- * country codes and IP address patterns of
- * ORs not to consider as exits. */
+ struct routerset_t *ExcludeNodes;/**< Structure containing nicknames,
+ * digests, country codes and IP address patterns
+ * of ORs not to use in circuits. But see
+ * StrictNodes above. */
+ struct routerset_t *ExcludeExitNodes;/**< Structure containing nicknames,
+ * digests, country codes and IP address
+ * patterns of ORs not to consider as
+ * exits. */
/** Union of ExcludeNodes and ExcludeExitNodes */
- routerset_t *ExcludeExitNodesUnion_;
+ struct routerset_t *ExcludeExitNodesUnion_;
int DisableAllSwap; /**< Boolean: Attempt to call mlockall() on our
* process for all current and future memory. */
@@ -117,11 +122,6 @@ struct or_options_t {
* [][0] is IPv4, [][1] is IPv6
*/
tor_addr_t OutboundBindAddresses[OUTBOUND_ADDR_MAX][2];
- /** Directory server only: which versions of
- * Tor should we tell users to run? */
- struct config_line_t *RecommendedVersions;
- struct config_line_t *RecommendedClientVersions;
- struct config_line_t *RecommendedServerVersions;
/** Whether dirservers allow router descriptors with private IPs. */
int DirAllowPrivateAddresses;
/** Whether routers accept EXTEND cells to routers with private IPs. */
@@ -196,9 +196,6 @@ struct or_options_t {
int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
int V3AuthoritativeDir; /**< Boolean: is this an authoritative directory
* for version 3 directories? */
- int VersioningAuthoritativeDir; /**< Boolean: is this an authoritative
- * directory that's willing to recommend
- * versions? */
int BridgeAuthoritativeDir; /**< Boolean: is this an authoritative directory
* that aggregates bridge descriptors? */
@@ -269,20 +266,17 @@ struct or_options_t {
int FetchServerDescriptors; /**< Do we fetch server descriptors as normal? */
int FetchHidServDescriptors; /**< and hidden service descriptors? */
- int MinUptimeHidServDirectoryV2; /**< As directory authority, accept hidden
- * service directories after what time? */
-
int FetchUselessDescriptors; /**< Do we fetch non-running descriptors too? */
int AllDirActionsPrivate; /**< Should every directory action be sent
* through a Tor circuit? */
/** A routerset that should be used when picking middle nodes for HS
* circuits. */
- routerset_t *HSLayer2Nodes;
+ struct routerset_t *HSLayer2Nodes;
/** A routerset that should be used when picking third-hop nodes for HS
* circuits. */
- routerset_t *HSLayer3Nodes;
+ struct routerset_t *HSLayer3Nodes;
/** Onion Services in HiddenServiceSingleHopMode make one-hop (direct)
* circuits between the onion service server, and the introduction and
@@ -423,6 +417,11 @@ struct or_options_t {
char *Socks5ProxyUsername; /**< Username for SOCKS5 authentication, if any */
char *Socks5ProxyPassword; /**< Password for SOCKS5 authentication, if any */
+ char *TCPProxy; /**< protocol and hostname:port to use as a proxy, if any. */
+ tcp_proxy_protocol_t TCPProxyProtocol; /**< Derived from TCPProxy. */
+ tor_addr_t TCPProxyAddr; /**< Derived from TCPProxy. */
+ uint16_t TCPProxyPort; /**< Derived from TCPProxy. */
+
/** List of configuration lines for replacement directory authorities.
* If you just want to replace one class of authority at a time,
* use the "Alternate*Authority" options below instead. */
@@ -469,21 +468,6 @@ struct or_options_t {
struct smartlist_t *AuthDirRejectCCs;
/**@}*/
- int AuthDirListBadExits; /**< True iff we should list bad exits,
- * and vote for all other exits as good. */
- int AuthDirMaxServersPerAddr; /**< Do not permit more than this
- * number of servers per IP address. */
- int AuthDirHasIPv6Connectivity; /**< Boolean: are we on IPv6? */
- int AuthDirPinKeys; /**< Boolean: Do we enforce key-pinning? */
-
- /** If non-zero, always vote the Fast flag for any relay advertising
- * this amount of capacity or more. */
- uint64_t AuthDirFastGuarantee;
-
- /** If non-zero, this advertised capacity or more is always sufficient
- * to satisfy the bandwidth requirement for the Guard flag. */
- uint64_t AuthDirGuardBWGuarantee;
-
char *AccountingStart; /**< How long is the accounting interval, and when
* does it start? */
uint64_t AccountingMax; /**< How many bytes do we allow per accounting
@@ -540,12 +524,8 @@ struct or_options_t {
* protocol, is it a warn or an info in our logs? */
int TestSocks; /**< Boolean: when we get a socks connection, do we loudly
* log whether it was DNS-leaking or not? */
- int HardwareAccel; /**< Boolean: Should we enable OpenSSL hardware
- * acceleration where available? */
/** Token Bucket Refill resolution in milliseconds. */
int TokenBucketRefillInterval;
- char *AccelName; /**< Optional hardware acceleration engine name. */
- char *AccelDir; /**< Optional hardware acceleration engine search dir. */
/** Boolean: Do we try to enter from a smallish number
* of fixed nodes? */
@@ -577,7 +557,9 @@ struct or_options_t {
int DirCache; /**< Cache all directory documents and accept requests via
* tunnelled dir conns from clients. If 1, enabled (default);
- * If 0, disabled. */
+ * If 0, disabled. Use dir_server_mode() rather than
+ * referencing this option directly. (Except for routermode
+ * and relay_config, which do direct checks.) */
char *VirtualAddrNetworkIPv4; /**< Address and mask to hand out for virtual
* MAPADDRESS requests for IPv4 addresses */
@@ -680,9 +662,6 @@ struct or_options_t {
* accessing this value directly. */
int ClientPreferIPv6DirPort;
- /** If true, prefer an IPv4 or IPv6 OR port at random. */
- int ClientAutoIPv6ORPort;
-
/** The length of time that we think a consensus should be fresh. */
int V3AuthVotingInterval;
/** The length of time we think it will take to distribute votes. */
@@ -702,14 +681,6 @@ struct or_options_t {
/** Location of guardfraction file */
char *GuardfractionFile;
- /** Authority only: key=value pairs that we add to our networkstatus
- * consensus vote on the 'params' line. */
- char *ConsensusParams;
-
- /** Authority only: minimum number of measured bandwidths we must see
- * before we only believe measured bandwidths to assign flags. */
- int MinMeasuredBWsForAuthToIgnoreAdvertised;
-
/** The length of time that we think an initial consensus should be fresh.
* Only altered on testing networks. */
int TestingV3AuthInitialVotingInterval;
@@ -726,16 +697,6 @@ struct or_options_t {
voting. Only altered on testing networks. */
int TestingV3AuthVotingStartOffset;
- /** 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. */
- int TestingAuthDirTimeToLearnReachability;
-
- /** Clients don't download any descriptor this recent, since it will
- * probably not have propagated to enough caches. Only altered on testing
- * networks. */
- int TestingEstimatedDescriptorPropagationTime;
-
/** Schedule for when servers should download things in general. Only
* altered on testing networks. */
int TestingServerDownloadInitialDelay;
@@ -809,27 +770,6 @@ struct or_options_t {
* of certain configuration options. */
int TestingTorNetwork;
- /** Minimum value for the Exit flag threshold on testing networks. */
- uint64_t TestingMinExitFlagThreshold;
-
- /** Minimum value for the Fast flag threshold on testing networks. */
- uint64_t TestingMinFastFlagThreshold;
-
- /** Relays in a testing network which should be voted Exit
- * regardless of exit policy. */
- routerset_t *TestingDirAuthVoteExit;
- int TestingDirAuthVoteExitIsStrict;
-
- /** Relays in a testing network which should be voted Guard
- * regardless of uptime and bandwidth. */
- routerset_t *TestingDirAuthVoteGuard;
- int TestingDirAuthVoteGuardIsStrict;
-
- /** Relays in a testing network which should be voted HSDir
- * regardless of uptime and DirPort. */
- routerset_t *TestingDirAuthVoteHSDir;
- int TestingDirAuthVoteHSDirIsStrict;
-
/** Enable CONN_BW events. Only altered on testing networks. */
int TestingEnableConnBwEvent;
@@ -854,7 +794,7 @@ struct or_options_t {
* to make this false. */
int ReloadTorrcOnSIGHUP;
- /* The main parameter for picking circuits within a connection.
+ /** The main parameter for picking circuits within a connection.
*
* If this value is positive, when picking a cell to relay on a connection,
* we always relay from the circuit whose weighted cell count is lowest.
@@ -1008,19 +948,6 @@ struct or_options_t {
*/
uint64_t MaxUnparseableDescSizeToLog;
- /** Bool (default: 1): Under bandwidth pressure, if set to 1, the authority
- * will always answer directory requests from relays but will start sending
- * 503 error code for the other connections. If set to 0, all connections
- * are considered the same and the authority will try to answer them all
- * regardless of bandwidth pressure or not. */
- int AuthDirRejectRequestsUnderLoad;
-
- /** Bool (default: 1): Switch for the shared random protocol. Only
- * relevant to a directory authority. If off, the authority won't
- * participate in the protocol. If on (default), a flag is added to the
- * vote indicating participation. */
- int AuthDirSharedRandomness;
-
/** If 1, we skip all OOS checks. */
int DisableOOSCheck;
@@ -1028,11 +955,6 @@ struct or_options_t {
* If -1, we should do whatever the consensus parameter says. */
int ExtendByEd25519ID;
- /** Bool (default: 1): When testing routerinfos as a directory authority,
- * do we enforce Ed25519 identity match? */
- /* NOTE: remove this option someday. */
- int AuthDirTestEd25519LinkKeys;
-
/** Bool (default: 0): Tells if a %include was used on torrc */
int IncludeUsed;
@@ -1057,7 +979,7 @@ struct or_options_t {
/** The list of scheduler type string ordered by priority that is first one
* has to be tried first. Default: KIST,KISTLite,Vanilla */
struct smartlist_t *Schedulers;
- /* An ordered list of scheduler_types mapped from Schedulers. */
+ /** An ordered list of scheduler_types mapped from Schedulers. */
struct smartlist_t *SchedulerTypes_;
/** List of files that were opened by %include in torrc and torrc-defaults */
diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h
index 225003bb7e..8c4e9d5e61 100644
--- a/src/app/config/or_state_st.h
+++ b/src/app/config/or_state_st.h
@@ -1,11 +1,11 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file or_state_t
+ * \file or_state_st.h
*
* \brief The or_state_t structure, which represents Tor's state file.
*/
@@ -89,13 +89,6 @@ struct or_state_t {
/** When did we last rotate our onion key? "0" for 'no idea'. */
time_t LastRotatedOnionKey;
- /** Number of minutes since the last user-initiated request (as defined by
- * the dormant net-status system.) Set to zero if we are dormant. */
- int MinutesSinceUserActivity;
- /** True if we were dormant when we last wrote the file; false if we
- * weren't. "auto" on initial startup. */
- int Dormant;
-
/**
* State objects for individual modules.
*
diff --git a/src/app/config/quiet_level.c b/src/app/config/quiet_level.c
new file mode 100644
index 0000000000..e04faaef3a
--- /dev/null
+++ b/src/app/config/quiet_level.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file quiet_level.c
+ * @brief Code to handle default logging level (quiet/hush/normal).
+ **/
+
+#include "orconfig.h"
+#include "lib/log/log.h"
+#include "app/config/quiet_level.h"
+
+/** Decides our behavior when no logs are configured/before any logs have been
+ * configured. For QUIET_NONE, we log notice to stdout as normal. For
+ * QUIET_HUSH, we log warnings only. For QUIET_SILENT, we log nothing.
+ */
+quiet_level_t quiet_level = 0;
+
+/** Add a default log (or not), depending on the value of <b>quiet</b>. */
+void
+add_default_log_for_quiet_level(quiet_level_t quiet)
+{
+ switch (quiet) {
+ case QUIET_SILENT:
+ /* --quiet: no initial logging */
+ return;
+ case QUIET_HUSH:
+ /* --hush: log at warning or higher. */
+ add_default_log(LOG_WARN);
+ break;
+ case QUIET_NONE: FALLTHROUGH;
+ default:
+ add_default_log(LOG_NOTICE);
+ }
+}
diff --git a/src/app/config/quiet_level.h b/src/app/config/quiet_level.h
new file mode 100644
index 0000000000..3a630b90e7
--- /dev/null
+++ b/src/app/config/quiet_level.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2001 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 quiet_level.h
+ * \brief Declare the quiet_level enumeration and global.
+ **/
+
+#ifndef QUIET_LEVEL_H
+#define QUIET_LEVEL_H
+
+/** Enumeration to define how quietly Tor should log at startup. */
+typedef enum {
+ /** Default quiet level: we log everything of level NOTICE or higher. */
+ QUIET_NONE = 0,
+ /** "--hush" quiet level: we log everything of level WARNING or higher. */
+ QUIET_HUSH = 1 ,
+ /** "--quiet" quiet level: we log nothing at all. */
+ QUIET_SILENT = 2
+} quiet_level_t;
+
+/** How quietly should Tor log at startup? */
+extern quiet_level_t quiet_level;
+
+void add_default_log_for_quiet_level(quiet_level_t quiet);
+
+#endif /* !defined(QUIET_LEVEL_H) */
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
new file mode 100644
index 0000000000..9d1a8e0260
--- /dev/null
+++ b/src/app/config/resolve_addr.c
@@ -0,0 +1,314 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file resolve_addr.c
+ * \brief Implement resolving address functions
+ **/
+
+#define RESOLVE_ADDR_PRIVATE
+
+#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
+
+#include "core/mainloop/mainloop.h"
+
+#include "feature/control/control_events.h"
+
+#include "lib/net/gethostname.h"
+#include "lib/net/resolve.h"
+
+/** Last value actually set by resolve_my_address. */
+static uint32_t last_resolved_addr = 0;
+
+/** Accessor for last_resolved_addr from outside this file. */
+uint32_t
+get_last_resolved_addr(void)
+{
+ return last_resolved_addr;
+}
+
+/** Reset last_resolved_addr from outside this file. */
+void
+reset_last_resolved_addr(void)
+{
+ last_resolved_addr = 0;
+}
+
+/**
+ * Attempt getting our non-local (as judged by tor_addr_is_internal()
+ * function) IP address using following techniques, listed in
+ * order from best (most desirable, try first) to worst (least
+ * desirable, try if everything else fails).
+ *
+ * First, attempt using <b>options-\>Address</b> to get our
+ * non-local IP address.
+ *
+ * If <b>options-\>Address</b> represents a non-local IP address,
+ * consider it ours.
+ *
+ * If <b>options-\>Address</b> is a DNS name that resolves to
+ * a non-local IP address, consider this IP address ours.
+ *
+ * If <b>options-\>Address</b> is NULL, fall back to getting local
+ * hostname and using it in above-described ways to try and
+ * get our IP address.
+ *
+ * In case local hostname cannot be resolved to a non-local IP
+ * address, try getting an IP address of network interface
+ * in hopes it will be non-local one.
+ *
+ * Fail if one or more of the following is true:
+ * - DNS name in <b>options-\>Address</b> cannot be resolved.
+ * - <b>options-\>Address</b> is a local host address.
+ * - Attempt at getting local hostname fails.
+ * - Attempt at getting network interface address fails.
+ *
+ * Return 0 if all is well, or -1 if we can't find a suitable
+ * public IP address.
+ *
+ * If we are returning 0:
+ * - Put our public IP address (in host order) into *<b>addr_out</b>.
+ * - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
+ * string describing how we arrived at our answer.
+ * - "CONFIGURED" - parsed from IP address string in
+ * <b>options-\>Address</b>
+ * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
+ * - "GETHOSTNAME" - resolved from a local hostname.
+ * - "INTERFACE" - retrieved from a network interface.
+ * - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
+ * get our address, set *<b>hostname_out</b> to a newly allocated string
+ * holding that hostname. (If we didn't get our address by resolving a
+ * hostname, set *<b>hostname_out</b> to NULL.)
+ *
+ * XXXX ipv6
+ */
+int
+resolve_my_address(int warn_severity, const or_options_t *options,
+ uint32_t *addr_out,
+ const char **method_out, char **hostname_out)
+{
+ struct in_addr in;
+ uint32_t addr; /* host order */
+ char hostname[256];
+ const char *method_used;
+ const char *hostname_used;
+ int explicit_ip=1;
+ int explicit_hostname=1;
+ int from_interface=0;
+ char *addr_string = NULL;
+ const char *address = options->Address;
+ int notice_severity = warn_severity <= LOG_NOTICE ?
+ LOG_NOTICE : warn_severity;
+
+ tor_addr_t myaddr;
+ tor_assert(addr_out);
+
+ /*
+ * Step one: Fill in 'hostname' to be our best guess.
+ */
+
+ if (address && *address) {
+ strlcpy(hostname, address, sizeof(hostname));
+ log_debug(LD_CONFIG, "Trying configured Address '%s' as local hostname",
+ hostname);
+ } else { /* then we need to guess our address */
+ explicit_ip = 0; /* it's implicit */
+ explicit_hostname = 0; /* it's implicit */
+
+ if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
+ log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
+ return -1;
+ }
+ log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname);
+ }
+
+ /*
+ * Step two: Now that we know 'hostname', parse it or resolve it. If
+ * it doesn't parse or resolve, look at the interface address. Set 'addr'
+ * to be our (host-order) 32-bit answer.
+ */
+
+ if (tor_inet_aton(hostname, &in) == 0) {
+ /* then we have to resolve it */
+ log_debug(LD_CONFIG, "Local hostname '%s' is DNS address. "
+ "Trying to resolve to IP address.", hostname);
+ explicit_ip = 0;
+ if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */
+ uint32_t interface_ip; /* host order */
+
+ if (explicit_hostname) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not resolve local Address '%s'. Failing.", hostname);
+ return -1;
+ }
+ log_fn(notice_severity, LD_CONFIG,
+ "Could not resolve guessed local hostname '%s'. "
+ "Trying something else.", hostname);
+ if (get_interface_address(warn_severity, &interface_ip)) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address. Failing.");
+ return -1;
+ }
+ from_interface = 1;
+ addr = interface_ip;
+ log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
+ "local interface. Using that.", fmt_addr32(addr));
+ strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
+ } else { /* resolved hostname into addr */
+ tor_addr_from_ipv4h(&myaddr, addr);
+
+ if (!explicit_hostname &&
+ tor_addr_is_internal(&myaddr, 0)) {
+ tor_addr_t interface_ip;
+
+ log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
+ "resolves to a private IP address (%s). Trying something "
+ "else.", hostname, fmt_addr32(addr));
+
+ if (get_interface_address6(warn_severity, AF_INET, &interface_ip)<0) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address. Too bad.");
+ } else if (tor_addr_is_internal(&interface_ip, 0)) {
+ log_fn(notice_severity, LD_CONFIG,
+ "Interface IP address '%s' is a private address too. "
+ "Ignoring.", fmt_addr(&interface_ip));
+ } else {
+ from_interface = 1;
+ addr = tor_addr_to_ipv4h(&interface_ip);
+ log_fn(notice_severity, LD_CONFIG,
+ "Learned IP address '%s' for local interface."
+ " Using that.", fmt_addr32(addr));
+ strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
+ }
+ }
+ }
+ } else {
+ log_debug(LD_CONFIG, "Local hostname '%s' is already IP address, "
+ "skipping DNS resolution", hostname);
+ addr = ntohl(in.s_addr); /* set addr so that addr_string is not
+ * illformed */
+ }
+
+ /*
+ * Step three: Check whether 'addr' is an internal IP address, and error
+ * out if it is and we don't want that.
+ */
+
+ tor_addr_from_ipv4h(&myaddr,addr);
+
+ addr_string = tor_dup_ip(addr);
+ if (addr_string && tor_addr_is_internal(&myaddr, 0)) {
+ /* make sure we're ok with publishing an internal IP */
+ if (using_default_dir_authorities(options)) {
+ /* if they are using the default authorities, disallow internal IPs
+ * always. For IPv6 ORPorts, this check is done in
+ * router_get_advertised_ipv6_or_ap(). See #33681. */
+ log_fn(warn_severity, LD_CONFIG,
+ "Address '%s' resolves to private IP address '%s'. "
+ "Tor servers that use the default DirAuthorities must have "
+ "public IP addresses.", hostname, addr_string);
+ tor_free(addr_string);
+ return -1;
+ }
+ if (!explicit_ip) {
+ /* even if they've set their own authorities, require an explicit IP if
+ * they're using an internal address. */
+ log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
+ "IP address '%s'. Please set the Address config option to be "
+ "the IP address you want to use.", hostname, addr_string);
+ tor_free(addr_string);
+ return -1;
+ }
+ }
+
+ /*
+ * Step four: We have a winner! 'addr' is our answer for sure, and
+ * 'addr_string' is its string form. Fill out the various fields to
+ * say how we decided it.
+ */
+
+ log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string);
+
+ if (explicit_ip) {
+ method_used = "CONFIGURED";
+ hostname_used = NULL;
+ } else if (explicit_hostname) {
+ method_used = "RESOLVED";
+ hostname_used = hostname;
+ } else if (from_interface) {
+ method_used = "INTERFACE";
+ hostname_used = NULL;
+ } else {
+ method_used = "GETHOSTNAME";
+ hostname_used = hostname;
+ }
+
+ *addr_out = addr;
+ if (method_out)
+ *method_out = method_used;
+ if (hostname_out)
+ *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
+
+ /*
+ * Step five: Check if the answer has changed since last time (or if
+ * there was no last time), and if so call various functions to keep
+ * us up-to-date.
+ */
+
+ if (last_resolved_addr && last_resolved_addr != *addr_out) {
+ /* Leave this as a notice, regardless of the requested severity,
+ * at least until dynamic IP address support becomes bulletproof. */
+ log_notice(LD_NET,
+ "Your IP address seems to have changed to %s "
+ "(METHOD=%s%s%s). Updating.",
+ addr_string, method_used,
+ hostname_used ? " HOSTNAME=" : "",
+ hostname_used ? hostname_used : "");
+ ip_address_changed(0);
+ }
+
+ if (last_resolved_addr != *addr_out) {
+ control_event_server_status(LOG_NOTICE,
+ "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
+ addr_string, method_used,
+ hostname_used ? " HOSTNAME=" : "",
+ hostname_used ? hostname_used : "");
+ }
+ last_resolved_addr = *addr_out;
+
+ /*
+ * And finally, clean up and return success.
+ */
+
+ tor_free(addr_string);
+ return 0;
+}
+
+/** Return true iff <b>addr</b> is judged to be on the same network as us, or
+ * on a private network.
+ */
+MOCK_IMPL(int,
+is_local_addr, (const tor_addr_t *addr))
+{
+ if (tor_addr_is_internal(addr, 0))
+ return 1;
+ /* Check whether ip is on the same /24 as we are. */
+ if (get_options()->EnforceDistinctSubnets == 0)
+ return 0;
+ if (tor_addr_family(addr) == AF_INET) {
+ uint32_t ip = tor_addr_to_ipv4h(addr);
+
+ /* It's possible that this next check will hit before the first time
+ * resolve_my_address actually succeeds. (For clients, it is likely that
+ * resolve_my_address will never be called at all). In those cases,
+ * last_resolved_addr will be 0, and so checking to see whether ip is on
+ * the same /24 as last_resolved_addr will be the same as checking whether
+ * it was on net 0, which is already done by tor_addr_is_internal.
+ */
+ if ((last_resolved_addr & (uint32_t)0xffffff00ul)
+ == (ip & (uint32_t)0xffffff00ul))
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h
new file mode 100644
index 0000000000..3747546402
--- /dev/null
+++ b/src/app/config/resolve_addr.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file resolve_addr.h
+ * \brief Header file for resolve_addr.c.
+ **/
+
+#ifndef TOR_CONFIG_RESOLVE_ADDR_H
+#define TOR_CONFIG_RESOLVE_ADDR_H
+
+#include "app/config/or_options_st.h"
+
+int resolve_my_address(int warn_severity, const or_options_t *options,
+ uint32_t *addr_out,
+ const char **method_out, char **hostname_out);
+
+uint32_t get_last_resolved_addr(void);
+void reset_last_resolved_addr(void);
+
+MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
+
+#ifdef RESOLVE_ADDR_PRIVATE
+
+#endif /* RESOLVE_ADDR_PRIVATE */
+
+#endif /* TOR_CONFIG_RESOLVE_ADDR_H */
+
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index 552bd2c443..dcc55f1898 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,7 +12,7 @@
*
* This 'state' file is a typed key-value store that allows multiple
* entries for the same key. It follows the same metaformat as described
- * in confparse.c, and uses the same code to read and write itself.
+ * in confmgt.c, and uses the same code to read and write itself.
*
* The state file is most suitable for small values that don't change too
* frequently. For values that become very large, we typically use a separate
@@ -32,7 +32,8 @@
#include "core/or/or.h"
#include "core/or/circuitstats.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "feature/relay/transport_config.h"
+#include "lib/confmgt/confmgt.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
#include "core/mainloop/connection.h"
@@ -44,6 +45,7 @@
#include "feature/relay/routermode.h"
#include "lib/sandbox/sandbox.h"
#include "app/config/statefile.h"
+#include "app/main/subsysmgr.h"
#include "lib/encoding/confline.h"
#include "lib/net/resolve.h"
#include "lib/version/torversion.h"
@@ -76,6 +78,7 @@ DUMMY_TYPECHECK_INSTANCE(or_state_t);
VAR(#member, conftype, member, initvalue)
/** Array of "state" variables saved to the ~/.tor/state file. */
+// clang-format off
static const config_var_t state_vars_[] = {
/* Remember to document these in state-contents.txt ! */
@@ -130,20 +133,17 @@ static const config_var_t state_vars_[] = {
VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
- V(MinutesSinceUserActivity, POSINT, NULL),
- V(Dormant, AUTOBOOL, "auto"),
-
END_OF_CONFIG_VARS
};
+// clang-format on
#undef VAR
#undef V
static int or_state_validate(or_state_t *state, char **msg);
-static int or_state_validate_cb(void *old_options, void *options,
- void *default_options,
- int from_setconf, char **msg);
+static int or_state_validate_cb(const void *old_options,
+ void *options, char **msg);
/** Magic value for or_state_t. */
#define OR_STATE_MAGIC 0x57A73f57
@@ -158,35 +158,40 @@ static struct_member_t state_extra_var = {
/** Configuration format for or_state_t. */
static const config_format_t state_format = {
- sizeof(or_state_t),
- {
+ .size = sizeof(or_state_t),
+ .magic = {
"or_state_t",
OR_STATE_MAGIC,
offsetof(or_state_t, magic_),
},
- state_abbrevs_,
- NULL,
- state_vars_,
- or_state_validate_cb,
- NULL,
- &state_extra_var,
- offsetof(or_state_t, substates_),
+ .abbrevs = state_abbrevs_,
+ .vars = state_vars_,
+ .legacy_validate_fn = or_state_validate_cb,
+ .extra = &state_extra_var,
+ .has_config_suite = true,
+ .config_suite_offset = offsetof(or_state_t, substates_),
};
/* A global configuration manager for state-file objects */
static config_mgr_t *state_mgr = NULL;
/** Return the configuration manager for state-file objects. */
-static const config_mgr_t *
+STATIC const config_mgr_t *
get_state_mgr(void)
{
if (PREDICT_UNLIKELY(state_mgr == NULL)) {
state_mgr = config_mgr_new(&state_format);
+ int rv = subsystems_register_state_formats(state_mgr);
+ tor_assert(rv == 0);
config_mgr_freeze(state_mgr);
}
return state_mgr;
}
+#define CHECK_STATE_MAGIC(s) STMT_BEGIN \
+ config_check_toplevel_magic(get_state_mgr(), (s)); \
+ STMT_END
+
/** Persistent serialized state. */
static or_state_t *global_state = NULL;
@@ -268,19 +273,6 @@ validate_transports_in_state(or_state_t *state)
return 0;
}
-static int
-or_state_validate_cb(void *old_state, void *state, void *default_state,
- int from_setconf, char **msg)
-{
- /* We don't use these; only options do. Still, we need to match that
- * signature. */
- (void) from_setconf;
- (void) default_state;
- (void) old_state;
-
- return or_state_validate(state, msg);
-}
-
/** Return 0 if every setting in <b>state</b> is reasonable, and a
* permissible transition from <b>old_state</b>. Else warn and return -1.
* Should have no side effects, except for normalizing the contents of
@@ -289,6 +281,23 @@ or_state_validate_cb(void *old_state, void *state, void *default_state,
static int
or_state_validate(or_state_t *state, char **msg)
{
+ return config_validate(get_state_mgr(), NULL, state, msg);
+}
+
+/**
+ * Legacy validation/normalization callback for or_state_t. See
+ * legacy_validate_fn_t for more information.
+ */
+static int
+or_state_validate_cb(const void *old_state, void *state_, char **msg)
+{
+ /* There is not a meaningful concept of a state-to-state transition,
+ * since we do not reload the state after we start. */
+ (void) old_state;
+ CHECK_STATE_MAGIC(state_);
+
+ or_state_t *state = state_;
+
if (entry_guards_parse_state(state, 0, msg)<0)
return -1;
@@ -307,6 +316,9 @@ or_state_set(or_state_t *new_state)
tor_assert(new_state);
config_free(get_state_mgr(), global_state);
global_state = new_state;
+ if (subsystems_set_state(get_state_mgr(), global_state) < 0) {
+ ret = -1;
+ }
if (entry_guards_parse_state(global_state, 1, &err)<0) {
log_warn(LD_GENERAL,"%s",err);
tor_free(err);
@@ -321,7 +333,6 @@ or_state_set(or_state_t *new_state)
get_circuit_build_times_mutable(),global_state) < 0) {
ret = -1;
}
- netstatus_load_from_state(global_state, time(NULL));
return ret;
}
@@ -510,10 +521,10 @@ or_state_save(time_t now)
/* Call everything else that might dirty the state even more, in order
* to avoid redundant writes. */
+ (void) subsystems_flush_state(get_state_mgr(), global_state);
entry_guards_update_state(global_state);
rep_hist_update_state(global_state);
circuit_build_times_update_state(get_circuit_build_times(), global_state);
- netstatus_flush_to_state(global_state, now);
if (accounting_is_enabled(get_options()))
accounting_run_housekeeping(now);
@@ -633,7 +644,7 @@ get_stored_bindaddr_for_server_transport(const char *transport)
{
/* See if the user explicitly asked for a specific listening
address for this transport. */
- char *conf_bindaddr = get_transport_bindaddr_from_config(transport);
+ char *conf_bindaddr = pt_get_bindaddr_from_config(transport);
if (conf_bindaddr)
return conf_bindaddr;
}
diff --git a/src/app/config/statefile.h b/src/app/config/statefile.h
index 515c90a52f..98d9d2dda1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -31,6 +31,8 @@ STATIC struct config_line_t *get_transport_in_state_by_name(
STATIC void or_state_free_(or_state_t *state);
#define or_state_free(st) FREE_AND_NULL(or_state_t, or_state_free_, (st))
STATIC or_state_t *or_state_new(void);
+struct config_mgr_t;
+STATIC const struct config_mgr_t *get_state_mgr(void);
#endif /* defined(STATEFILE_PRIVATE) */
#endif /* !defined(TOR_STATEFILE_H) */
diff --git a/src/app/config/testnet.inc b/src/app/config/testnet.inc
index 0ed3c38627..907c35f97c 100644
--- a/src/app/config/testnet.inc
+++ b/src/app/config/testnet.inc
@@ -1,3 +1,5 @@
+// When modifying, don't forget to update the defaults
+// for 'TestingTorNetwork' in 'doc/tor.1.txt'
{ "DirAllowPrivateAddresses", "1" },
{ "EnforceDistinctSubnets", "0" },
{ "AssumeReachable", "1" },
@@ -17,7 +19,6 @@
{ "TestingV3AuthInitialVoteDelay", "20 seconds" },
{ "TestingV3AuthInitialDistDelay", "20 seconds" },
{ "TestingAuthDirTimeToLearnReachability", "0 minutes" },
-{ "TestingEstimatedDescriptorPropagationTime", "0 minutes" },
{ "MinUptimeHidServDirectoryV2", "0 minutes" },
{ "TestingServerDownloadInitialDelay", "0" },
{ "TestingClientDownloadInitialDelay", "0" },
diff --git a/src/app/config/tor_cmdline_mode.h b/src/app/config/tor_cmdline_mode.h
new file mode 100644
index 0000000000..30a339a438
--- /dev/null
+++ b/src/app/config/tor_cmdline_mode.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2001 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 tor_cmdline_mode.h
+ * \brief Declare the tor_cmdline_mode_t enumeration
+ **/
+
+#ifndef TOR_CMDLINE_MODE_H
+#define TOR_CMDLINE_MODE_H
+
+/**
+ * Enumeration to describe which command Tor is running. These commands
+ * are controlled by command-line options.
+ **/
+typedef enum {
+ CMD_RUN_TOR=0, /**< The default: run Tor as a daemon. */
+ CMD_LIST_FINGERPRINT, /**< Running --list-fingerprint. */
+ CMD_HASH_PASSWORD, /**< Running --hash-password. */
+ CMD_VERIFY_CONFIG, /**< Running --verify-config. */
+ CMD_DUMP_CONFIG, /**< Running --dump-config. */
+ CMD_KEYGEN, /**< Running --keygen */
+ CMD_KEY_EXPIRATION, /**< Running --key-expiration */
+ CMD_IMMEDIATE, /**< Special value: indicates a command that is handled
+ * immediately during configuration processing. */
+ CMD_RUN_UNITTESTS, /**< Special value: indicates that we have entered
+ * the Tor code from the unit tests, not from the
+ * regular Tor binary at all. */
+} tor_cmdline_mode_t;
+
+#endif /* !defined(TOR_CMDLINE_MODE_H) */
diff --git a/src/app/main/.may_include b/src/app/main/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/app/main/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/app/main/app_main.md b/src/app/main/app_main.md
new file mode 100644
index 0000000000..b8c789716c
--- /dev/null
+++ b/src/app/main/app_main.md
@@ -0,0 +1,2 @@
+@dir /app/main
+@brief app/main: Entry point for tor.
diff --git a/src/app/main/include.am b/src/app/main/include.am
new file mode 100644
index 0000000000..ea392a8581
--- /dev/null
+++ b/src/app/main/include.am
@@ -0,0 +1,18 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/app/main/main.c \
+ src/app/main/shutdown.c \
+ src/app/main/subsystem_list.c \
+ src/app/main/subsysmgr.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/app/main/main.h \
+ src/app/main/ntmain.h \
+ src/app/main/shutdown.h \
+ src/app/main/subsysmgr.h
+
+if BUILD_NT_SERVICES
+LIBTOR_APP_A_SOURCES += src/app/main/ntmain.c
+endif
diff --git a/src/app/main/main.c b/src/app/main/main.c
index 1901479eba..d7d36bff4e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,7 @@
#include "app/config/config.h"
#include "app/config/statefile.h"
+#include "app/config/quiet_level.h"
#include "app/main/main.h"
#include "app/main/ntmain.h"
#include "app/main/shutdown.h"
@@ -66,7 +67,6 @@
#include "lib/osinfo/uname.h"
#include "lib/sandbox/sandbox.h"
#include "lib/fs/lockfile.h"
-#include "lib/net/resolve.h"
#include "lib/tls/tortls.h"
#include "lib/evloop/compat_libevent.h"
#include "lib/encoding/confline.h"
@@ -108,16 +108,6 @@ static void dumpmemusage(int severity);
static void dumpstats(int severity); /* log stats */
static void process_signal(int sig);
-/********* START VARIABLES **********/
-
-/** Decides our behavior when no logs are configured/before any
- * logs have been configured. For 0, we log notice to stdout as normal.
- * For 1, we log warnings only. For 2, we log nothing.
- */
-int quiet_level = 0;
-
-/********* END VARIABLES ************/
-
/** Called when we get a SIGHUP: reload configuration files and keys,
* retry all connections, and so on. */
static int
@@ -304,6 +294,19 @@ process_signal(int sig)
}
}
+#ifdef _WIN32
+/** Activate SIGINT on reciving a control signal in console */
+static BOOL WINAPI
+process_win32_console_ctrl(DWORD ctrl_type)
+{
+ /* Ignore type of the ctrl signal */
+ (void) ctrl_type;
+
+ activate_signal(SIGINT);
+ return TRUE;
+}
+#endif
+
/**
* Write current memory usage information to the log.
*/
@@ -424,6 +427,7 @@ dumpstats(int severity)
rep_hist_dump_stats(now,severity);
rend_service_dump_stats(severity);
+ hs_service_dump_stats(severity);
}
#ifdef _WIN32
@@ -506,6 +510,13 @@ handle_signals(void)
&signal_handlers[i].signal_value);
}
}
+
+#ifdef _WIN32
+ /* Windows lacks traditional POSIX signals but WinAPI provides a function
+ * 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
}
/* Cause the signal handler for signal_num to be called in the event loop. */
@@ -528,7 +539,7 @@ int
tor_init(int argc, char *argv[])
{
char progname[256];
- int quiet = 0;
+ quiet_level_t quiet = QUIET_NONE;
time_of_process_start = time(NULL);
tor_init_connection_lists();
@@ -547,43 +558,17 @@ tor_init(int argc, char *argv[])
hs_init();
{
- /* We search for the "quiet" option first, since it decides whether we
- * will log anything at all to the command line. */
- config_line_t *opts = NULL, *cmdline_opts = NULL;
- const config_line_t *cl;
- (void) config_parse_commandline(argc, argv, 1, &opts, &cmdline_opts);
- for (cl = cmdline_opts; cl; cl = cl->next) {
- if (!strcmp(cl->key, "--hush"))
- quiet = 1;
- if (!strcmp(cl->key, "--quiet") ||
- !strcmp(cl->key, "--dump-config"))
- quiet = 2;
- /* The following options imply --hush */
- if (!strcmp(cl->key, "--version") || !strcmp(cl->key, "--digests") ||
- !strcmp(cl->key, "--list-torrc-options") ||
- !strcmp(cl->key, "--library-versions") ||
- !strcmp(cl->key, "--list-modules") ||
- !strcmp(cl->key, "--hash-password") ||
- !strcmp(cl->key, "-h") || !strcmp(cl->key, "--help")) {
- if (quiet < 1)
- quiet = 1;
- }
- }
- config_free_lines(opts);
- config_free_lines(cmdline_opts);
+ /* We check for the "quiet"/"hush" settings first, since they decide
+ whether we log anything at all to stdout. */
+ parsed_cmdline_t *cmdline;
+ cmdline = config_parse_commandline(argc, argv, 1);
+ if (cmdline)
+ quiet = cmdline->quiet_level;
+ parsed_cmdline_free(cmdline);
}
/* give it somewhere to log to initially */
- switch (quiet) {
- case 2:
- /* no initial logging */
- break;
- case 1:
- add_temp_log(LOG_WARN);
- break;
- default:
- add_temp_log(LOG_NOTICE);
- }
+ add_default_log_for_quiet_level(quiet);
quiet_level = quiet;
{
@@ -627,9 +612,6 @@ tor_init(int argc, char *argv[])
return 1;
}
- /* The options are now initialised */
- const or_options_t *options = get_options();
-
/* Initialize channelpadding and circpad parameters to defaults
* until we get a consensus */
channelpadding_new_consensus_params(NULL);
@@ -651,13 +633,6 @@ tor_init(int argc, char *argv[])
"and you probably shouldn't.");
#endif
- if (crypto_global_init(options->HardwareAccel,
- options->AccelName,
- options->AccelDir)) {
- log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting.");
- return -1;
- }
-
/* Scan/clean unparseable descriptors; after reading config */
routerparse_init();
@@ -847,6 +822,9 @@ sandbox_init_filter(void)
#define OPEN(name) \
sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name))
+#define OPENDIR(dir) \
+ sandbox_cfg_allow_opendir_dirname(&cfg, tor_strdup(dir))
+
#define OPEN_DATADIR(name) \
sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname(name))
@@ -863,8 +841,10 @@ sandbox_init_filter(void)
OPEN_DATADIR2(name, name2 suffix); \
} while (0)
+// KeyDirectory is a directory, but it is only opened in check_private_dir
+// which calls open instead of opendir
#define OPEN_KEY_DIRECTORY() \
- sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->KeyDirectory))
+ OPEN(options->KeyDirectory)
#define OPEN_CACHEDIR(name) \
sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name))
#define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \
@@ -878,6 +858,8 @@ sandbox_init_filter(void)
OPEN_KEYDIR(name suffix); \
} while (0)
+ // DataDirectory is a directory, but it is only opened in check_private_dir
+ // which calls open instead of opendir
OPEN(options->DataDirectory);
OPEN_KEY_DIRECTORY();
@@ -925,7 +907,11 @@ sandbox_init_filter(void)
}
SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, {
- OPEN(f);
+ if (file_status(f) == FN_DIR) {
+ OPENDIR(f);
+ } else {
+ OPEN(f);
+ }
});
#define RENAME_SUFFIX(name, suffix) \
@@ -1038,7 +1024,7 @@ sandbox_init_filter(void)
* directory that holds it. */
char *dirname = tor_strdup(port->unix_addr);
if (get_parent_directory(dirname) == 0) {
- OPEN(dirname);
+ OPENDIR(dirname);
}
tor_free(dirname);
sandbox_cfg_allow_chmod_filename(&cfg, tor_strdup(port->unix_addr));
@@ -1284,15 +1270,10 @@ tor_run_main(const tor_main_configuration_t *tor_cfg)
memcpy(argv + tor_cfg->argc, tor_cfg->argv_owned,
tor_cfg->argc_owned*sizeof(char*));
-#ifdef NT_SERVICE
- {
- int done = 0;
- result = nt_service_parse_options(argc, argv, &done);
- if (done) {
- goto done;
- }
- }
-#endif /* defined(NT_SERVICE) */
+ int done = 0;
+ result = nt_service_parse_options(argc, argv, &done);
+ if (POSSIBLE(done))
+ goto done;
pubsub_install();
@@ -1327,9 +1308,7 @@ tor_run_main(const tor_main_configuration_t *tor_cfg)
switch (get_options()->command) {
case CMD_RUN_TOR:
-#ifdef NT_SERVICE
nt_service_set_state(SERVICE_RUNNING);
-#endif
result = run_tor_main_loop();
break;
case CMD_KEYGEN:
@@ -1347,7 +1326,7 @@ tor_run_main(const tor_main_configuration_t *tor_cfg)
result = 0;
break;
case CMD_VERIFY_CONFIG:
- if (quiet_level == 0)
+ if (quiet_level == QUIET_NONE)
printf("Configuration was valid\n");
result = 0;
break;
@@ -1355,6 +1334,7 @@ tor_run_main(const tor_main_configuration_t *tor_cfg)
result = do_dump_config();
break;
case CMD_RUN_UNITTESTS: /* only set by test.c */
+ case CMD_IMMEDIATE: /* Handled in config.c */
default:
log_warn(LD_BUG,"Illegal command number %d: internal error.",
get_options()->command);
diff --git a/src/app/main/main.h b/src/app/main/main.h
index 76574a9071..e6ed978c61 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/main/ntmain.c b/src/app/main/ntmain.c
index de82eeb1de..5dc0edd591 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -66,7 +66,7 @@ static int nt_service_cmd_stop(void);
/** Struct to hold dynamically loaded NT-service related function pointers.
*/
-struct service_fns {
+struct {
int loaded;
/** @{ */
@@ -347,6 +347,7 @@ nt_service_main(void)
"or --key-expiration) in NT service.");
break;
case CMD_RUN_UNITTESTS:
+ case CMD_IMMEDIATE:
default:
log_err(LD_CONFIG, "Illegal command number %d: internal error.",
get_options()->command);
@@ -602,7 +603,7 @@ nt_service_install(int argc, char **argv)
/* Genericity is apparently _so_ last year in Redmond, where some
* accounts are accounts that you can look up, and some accounts
* are magic and undetectable via the security subsystem. See
- * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
+ * https://msdn2.microsoft.com/en-us/library/ms684188.aspx
*/
printf("Running on a Post-Win2K OS, so we'll assume that the "
"LocalService account exists.\n");
diff --git a/src/app/main/ntmain.h b/src/app/main/ntmain.h
index c39386c054..c2d6e23da7 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,7 +22,8 @@ int nt_service_is_stopping(void);
void nt_service_set_state(DWORD state);
#else
#define nt_service_is_stopping() 0
+#define nt_service_parse_options(a, b, c) (0)
+#define nt_service_set_state(s) STMT_NIL
#endif /* defined(NT_SERVICE) */
#endif /* !defined(TOR_NTMAIN_H) */
-
diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c
index 93d6351d1b..aac15246b9 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -43,8 +43,8 @@
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
-#include "feature/nodelist/routerlist.h"
#include "feature/relay/ext_orport.h"
+#include "feature/relay/relay_config.h"
#include "feature/rend/rendcache.h"
#include "feature/rend/rendclient.h"
#include "feature/stats/geoip_stats.h"
@@ -75,7 +75,8 @@ tor_cleanup(void)
/* Remove Extended ORPort cookie authentication file */
{
char *cookie_fname = get_ext_or_auth_cookie_file_name();
- tor_remove_file(cookie_fname);
+ if (cookie_fname)
+ tor_remove_file(cookie_fname);
tor_free(cookie_fname);
}
if (accounting_is_enabled(options))
@@ -143,6 +144,7 @@ tor_free_all(int postfork)
if (!postfork) {
config_free_all();
+ relay_config_free_all();
or_state_free_all();
}
if (!postfork) {
diff --git a/src/app/main/shutdown.h b/src/app/main/shutdown.h
index 1bca96a0aa..623ae9525b 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/main/subsysmgr.c b/src/app/main/subsysmgr.c
index 5aa4fd76c9..de601d28cd 100644
--- a/src/app/main/subsysmgr.c
+++ b/src/app/main/subsysmgr.c
@@ -1,15 +1,25 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file subsysmgr.c
+ * @brief Manager for Tor's subsystems.
+ *
+ * This code is responsible for initializing, configuring, and shutting
+ * down all of Tor's individual subsystems.
+ **/
+
#include "orconfig.h"
#include "app/main/subsysmgr.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/dispatch/dispatch_naming.h"
#include "lib/dispatch/msgtypes.h"
#include "lib/err/torerr.h"
#include "lib/log/log.h"
+#include "lib/log/util_bug.h"
#include "lib/malloc/malloc.h"
#include "lib/pubsub/pubsub_build.h"
#include "lib/pubsub/pubsub_connect.h"
@@ -23,12 +33,42 @@
**/
static bool subsystem_array_validated = false;
+/** Index value indicating that a subsystem has no options/state object, and
+ * so that object does not have an index. */
+#define IDX_NONE (-1)
+
+/**
+ * Runtime status of a single subsystem.
+ **/
+typedef struct subsys_status_t {
+ /** True if the given subsystem is initialized. */
+ bool initialized;
+ /** Index for this subsystem's options object, or IDX_NONE for none. */
+ int options_idx;
+ /** Index for this subsystem's state object, or IDX_NONE for none. */
+ int state_idx;
+} subsys_status_t;
+
+/** An overestimate of the number of subsystems. */
+#define N_SYS_STATUS 128
/**
* True if a given subsystem is initialized. Expand this array if there
* are more than this number of subsystems. (We'd rather not
* dynamically allocate in this module.)
**/
-static bool sys_initialized[128];
+static subsys_status_t sys_status[N_SYS_STATUS];
+
+/** Set <b>status</b> to a default (not set-up) state. */
+static void
+subsys_status_clear(subsys_status_t *status)
+{
+ if (!status)
+ return;
+ memset(status, 0, sizeof(*status));
+ status->initialized = false;
+ status->state_idx = IDX_NONE;
+ status->options_idx = IDX_NONE;
+}
/**
* Exit with a raw assertion if the subsystems list is inconsistent;
@@ -40,8 +80,8 @@ check_and_setup(void)
if (subsystem_array_validated)
return;
- raw_assert(ARRAY_LENGTH(sys_initialized) >= n_tor_subsystems);
- memset(sys_initialized, 0, sizeof(sys_initialized));
+ raw_assert(ARRAY_LENGTH(sys_status) >= n_tor_subsystems);
+ memset(sys_status, 0, sizeof(sys_status));
int last_level = MIN_SUBSYS_LEVEL;
@@ -59,6 +99,8 @@ check_and_setup(void)
sys->name, i, sys->level, last_level);
raw_assert_unreached_msg("There is a bug in subsystem_list.c");
}
+ subsys_status_clear(&sys_status[i]);
+
last_level = sys->level;
}
@@ -89,7 +131,7 @@ subsystems_init_upto(int target_level)
continue;
if (sys->level > target_level)
break;
- if (sys_initialized[i])
+ if (sys_status[i].initialized)
continue;
int r = 0;
if (sys->initialize) {
@@ -104,7 +146,7 @@ subsystems_init_upto(int target_level)
sys->name, i);
raw_assert_unreached_msg("A subsystem couldn't be initialized.");
}
- sys_initialized[i] = true;
+ sys_status[i].initialized = true;
}
return 0;
@@ -124,7 +166,7 @@ subsystems_add_pubsub_upto(pubsub_builder_t *builder,
continue;
if (sys->level > target_level)
break;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
int r = 0;
if (sys->add_pubsub) {
@@ -178,13 +220,13 @@ subsystems_shutdown_downto(int target_level)
continue;
if (sys->level <= target_level)
break;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
if (sys->shutdown) {
log_debug(LD_GENERAL, "Shutting down %s", sys->name);
sys->shutdown();
}
- sys_initialized[i] = false;
+ subsys_status_clear(&sys_status[i]);
}
}
@@ -200,7 +242,7 @@ subsystems_prefork(void)
const subsys_fns_t *sys = tor_subsystems[i];
if (!sys->supported)
continue;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
if (sys->prefork) {
log_debug(LD_GENERAL, "Pre-fork: %s", sys->name);
@@ -221,7 +263,7 @@ subsystems_postfork(void)
const subsys_fns_t *sys = tor_subsystems[i];
if (!sys->supported)
continue;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
if (sys->postfork) {
log_debug(LD_GENERAL, "Post-fork: %s", sys->name);
@@ -242,7 +284,7 @@ subsystems_thread_cleanup(void)
const subsys_fns_t *sys = tor_subsystems[i];
if (!sys->supported)
continue;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
if (sys->thread_cleanup) {
log_debug(LD_GENERAL, "Thread cleanup: %s", sys->name);
@@ -250,3 +292,187 @@ subsystems_thread_cleanup(void)
}
}
}
+
+/**
+ * Dump a human- and machine-readable list of all the subsystems to stdout,
+ * in their initialization order, prefixed with their level.
+ **/
+void
+subsystems_dump_list(void)
+{
+ for (unsigned i = 0; i < n_tor_subsystems - 1; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ printf("% 4d\t%16s\t%s\n", sys->level, sys->name,
+ sys->location?sys->location:"");
+ }
+}
+
+/**
+ * Register all subsystem-declared options formats in <b>mgr</b>.
+ *
+ * Return 0 on success, -1 on failure.
+ **/
+int
+subsystems_register_options_formats(config_mgr_t *mgr)
+{
+ tor_assert(mgr);
+ check_and_setup();
+
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys->options_format) {
+ int options_idx = config_mgr_add_format(mgr, sys->options_format);
+ sys_status[i].options_idx = options_idx;
+ log_debug(LD_CONFIG, "Added options format for %s with index %d",
+ sys->name, options_idx);
+ }
+ }
+ return 0;
+}
+
+/**
+ * Register all subsystem-declared state formats in <b>mgr</b>.
+ *
+ * Return 0 on success, -1 on failure.
+ **/
+int
+subsystems_register_state_formats(config_mgr_t *mgr)
+{
+ tor_assert(mgr);
+ check_and_setup();
+
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys->state_format) {
+ int state_idx = config_mgr_add_format(mgr, sys->state_format);
+ sys_status[i].state_idx = state_idx;
+ log_debug(LD_CONFIG, "Added state format for %s with index %d",
+ sys->name, state_idx);
+ }
+ }
+ return 0;
+}
+
+#ifdef TOR_UNIT_TESTS
+/**
+ * Helper: look up the index for <b>sys</b>. Return -1 if the subsystem
+ * is not recognized.
+ **/
+static int
+subsys_get_idx(const subsys_fns_t *sys)
+{
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ if (sys == tor_subsystems[i])
+ return (int)i;
+ }
+ return -1;
+}
+
+/**
+ * Return the current state-manager's index for any state held by the
+ * subsystem <b>sys</b>. If <b>sys</b> has no options, return -1.
+ *
+ * Using raw indices can be error-prone: only do this from the unit
+ * tests. If you need a way to access another subsystem's configuration,
+ * that subsystem should provide access functions.
+ **/
+int
+subsystems_get_options_idx(const subsys_fns_t *sys)
+{
+ int i = subsys_get_idx(sys);
+ tor_assert(i >= 0);
+ return sys_status[i].options_idx;
+}
+
+/**
+ * Return the current state-manager's index for any state held by the
+ * subsystem <b>sys</b>. If <b>sys</b> has no state, return -1.
+ *
+ * Using raw indices can be error-prone: only do this from the unit
+ * tests. If you need a way to access another subsystem's state
+ * that subsystem should provide access functions.
+ **/
+int
+subsystems_get_state_idx(const subsys_fns_t *sys)
+{
+ int i = subsys_get_idx(sys);
+ tor_assert(i >= 0);
+ return sys_status[i].state_idx;
+}
+#endif /* defined(TOR_UNIT_TESTS) */
+
+/**
+ * Call all appropriate set_options() methods to tell the various subsystems
+ * about a new set of torrc options. Return 0 on success, -1 on
+ * nonrecoverable failure.
+ **/
+int
+subsystems_set_options(const config_mgr_t *mgr, struct or_options_t *options)
+{
+ /* XXXX This does not yet handle reversible option assignment; I'll
+ * do that later in this branch. */
+
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys_status[i].options_idx >= 0 && sys->set_options) {
+ void *obj = config_mgr_get_obj_mutable(mgr, options,
+ sys_status[i].options_idx);
+ int rv = sys->set_options(obj);
+ if (rv < 0) {
+ log_err(LD_CONFIG, "Error when handling option for %s; "
+ "cannot proceed.", sys->name);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Call all appropriate set_state() methods to tell the various subsystems
+ * about an initial DataDir/state file. Return 0 on success, -1 on
+ * nonrecoverable failure.
+ **/
+int
+subsystems_set_state(const config_mgr_t *mgr, struct or_state_t *state)
+{
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys_status[i].state_idx >= 0 && sys->set_state) {
+ void *obj = config_mgr_get_obj_mutable(mgr, state,
+ sys_status[i].state_idx);
+ int rv = sys->set_state(obj);
+ if (rv < 0) {
+ log_err(LD_CONFIG, "Error when handling state for %s; "
+ "cannot proceed.", sys->name);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Call all appropriate flush_state() methods to tell the various subsystems
+ * to update the state objects in <b>state</b>. Return 0 on success,
+ * -1 on failure.
+ **/
+int
+subsystems_flush_state(const config_mgr_t *mgr, struct or_state_t *state)
+{
+ int result = 0;
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys_status[i].state_idx >= 0 && sys->flush_state) {
+ void *obj = config_mgr_get_obj_mutable(mgr, state,
+ sys_status[i].state_idx);
+ int rv = sys->flush_state(obj);
+ if (rv < 0) {
+ log_warn(LD_CONFIG, "Error when flushing state to state object for %s",
+ sys->name);
+ result = -1;
+ }
+ }
+ }
+ return result;
+}
diff --git a/src/app/main/subsysmgr.h b/src/app/main/subsysmgr.h
index d4426614e3..ae0b3df469 100644
--- a/src/app/main/subsysmgr.h
+++ b/src/app/main/subsysmgr.h
@@ -1,8 +1,13 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file subsysmgr.h
+ * @brief Header for subsysmgr.c
+ **/
+
#ifndef TOR_SUBSYSMGR_T
#define TOR_SUBSYSMGR_T
@@ -26,4 +31,23 @@ void subsystems_prefork(void);
void subsystems_postfork(void);
void subsystems_thread_cleanup(void);
+void subsystems_dump_list(void);
+
+struct config_mgr_t;
+int subsystems_register_options_formats(struct config_mgr_t *mgr);
+int subsystems_register_state_formats(struct config_mgr_t *mgr);
+struct or_options_t;
+struct or_state_t;
+int subsystems_set_options(const struct config_mgr_t *mgr,
+ struct or_options_t *options);
+int subsystems_set_state(const struct config_mgr_t *mgr,
+ struct or_state_t *state);
+int subsystems_flush_state(const struct config_mgr_t *mgr,
+ struct or_state_t *state);
+
+#ifdef TOR_UNIT_TESTS
+int subsystems_get_options_idx(const subsys_fns_t *sys);
+int subsystems_get_state_idx(const subsys_fns_t *sys);
+#endif
+
#endif /* !defined(TOR_SUBSYSMGR_T) */
diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c
index 1af9340c1a..e32083537f 100644
--- a/src/app/main/subsystem_list.c
+++ b/src/app/main/subsystem_list.c
@@ -1,26 +1,28 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file subsystem_list.c
+ * @brief List of Tor's subsystems.
+ **/
+
#include "orconfig.h"
#include "app/main/subsysmgr.h"
#include "lib/cc/compat_compiler.h"
#include "lib/cc/torint.h"
#include "core/mainloop/mainloop_sys.h"
-#include "core/or/ocirc_event_sys.h"
#include "core/or/or_sys.h"
-#include "core/or/orconn_event_sys.h"
#include "feature/control/btrack_sys.h"
-#include "feature/relay/relay_sys.h"
#include "lib/compress/compress_sys.h"
#include "lib/crypt_ops/crypto_sys.h"
#include "lib/err/torerr_sys.h"
#include "lib/log/log_sys.h"
#include "lib/net/network_sys.h"
#include "lib/process/process_sys.h"
-#include "lib/process/winprocess_sys.h"
+#include "lib/llharden/winprocess_sys.h"
#include "lib/thread/thread_sys.h"
#include "lib/time/time_sys.h"
#include "lib/tls/tortls_sys.h"
@@ -28,6 +30,7 @@
#include "lib/evloop/evloop_sys.h"
#include "feature/dirauth/dirauth_sys.h"
+#include "feature/relay/relay_sys.h"
#include <stddef.h>
@@ -41,31 +44,27 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_torerr,
&sys_wallclock,
- &sys_threads,
&sys_logging,
+ &sys_threads,
&sys_time,
- &sys_network,
- &sys_compress,
&sys_crypto,
+ &sys_compress,
+ &sys_network,
&sys_tortls,
- &sys_process,
-
- &sys_orconn_event,
- &sys_ocirc_event,
- &sys_btrack,
&sys_evloop,
+ &sys_process,
&sys_mainloop,
&sys_or,
&sys_relay,
-#ifdef HAVE_MODULE_DIRAUTH
+ &sys_btrack,
+
&sys_dirauth,
-#endif
};
const unsigned n_tor_subsystems = ARRAY_LENGTH(tor_subsystems);
diff --git a/src/app/main/tor_main.c b/src/app/main/tor_main.c
index 8a887ed269..0ee03fd5e9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/arch_goals.md b/src/arch_goals.md
new file mode 100644
index 0000000000..92c86d9df8
--- /dev/null
+++ b/src/arch_goals.md
@@ -0,0 +1,31 @@
+@page arch_goals High level code design practices
+
+This page describes the high level design practices for Tor's code.
+This design is a long-term goal of what we want our code to look like,
+rather than a description of how it currently is.
+
+Overall, we want various parts of tor's code to interact with each
+other through a small number of interfaces.
+
+We want to avoid having "god objects" or "god modules". These are
+objects or modules that know far too much about other parts of the
+code. God objects/modules are generally recognized to be an
+antipattern of software design.
+
+Historically, there have been modules in tor that have tended toward
+becoming god modules. These include modules that help more
+specialized code communicate with the outside world: the configuration
+and control modules, for example. Others are modules that deal with
+global state, initialization, or shutdown.
+
+If a centralized module needs to invoke code in almost every other
+module in the system, it is better if it exports a small, general
+interface that other modules call. The centralized module should not
+explicitly call out to all the modules that interact with it.
+
+Instead, modules that interact with the centralized module should call
+registration interfaces. These interfaces allow modules to register
+handlers for things like configuration parsing and control command
+execution. (The config and control modules are examples of this.)
+Alternatively, registration can happen through statically initialized
+data structures. (The subsystem mechanism is an example of this.)
diff --git a/src/config/mmdb-convert.py b/src/config/mmdb-convert.py
index b861e9433e..4acfea6c0e 100644
--- a/src/config/mmdb-convert.py
+++ b/src/config/mmdb-convert.py
@@ -9,7 +9,7 @@
#
# You should have received a copy of the CC0 legalcode along with this
# work in doc/cc0.txt. If not, see
-# <http://creativecommons.org/publicdomain/zero/1.0/>.
+# <https://creativecommons.org/publicdomain/zero/1.0/>.
# Nick Mathewson is responsible for this kludge, but takes no
# responsibility for it.
@@ -28,6 +28,11 @@
pieces.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import struct
import bisect
import socket
diff --git a/src/core/core.md b/src/core/core.md
new file mode 100644
index 0000000000..8ecc43eaae
--- /dev/null
+++ b/src/core/core.md
@@ -0,0 +1,18 @@
+@dir /core
+@brief core: main loop and onion routing functionality
+
+The "core" directory has the central protocols for Tor, which every
+client and relay must implement in order to perform onion routing.
+
+It is divided into three lower-level pieces:
+
+ - \refdir{core/crypto} -- Tor-specific cryptography.
+
+ - \refdir{core/proto} -- Protocol encoding/decoding.
+
+ - \refdir{core/mainloop} -- A connection-oriented asynchronous mainloop.
+
+and one high-level piece:
+
+ - \refdir{core/or} -- Implements onion routing itself.
+
diff --git a/src/core/crypto/core_crypto.md b/src/core/crypto/core_crypto.md
new file mode 100644
index 0000000000..26ade1f8f8
--- /dev/null
+++ b/src/core/crypto/core_crypto.md
@@ -0,0 +1,6 @@
+@dir /core/crypto
+@brief core/crypto: Tor-specific cryptography
+
+This module implements Tor's circuit-construction crypto and Tor's
+relay crypto.
+
diff --git a/src/core/crypto/hs_ntor.c b/src/core/crypto/hs_ntor.c
index add8a2b8f2..07bcdc566c 100644
--- a/src/core/crypto/hs_ntor.c
+++ b/src/core/crypto/hs_ntor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** \file hs_ntor.c
@@ -170,7 +170,7 @@ get_rendezvous1_key_material(const uint8_t *rend_secret_hs_input,
* necessary key material, and return 0. */
static void
get_introduce1_key_material(const uint8_t *secret_input,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
{
uint8_t keystream[CIPHER256_KEY_LEN + DIGEST256_LEN];
@@ -181,7 +181,7 @@ get_introduce1_key_material(const uint8_t *secret_input,
/* Let's build info */
ptr = info_blob;
APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND));
- APPEND(ptr, subcredential, DIGEST256_LEN);
+ APPEND(ptr, subcredential->subcred, SUBCRED_LEN);
tor_assert(ptr == info_blob + sizeof(info_blob));
/* Let's build the input to the KDF */
@@ -317,7 +317,7 @@ hs_ntor_client_get_introduce1_keys(
const ed25519_public_key_t *intro_auth_pubkey,
const curve25519_public_key_t *intro_enc_pubkey,
const curve25519_keypair_t *client_ephemeral_enc_keypair,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
{
int bad = 0;
@@ -450,9 +450,31 @@ hs_ntor_service_get_introduce1_keys(
const ed25519_public_key_t *intro_auth_pubkey,
const curve25519_keypair_t *intro_enc_keypair,
const curve25519_public_key_t *client_ephemeral_enc_pubkey,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
{
+ return hs_ntor_service_get_introduce1_keys_multi(
+ intro_auth_pubkey,
+ intro_enc_keypair,
+ client_ephemeral_enc_pubkey,
+ 1,
+ subcredential,
+ hs_ntor_intro_cell_keys_out);
+}
+
+/**
+ * As hs_ntor_service_get_introduce1_keys(), but take multiple subcredentials
+ * as input, and yield multiple sets of keys as output.
+ **/
+int
+hs_ntor_service_get_introduce1_keys_multi(
+ const struct ed25519_public_key_t *intro_auth_pubkey,
+ const struct curve25519_keypair_t *intro_enc_keypair,
+ const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
+ size_t n_subcredentials,
+ const hs_subcredential_t *subcredentials,
+ hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
+{
int bad = 0;
uint8_t secret_input[INTRO_SECRET_HS_INPUT_LEN];
uint8_t dh_result[CURVE25519_OUTPUT_LEN];
@@ -460,7 +482,8 @@ hs_ntor_service_get_introduce1_keys(
tor_assert(intro_auth_pubkey);
tor_assert(intro_enc_keypair);
tor_assert(client_ephemeral_enc_pubkey);
- tor_assert(subcredential);
+ tor_assert(n_subcredentials >= 1);
+ tor_assert(subcredentials);
tor_assert(hs_ntor_intro_cell_keys_out);
/* Compute EXP(X, b) */
@@ -476,13 +499,16 @@ hs_ntor_service_get_introduce1_keys(
secret_input);
bad |= safe_mem_is_zero(secret_input, CURVE25519_OUTPUT_LEN);
- /* Get ENC_KEY and MAC_KEY! */
- get_introduce1_key_material(secret_input, subcredential,
- hs_ntor_intro_cell_keys_out);
+ for (unsigned i = 0; i < n_subcredentials; ++i) {
+ /* Get ENC_KEY and MAC_KEY! */
+ get_introduce1_key_material(secret_input, &subcredentials[i],
+ &hs_ntor_intro_cell_keys_out[i]);
+ }
memwipe(secret_input, 0, sizeof(secret_input));
if (bad) {
- memwipe(hs_ntor_intro_cell_keys_out, 0, sizeof(hs_ntor_intro_cell_keys_t));
+ memwipe(hs_ntor_intro_cell_keys_out, 0,
+ sizeof(hs_ntor_intro_cell_keys_t) * n_subcredentials);
}
return bad ? -1 : 0;
diff --git a/src/core/crypto/hs_ntor.h b/src/core/crypto/hs_ntor.h
index e5a5171915..9a975dd83f 100644
--- a/src/core/crypto/hs_ntor.h
+++ b/src/core/crypto/hs_ntor.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file hs_ntor.h
+ * @brief Header for hs_ntor.c
+ **/
+
#ifndef TOR_HS_NTOR_H
#define TOR_HS_NTOR_H
@@ -14,7 +19,7 @@ struct curve25519_keypair_t;
(DIGEST256_LEN*2 + CIPHER256_KEY_LEN*2)
/* Key material needed to encode/decode INTRODUCE1 cells */
-typedef struct {
+typedef struct hs_ntor_intro_cell_keys_t {
/* Key used for encryption of encrypted INTRODUCE1 blob */
uint8_t enc_key[CIPHER256_KEY_LEN];
/* MAC key used to protect encrypted INTRODUCE1 blob */
@@ -22,7 +27,7 @@ typedef struct {
} hs_ntor_intro_cell_keys_t;
/* Key material needed to encode/decode RENDEZVOUS1 cells */
-typedef struct {
+typedef struct hs_ntor_rend_cell_keys_t {
/* This is the MAC of the HANDSHAKE_INFO field */
uint8_t rend_cell_auth_mac[DIGEST256_LEN];
/* This is the key seed used to derive further rendezvous crypto keys as
@@ -30,11 +35,20 @@ typedef struct {
uint8_t ntor_key_seed[DIGEST256_LEN];
} hs_ntor_rend_cell_keys_t;
+#define SUBCRED_LEN DIGEST256_LEN
+
+/**
+ * A 'subcredential' used to prove knowledge of a hidden service.
+ **/
+typedef struct hs_subcredential_t {
+ uint8_t subcred[SUBCRED_LEN];
+} hs_subcredential_t;
+
int hs_ntor_client_get_introduce1_keys(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_public_key_t *intro_enc_pubkey,
const struct curve25519_keypair_t *client_ephemeral_enc_keypair,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
int hs_ntor_client_get_rendezvous1_keys(
@@ -44,11 +58,19 @@ int hs_ntor_client_get_rendezvous1_keys(
const struct curve25519_public_key_t *service_ephemeral_rend_pubkey,
hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out);
+int hs_ntor_service_get_introduce1_keys_multi(
+ const struct ed25519_public_key_t *intro_auth_pubkey,
+ const struct curve25519_keypair_t *intro_enc_keypair,
+ const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
+ size_t n_subcredentials,
+ const hs_subcredential_t *subcredentials,
+ hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
+
int hs_ntor_service_get_introduce1_keys(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_keypair_t *intro_enc_keypair,
const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
int hs_ntor_service_get_rendezvous1_keys(
diff --git a/src/core/crypto/include.am b/src/core/crypto/include.am
new file mode 100644
index 0000000000..28b7e22905
--- /dev/null
+++ b/src/core/crypto/include.am
@@ -0,0 +1,18 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/core/crypto/hs_ntor.c \
+ src/core/crypto/onion_crypto.c \
+ src/core/crypto/onion_fast.c \
+ src/core/crypto/onion_ntor.c \
+ src/core/crypto/onion_tap.c \
+ src/core/crypto/relay_crypto.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/core/crypto/hs_ntor.h \
+ src/core/crypto/onion_crypto.h \
+ src/core/crypto/onion_fast.h \
+ src/core/crypto/onion_ntor.h \
+ src/core/crypto/onion_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 56b02e2996..69b4dc40aa 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/onion_crypto.h b/src/core/crypto/onion_crypto.h
index 7abdd6538e..2665d326a3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/onion_fast.c b/src/core/crypto/onion_fast.c
index 31bd20235f..d760549325 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 0ba8cbbc35..da983a56d9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 7087fe1bd7..5a77230d02 100644
--- a/src/core/crypto/onion_ntor.c
+++ b/src/core/crypto/onion_ntor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, 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 51e72b4083..9473409e40 100644
--- a/src/core/crypto/onion_ntor.h
+++ b/src/core/crypto/onion_ntor.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file onion_ntor.h
+ * @brief Header for onion_ntor.c
+ **/
+
#ifndef TOR_ONION_NTOR_H
#define TOR_ONION_NTOR_H
diff --git a/src/core/crypto/onion_tap.c b/src/core/crypto/onion_tap.c
index 854889d88d..119f55f206 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 0e43b9c8ba..78174b1fab 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 8a285131a8..3e6167e0e1 100644
--- a/src/core/crypto/relay_crypto.c
+++ b/src/core/crypto/relay_crypto.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file relay_crypto.h
+ * @brief Header for relay_crypto.c
+ **/
+
#include "core/or/or.h"
#include "core/or/circuitlist.h"
#include "core/or/crypt_path.h"
diff --git a/src/core/crypto/relay_crypto.h b/src/core/crypto/relay_crypto.h
index 9478f8d359..5e36c7678c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/include.am b/src/core/include.am
index 9b4b251c81..7752a7974b 100644
--- a/src/core/include.am
+++ b/src/core/include.am
@@ -1,201 +1,21 @@
-noinst_LIBRARIES += \
- src/core/libtor-app.a
-if UNITTESTS_ENABLED
-noinst_LIBRARIES += \
- src/core/libtor-app-testing.a
-endif
-
-# ADD_C_FILE: INSERT SOURCES HERE.
-LIBTOR_APP_A_SOURCES = \
- src/app/config/config.c \
- src/app/config/statefile.c \
- src/app/main/main.c \
- src/app/main/shutdown.c \
- src/app/main/subsystem_list.c \
- src/app/main/subsysmgr.c \
- src/core/crypto/hs_ntor.c \
- src/core/crypto/onion_crypto.c \
- src/core/crypto/onion_fast.c \
- src/core/crypto/onion_ntor.c \
- src/core/crypto/onion_tap.c \
- src/core/crypto/relay_crypto.c \
- src/core/mainloop/connection.c \
- src/core/mainloop/cpuworker.c \
- src/core/mainloop/mainloop.c \
- src/core/mainloop/mainloop_pubsub.c \
- src/core/mainloop/mainloop_sys.c \
- src/core/mainloop/netstatus.c \
- src/core/mainloop/periodic.c \
- src/core/or/address_set.c \
- src/core/or/channel.c \
- src/core/or/channelpadding.c \
- src/core/or/channeltls.c \
- src/core/or/circuitbuild.c \
- src/core/or/circuitlist.c \
- src/core/or/circuitmux.c \
- src/core/or/circuitmux_ewma.c \
- src/core/or/circuitpadding.c \
- src/core/or/circuitpadding_machines.c \
- src/core/or/circuitstats.c \
- src/core/or/circuituse.c \
- src/core/or/crypt_path.c \
- src/core/or/command.c \
- src/core/or/connection_edge.c \
- src/core/or/connection_or.c \
- src/core/or/dos.c \
- src/core/or/onion.c \
- src/core/or/ocirc_event.c \
- src/core/or/or_periodic.c \
- src/core/or/or_sys.c \
- src/core/or/orconn_event.c \
- src/core/or/policies.c \
- src/core/or/protover.c \
- 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/status.c \
- src/core/or/versions.c \
- src/core/proto/proto_cell.c \
- src/core/proto/proto_control0.c \
- src/core/proto/proto_ext_or.c \
- src/core/proto/proto_http.c \
- src/core/proto/proto_socks.c \
- src/feature/api/tor_api.c \
- src/feature/client/addressmap.c \
- src/feature/client/bridges.c \
- src/feature/client/circpathbias.c \
- src/feature/client/dnsserv.c \
- src/feature/client/entrynodes.c \
- src/feature/client/transports.c \
- src/feature/control/btrack.c \
- src/feature/control/btrack_circuit.c \
- src/feature/control/btrack_orconn.c \
- src/feature/control/btrack_orconn_cevent.c \
- src/feature/control/btrack_orconn_maps.c \
- src/feature/control/control.c \
- src/feature/control/control_auth.c \
- src/feature/control/control_bootstrap.c \
- src/feature/control/control_cmd.c \
- src/feature/control/control_events.c \
- src/feature/control/control_fmt.c \
- src/feature/control/control_getinfo.c \
- src/feature/control/control_proto.c \
- src/feature/control/fmt_serverstatus.c \
- src/feature/control/getinfo_geoip.c \
- src/feature/dircache/conscache.c \
- src/feature/dircache/consdiffmgr.c \
- src/feature/dircache/dircache.c \
- src/feature/dircache/dirserv.c \
- src/feature/dirclient/dirclient.c \
- src/feature/dirclient/dlstatus.c \
- src/feature/dircommon/consdiff.c \
- src/feature/dircommon/directory.c \
- src/feature/dircommon/fp_pair.c \
- src/feature/dircommon/voting_schedule.c \
- src/feature/dirparse/authcert_parse.c \
- src/feature/dirparse/microdesc_parse.c \
- src/feature/dirparse/ns_parse.c \
- src/feature/dirparse/parsecommon.c \
- src/feature/dirparse/policy_parse.c \
- src/feature/dirparse/routerparse.c \
- src/feature/dirparse/sigcommon.c \
- src/feature/dirparse/signing.c \
- src/feature/dirparse/unparseable.c \
- src/feature/hibernate/hibernate.c \
- src/feature/hs/hs_cache.c \
- src/feature/hs/hs_cell.c \
- src/feature/hs/hs_circuit.c \
- src/feature/hs/hs_circuitmap.c \
- src/feature/hs/hs_client.c \
- src/feature/hs/hs_common.c \
- src/feature/hs/hs_config.c \
- src/feature/hs/hs_control.c \
- src/feature/hs/hs_descriptor.c \
- src/feature/hs/hs_dos.c \
- src/feature/hs/hs_ident.c \
- src/feature/hs/hs_intropoint.c \
- src/feature/hs/hs_service.c \
- src/feature/hs/hs_stats.c \
- src/feature/hs_common/replaycache.c \
- src/feature/hs_common/shared_random_client.c \
- src/feature/keymgt/loadkey.c \
- src/feature/nodelist/authcert.c \
- src/feature/nodelist/describe.c \
- src/feature/nodelist/dirlist.c \
- src/feature/nodelist/microdesc.c \
- src/feature/nodelist/networkstatus.c \
- src/feature/nodelist/nickname.c \
- src/feature/nodelist/nodefamily.c \
- src/feature/nodelist/nodelist.c \
- src/feature/nodelist/node_select.c \
- src/feature/nodelist/routerinfo.c \
- src/feature/nodelist/routerlist.c \
- src/feature/nodelist/routerset.c \
- src/feature/nodelist/fmt_routerstatus.c \
- src/feature/nodelist/torcert.c \
- src/feature/relay/dns.c \
- src/feature/relay/ext_orport.c \
- src/feature/relay/onion_queue.c \
- src/feature/relay/relay_periodic.c \
- src/feature/relay/relay_sys.c \
- src/feature/relay/router.c \
- src/feature/relay/routerkeys.c \
- src/feature/relay/routermode.c \
- src/feature/relay/selftest.c \
- 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/stats/geoip_stats.c \
- src/feature/stats/rephist.c \
- src/feature/stats/predict_ports.c
-
-if BUILD_NT_SERVICES
-LIBTOR_APP_A_SOURCES += src/app/main/ntmain.c
-endif
-
#
-# Modules are conditionnally compiled in tor starting here. We add the C files
+# Modules are conditionally compiled in tor starting here. We add the C files
# only if the modules has been enabled at configure time. We always add the
# source files of every module to libtor-testing.a so we can build the unit
# tests for everything. See the UNITTESTS_ENABLED branch below.
#
LIBTOR_APP_TESTING_A_SOURCES = $(LIBTOR_APP_A_SOURCES)
-# The Directory Authority module.
-MODULE_DIRAUTH_SOURCES = \
- src/feature/dirauth/authmode.c \
- src/feature/dirauth/bridgeauth.c \
- src/feature/dirauth/bwauth.c \
- src/feature/dirauth/dirauth_periodic.c \
- src/feature/dirauth/dirauth_sys.c \
- src/feature/dirauth/dircollate.c \
- src/feature/dirauth/dirvote.c \
- src/feature/dirauth/dsigs_parse.c \
- src/feature/dirauth/guardfraction.c \
- src/feature/dirauth/keypin.c \
- src/feature/dirauth/process_descs.c \
- src/feature/dirauth/reachability.c \
- src/feature/dirauth/recommend_pkg.c \
- src/feature/dirauth/shared_random.c \
- src/feature/dirauth/shared_random_state.c \
- src/feature/dirauth/voteflags.c
+src_core_libtor_app_a_SOURCES = \
+ $(LIBTOR_APP_A_SOURCES) \
+ $(LIBTOR_APP_A_STUB_SOURCES)
-if BUILD_MODULE_DIRAUTH
-LIBTOR_APP_A_SOURCES += $(MODULE_DIRAUTH_SOURCES)
-endif
-
-src_core_libtor_app_a_SOURCES = $(LIBTOR_APP_A_SOURCES)
if UNITTESTS_ENABLED
# Add the sources of the modules that are needed for tests to work here.
+LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_RELAY_SOURCES)
+LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_DIRCACHE_SOURCES)
LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_DIRAUTH_SOURCES)
src_core_libtor_app_testing_a_SOURCES = $(LIBTOR_APP_TESTING_A_SOURCES)
@@ -210,239 +30,6 @@ AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \
src_core_libtor_app_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_core_libtor_app_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
-# ADD_C_FILE: INSERT HEADERS HERE.
-noinst_HEADERS += \
- src/app/config/config.h \
- src/app/config/or_options_st.h \
- src/app/config/or_state_st.h \
- src/app/config/statefile.h \
- src/app/main/main.h \
- src/app/main/ntmain.h \
- src/app/main/shutdown.h \
- src/app/main/subsysmgr.h \
- src/core/crypto/hs_ntor.h \
- src/core/crypto/onion_crypto.h \
- src/core/crypto/onion_fast.h \
- src/core/crypto/onion_ntor.h \
- src/core/crypto/onion_tap.h \
- src/core/crypto/relay_crypto.h \
- src/core/mainloop/connection.h \
- src/core/mainloop/cpuworker.h \
- src/core/mainloop/mainloop.h \
- src/core/mainloop/mainloop_pubsub.h \
- src/core/mainloop/mainloop_sys.h \
- src/core/mainloop/netstatus.h \
- src/core/mainloop/periodic.h \
- src/core/or/addr_policy_st.h \
- src/core/or/address_set.h \
- src/core/or/cell_queue_st.h \
- src/core/or/cell_st.h \
- src/core/or/channel.h \
- src/core/or/channelpadding.h \
- src/core/or/channeltls.h \
- src/core/or/circuit_st.h \
- src/core/or/circuitbuild.h \
- src/core/or/circuitlist.h \
- src/core/or/circuitmux.h \
- src/core/or/circuitmux_ewma.h \
- src/core/or/circuitstats.h \
- src/core/or/circuitpadding.h \
- src/core/or/circuitpadding_machines.h \
- src/core/or/circuituse.h \
- src/core/or/command.h \
- src/core/or/connection_edge.h \
- src/core/or/connection_or.h \
- src/core/or/connection_st.h \
- src/core/or/crypt_path.h \
- src/core/or/cpath_build_state_st.h \
- src/core/or/crypt_path_reference_st.h \
- src/core/or/crypt_path_st.h \
- src/core/or/destroy_cell_queue_st.h \
- src/core/or/dos.h \
- src/core/or/edge_connection_st.h \
- src/core/or/half_edge_st.h \
- src/core/or/entry_connection_st.h \
- src/core/or/entry_port_cfg_st.h \
- src/core/or/extend_info_st.h \
- src/core/or/listener_connection_st.h \
- src/core/or/onion.h \
- src/core/or/or.h \
- src/core/or/or_periodic.h \
- src/core/or/or_sys.h \
- src/core/or/orconn_event.h \
- src/core/or/orconn_event_sys.h \
- src/core/or/or_circuit_st.h \
- src/core/or/or_connection_st.h \
- src/core/or/or_handshake_certs_st.h \
- src/core/or/or_handshake_state_st.h \
- src/core/or/ocirc_event.h \
- src/core/or/ocirc_event_sys.h \
- src/core/or/origin_circuit_st.h \
- src/core/or/policies.h \
- src/core/or/port_cfg_st.h \
- src/core/or/protover.h \
- src/core/or/reasons.h \
- src/core/or/relay.h \
- src/core/or/relay_crypto_st.h \
- src/core/or/scheduler.h \
- src/core/or/sendme.h \
- src/core/or/server_port_cfg_st.h \
- src/core/or/socks_request_st.h \
- src/core/or/status.h \
- src/core/or/tor_version_st.h \
- src/core/or/var_cell_st.h \
- src/core/or/versions.h \
- src/core/proto/proto_cell.h \
- src/core/proto/proto_control0.h \
- src/core/proto/proto_ext_or.h \
- src/core/proto/proto_http.h \
- src/core/proto/proto_socks.h \
- src/feature/api/tor_api_internal.h \
- src/feature/client/addressmap.h \
- src/feature/client/bridges.h \
- src/feature/client/circpathbias.h \
- src/feature/client/dnsserv.h \
- src/feature/client/entrynodes.h \
- src/feature/client/transports.h \
- src/feature/control/btrack_circuit.h \
- src/feature/control/btrack_orconn.h \
- src/feature/control/btrack_orconn_cevent.h \
- src/feature/control/btrack_orconn_maps.h \
- src/feature/control/btrack_sys.h \
- src/feature/control/control.h \
- src/feature/control/control_auth.h \
- src/feature/control/control_cmd.h \
- src/feature/control/control_cmd_args_st.h \
- src/feature/control/control_connection_st.h \
- src/feature/control/control_events.h \
- src/feature/control/control_fmt.h \
- src/feature/control/control_getinfo.h \
- src/feature/control/control_proto.h \
- src/feature/control/fmt_serverstatus.h \
- src/feature/control/getinfo_geoip.h \
- src/feature/dirauth/authmode.h \
- src/feature/dirauth/bridgeauth.h \
- src/feature/dirauth/bwauth.h \
- src/feature/dirauth/dirauth_periodic.h \
- src/feature/dirauth/dirauth_sys.h \
- src/feature/dirauth/dircollate.h \
- src/feature/dirauth/dirvote.h \
- src/feature/dirauth/dsigs_parse.h \
- src/feature/dirauth/guardfraction.h \
- src/feature/dirauth/keypin.h \
- src/feature/dirauth/ns_detached_signatures_st.h \
- src/feature/dirauth/reachability.h \
- src/feature/dirauth/recommend_pkg.h \
- src/feature/dirauth/process_descs.h \
- src/feature/dirauth/shared_random.h \
- src/feature/dirauth/shared_random_state.h \
- src/feature/dirauth/vote_microdesc_hash_st.h \
- src/feature/dirauth/voteflags.h \
- src/feature/dircache/cached_dir_st.h \
- src/feature/dircache/conscache.h \
- src/feature/dircache/consdiffmgr.h \
- src/feature/dircache/dircache.h \
- src/feature/dircache/dirserv.h \
- src/feature/dirclient/dir_server_st.h \
- src/feature/dirclient/dirclient.h \
- src/feature/dirclient/dlstatus.h \
- src/feature/dirclient/download_status_st.h \
- src/feature/dircommon/consdiff.h \
- src/feature/dircommon/dir_connection_st.h \
- src/feature/dircommon/directory.h \
- src/feature/dircommon/fp_pair.h \
- src/feature/dircommon/vote_timing_st.h \
- src/feature/dircommon/voting_schedule.h \
- src/feature/dirparse/authcert_members.i \
- src/feature/dirparse/authcert_parse.h \
- src/feature/dirparse/microdesc_parse.h \
- src/feature/dirparse/ns_parse.h \
- src/feature/dirparse/parsecommon.h \
- src/feature/dirparse/policy_parse.h \
- src/feature/dirparse/routerparse.h \
- src/feature/dirparse/sigcommon.h \
- src/feature/dirparse/signing.h \
- src/feature/dirparse/unparseable.h \
- src/feature/hibernate/hibernate.h \
- src/feature/hs/hs_cache.h \
- src/feature/hs/hs_cell.h \
- src/feature/hs/hs_circuit.h \
- src/feature/hs/hs_circuitmap.h \
- src/feature/hs/hs_client.h \
- src/feature/hs/hs_common.h \
- src/feature/hs/hs_config.h \
- src/feature/hs/hs_control.h \
- src/feature/hs/hs_descriptor.h \
- src/feature/hs/hs_dos.h \
- src/feature/hs/hs_ident.h \
- src/feature/hs/hs_intropoint.h \
- src/feature/hs/hs_service.h \
- src/feature/hs/hs_stats.h \
- src/feature/hs/hsdir_index_st.h \
- src/feature/hs_common/replaycache.h \
- src/feature/hs_common/shared_random_client.h \
- src/feature/keymgt/loadkey.h \
- src/feature/nodelist/authcert.h \
- src/feature/nodelist/authority_cert_st.h \
- src/feature/nodelist/describe.h \
- src/feature/nodelist/desc_store_st.h \
- src/feature/nodelist/dirlist.h \
- src/feature/nodelist/document_signature_st.h \
- src/feature/nodelist/extrainfo_st.h \
- src/feature/nodelist/microdesc.h \
- src/feature/nodelist/microdesc_st.h \
- src/feature/nodelist/networkstatus.h \
- src/feature/nodelist/networkstatus_sr_info_st.h \
- src/feature/nodelist/networkstatus_st.h \
- src/feature/nodelist/networkstatus_voter_info_st.h \
- src/feature/nodelist/nickname.h \
- src/feature/nodelist/node_st.h \
- src/feature/nodelist/nodefamily.h \
- src/feature/nodelist/nodefamily_st.h \
- src/feature/nodelist/nodelist.h \
- src/feature/nodelist/node_select.h \
- src/feature/nodelist/routerinfo.h \
- src/feature/nodelist/routerinfo_st.h \
- src/feature/nodelist/routerlist.h \
- src/feature/nodelist/routerlist_st.h \
- src/feature/nodelist/routerset.h \
- src/feature/nodelist/fmt_routerstatus.h \
- src/feature/nodelist/routerstatus_st.h \
- src/feature/nodelist/signed_descriptor_st.h \
- src/feature/nodelist/torcert.h \
- src/feature/nodelist/vote_routerstatus_st.h \
- src/feature/relay/dns.h \
- src/feature/relay/dns_structs.h \
- src/feature/relay/ext_orport.h \
- src/feature/relay/onion_queue.h \
- src/feature/relay/relay_periodic.h \
- src/feature/relay/relay_sys.h \
- src/feature/relay/router.h \
- src/feature/relay/routerkeys.h \
- src/feature/relay/routermode.h \
- src/feature/relay/selftest.h \
- 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/stats/geoip_stats.h \
- src/feature/stats/rephist.h \
- src/feature/stats/predict_ports.h
-
-noinst_HEADERS += \
- src/app/config/auth_dirs.inc \
- src/app/config/fallback_dirs.inc \
- src/app/config/testnet.inc
-
-# This may someday want to be an installed file?
-noinst_HEADERS += src/feature/api/tor_api.h
-
micro-revision.i: FORCE
$(AM_V_at)rm -f micro-revision.tmp; \
if test -r "$(top_srcdir)/.git" && \
diff --git a/src/core/mainloop/.may_include b/src/core/mainloop/.may_include
index 79d6a130a4..8e01cf910e 100644
--- a/src/core/mainloop/.may_include
+++ b/src/core/mainloop/.may_include
@@ -2,6 +2,7 @@
orconfig.h
+lib/conf/*.h
lib/container/*.h
lib/dispatch/*.h
lib/evloop/*.h
@@ -15,6 +16,9 @@ lib/net/*.h
lib/evloop/*.h
lib/geoip/*.h
lib/sandbox/*.h
+lib/smartlist_core/*.h
lib/compress/*.h
+lib/log/*.h
-core/mainloop/*.h \ No newline at end of file
+core/mainloop/*.h
+core/mainloop/*.inc \ No newline at end of file
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index 50cd3810a4..fd5bf879c5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -65,9 +65,9 @@
* Define this so we get channel internal functions, since we're implementing
* part of a subclass (channel_tls_t).
*/
-#define TOR_CHANNEL_INTERNAL_
-#define CONNECTION_PRIVATE
+#define CHANNEL_OBJECT_PRIVATE
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
@@ -83,6 +83,7 @@
#include "core/or/reasons.h"
#include "core/or/relay.h"
#include "core/or/crypt_path.h"
+#include "core/proto/proto_haproxy.h"
#include "core/proto/proto_http.h"
#include "core/proto/proto_socks.h"
#include "feature/client/dnsserv.h"
@@ -91,6 +92,7 @@
#include "feature/control/control.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
+#include "feature/dirauth/dirauth_config.h"
#include "feature/dircache/dirserv.h"
#include "feature/dircommon/directory.h"
#include "feature/hibernate/hibernate.h"
@@ -107,6 +109,7 @@
#include "lib/crypt_ops/crypto_util.h"
#include "lib/geoip/geoip.h"
+#include "lib/cc/ctassert.h"
#include "lib/sandbox/sandbox.h"
#include "lib/net/buffers_net.h"
#include "lib/tls/tortls.h"
@@ -381,8 +384,12 @@ or_connection_new(int type, int socket_family)
connection_or_set_canonical(or_conn, 0);
- if (type == CONN_TYPE_EXT_OR)
+ if (type == CONN_TYPE_EXT_OR) {
+ /* 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;
}
@@ -639,7 +646,7 @@ connection_free_minimal(connection_t *conn)
}
}
- tor_free(conn->address);
+ tor_str_wipe_and_free(conn->address);
if (connection_speaks_cells(conn)) {
or_connection_t *or_conn = TO_OR_CONN(conn);
@@ -659,7 +666,7 @@ connection_free_minimal(connection_t *conn)
}
or_handshake_state_free(or_conn->handshake_state);
or_conn->handshake_state = NULL;
- tor_free(or_conn->nickname);
+ tor_str_wipe_and_free(or_conn->nickname);
if (or_conn->chan) {
/* Owww, this shouldn't happen, but... */
channel_t *base_chan = TLS_CHAN_TO_BASE(or_conn->chan);
@@ -679,8 +686,8 @@ connection_free_minimal(connection_t *conn)
}
if (conn->type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = TO_ENTRY_CONN(conn);
- tor_free(entry_conn->chosen_exit_name);
- tor_free(entry_conn->original_dest_address);
+ tor_str_wipe_and_free(entry_conn->chosen_exit_name);
+ tor_str_wipe_and_free(entry_conn->original_dest_address);
if (entry_conn->socks_request)
socks_request_free(entry_conn->socks_request);
if (entry_conn->pending_optimistic_data) {
@@ -718,11 +725,7 @@ connection_free_minimal(connection_t *conn)
tor_free(dir_conn->requested_resource);
tor_compress_free(dir_conn->compress_state);
- if (dir_conn->spool) {
- SMARTLIST_FOREACH(dir_conn->spool, spooled_resource_t *, spooled,
- spooled_resource_free(spooled));
- smartlist_free(dir_conn->spool);
- }
+ dir_conn_clear_spool(dir_conn);
rend_data_free(dir_conn->rend_data);
hs_ident_dir_conn_free(dir_conn->hs_ident);
@@ -1516,10 +1519,11 @@ 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;
- lis_conn->entry_cfg.prefer_ipv6 = 0;
}
if (connection_add(conn) < 0) { /* no space, forget it */
@@ -1905,6 +1909,8 @@ connection_init_accepted_conn(connection_t *conn,
conn->state = AP_CONN_STATE_SOCKS_WAIT;
TO_ENTRY_CONN(conn)->socks_request->socks_prefer_no_auth =
listener->entry_cfg.socks_prefer_no_auth;
+ TO_ENTRY_CONN(conn)->socks_request->socks_use_extended_errors =
+ listener->entry_cfg.extended_socks5_codes;
break;
case CONN_TYPE_AP_TRANS_LISTENER:
TO_ENTRY_CONN(conn)->is_transparent_ap = 1;
@@ -2282,9 +2288,12 @@ connection_proxy_state_to_string(int state)
"PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929",
"PROXY_SOCKS5_WANT_AUTH_RFC1929_OK",
"PROXY_SOCKS5_WANT_CONNECT_OK",
+ "PROXY_HAPROXY_WAIT_FOR_FLUSH",
"PROXY_CONNECTED",
};
+ CTASSERT(ARRAY_LENGTH(states) == PROXY_CONNECTED+1);
+
if (state < PROXY_NONE || state > PROXY_CONNECTED)
return unknown;
@@ -2317,7 +2326,11 @@ conn_get_proxy_type(const connection_t *conn)
return PROXY_SOCKS4;
else if (options->Socks5Proxy)
return PROXY_SOCKS5;
- else
+ else if (options->TCPProxy) {
+ /* The only supported protocol in TCPProxy is haproxy. */
+ tor_assert(options->TCPProxyProtocol == TCP_PROXY_PROTOCOL_HAPROXY);
+ return PROXY_HAPROXY;
+ } else
return PROXY_NONE;
}
@@ -2326,165 +2339,245 @@ conn_get_proxy_type(const connection_t *conn)
username NUL: */
#define SOCKS4_STANDARD_BUFFER_SIZE (1 + 1 + 2 + 4 + 1)
-/** Write a proxy request of <b>type</b> (socks4, socks5, https) to conn
- * for conn->addr:conn->port, authenticating with the auth details given
- * in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies
- * support authentication.
+/** Write a proxy request of https to conn for conn->addr:conn->port,
+ * authenticating with the auth details given in the configuration
+ * (if available).
*
* Returns -1 if conn->addr is incompatible with the proxy protocol, and
* 0 otherwise.
- *
- * Use connection_read_proxy_handshake() to complete the handshake.
*/
-int
-connection_proxy_connect(connection_t *conn, int type)
+static int
+connection_https_proxy_connect(connection_t *conn)
{
- const or_options_t *options;
+ tor_assert(conn);
+
+ const or_options_t *options = get_options();
+ char buf[1024];
+ char *base64_authenticator = NULL;
+ const char *authenticator = options->HTTPSProxyAuthenticator;
+
+ /* Send HTTP CONNECT and authentication (if available) in
+ * one request */
+
+ if (authenticator) {
+ base64_authenticator = alloc_http_authenticator(authenticator);
+ if (!base64_authenticator)
+ log_warn(LD_OR, "Encoding https authenticator failed");
+ }
+
+ if (base64_authenticator) {
+ const char *addrport = fmt_addrport(&conn->addr, conn->port);
+ tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.1\r\n"
+ "Host: %s\r\n"
+ "Proxy-Authorization: Basic %s\r\n\r\n",
+ addrport,
+ addrport,
+ base64_authenticator);
+ tor_free(base64_authenticator);
+ } else {
+ tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.0\r\n\r\n",
+ fmt_addrport(&conn->addr, conn->port));
+ }
+
+ connection_buf_add(buf, strlen(buf), conn);
+ conn->proxy_state = PROXY_HTTPS_WANT_CONNECT_OK;
+
+ return 0;
+}
+/** Write a proxy request of socks4 to conn for conn->addr:conn->port.
+ *
+ * Returns -1 if conn->addr is incompatible with the proxy protocol, and
+ * 0 otherwise.
+ */
+static int
+connection_socks4_proxy_connect(connection_t *conn)
+{
tor_assert(conn);
- options = get_options();
+ unsigned char *buf;
+ uint16_t portn;
+ uint32_t ip4addr;
+ size_t buf_size = 0;
+ char *socks_args_string = NULL;
- switch (type) {
- case PROXY_CONNECT: {
- char buf[1024];
- char *base64_authenticator=NULL;
- const char *authenticator = options->HTTPSProxyAuthenticator;
-
- /* Send HTTP CONNECT and authentication (if available) in
- * one request */
-
- if (authenticator) {
- base64_authenticator = alloc_http_authenticator(authenticator);
- if (!base64_authenticator)
- log_warn(LD_OR, "Encoding https authenticator failed");
- }
+ /* Send a SOCKS4 connect request */
- if (base64_authenticator) {
- const char *addrport = fmt_addrport(&conn->addr, conn->port);
- tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.1\r\n"
- "Host: %s\r\n"
- "Proxy-Authorization: Basic %s\r\n\r\n",
- addrport,
- addrport,
- base64_authenticator);
- tor_free(base64_authenticator);
- } else {
- tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.0\r\n\r\n",
- fmt_addrport(&conn->addr, conn->port));
- }
+ if (tor_addr_family(&conn->addr) != AF_INET) {
+ log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
+ return -1;
+ }
- connection_buf_add(buf, strlen(buf), conn);
- conn->proxy_state = PROXY_HTTPS_WANT_CONNECT_OK;
- break;
+ { /* If we are here because we are trying to connect to a
+ pluggable transport proxy, check if we have any SOCKS
+ arguments to transmit. If we do, compress all arguments to
+ a single string in 'socks_args_string': */
+
+ if (conn_get_proxy_type(conn) == PROXY_PLUGGABLE) {
+ socks_args_string =
+ pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
+ if (socks_args_string)
+ log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.",
+ socks_args_string);
}
+ }
- case PROXY_SOCKS4: {
- unsigned char *buf;
- uint16_t portn;
- uint32_t ip4addr;
- size_t buf_size = 0;
- char *socks_args_string = NULL;
+ { /* Figure out the buffer size we need for the SOCKS message: */
- /* Send a SOCKS4 connect request */
+ buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
- if (tor_addr_family(&conn->addr) != AF_INET) {
- log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
- return -1;
- }
+ /* If we have a SOCKS argument string, consider its size when
+ calculating the buffer size: */
+ if (socks_args_string)
+ buf_size += strlen(socks_args_string);
+ }
- { /* If we are here because we are trying to connect to a
- pluggable transport proxy, check if we have any SOCKS
- arguments to transmit. If we do, compress all arguments to
- a single string in 'socks_args_string': */
+ buf = tor_malloc_zero(buf_size);
- if (conn_get_proxy_type(conn) == PROXY_PLUGGABLE) {
- socks_args_string =
- pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
- if (socks_args_string)
- log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.",
- socks_args_string);
- }
- }
+ ip4addr = tor_addr_to_ipv4n(&conn->addr);
+ portn = htons(conn->port);
- { /* Figure out the buffer size we need for the SOCKS message: */
+ buf[0] = 4; /* version */
+ buf[1] = SOCKS_COMMAND_CONNECT; /* command */
+ memcpy(buf + 2, &portn, 2); /* port */
+ memcpy(buf + 4, &ip4addr, 4); /* addr */
+
+ /* Next packet field is the userid. If we have pluggable
+ transport SOCKS arguments, we have to embed them
+ there. Otherwise, we use an empty userid. */
+ if (socks_args_string) { /* place the SOCKS args string: */
+ tor_assert(strlen(socks_args_string) > 0);
+ tor_assert(buf_size >=
+ SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string));
+ strlcpy((char *)buf + 8, socks_args_string, buf_size - 8);
+ tor_free(socks_args_string);
+ } else {
+ buf[8] = 0; /* no userid */
+ }
- buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
+ connection_buf_add((char *)buf, buf_size, conn);
+ tor_free(buf);
- /* If we have a SOCKS argument string, consider its size when
- calculating the buffer size: */
- if (socks_args_string)
- buf_size += strlen(socks_args_string);
- }
+ conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
+ return 0;
+}
- buf = tor_malloc_zero(buf_size);
-
- ip4addr = tor_addr_to_ipv4n(&conn->addr);
- portn = htons(conn->port);
-
- buf[0] = 4; /* version */
- buf[1] = SOCKS_COMMAND_CONNECT; /* command */
- memcpy(buf + 2, &portn, 2); /* port */
- memcpy(buf + 4, &ip4addr, 4); /* addr */
-
- /* Next packet field is the userid. If we have pluggable
- transport SOCKS arguments, we have to embed them
- there. Otherwise, we use an empty userid. */
- if (socks_args_string) { /* place the SOCKS args string: */
- tor_assert(strlen(socks_args_string) > 0);
- tor_assert(buf_size >=
- SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string));
- strlcpy((char *)buf + 8, socks_args_string, buf_size - 8);
- tor_free(socks_args_string);
- } else {
- buf[8] = 0; /* no userid */
- }
+/** Write a proxy request of socks5 to conn for conn->addr:conn->port,
+ * authenticating with the auth details given in the configuration
+ * (if available).
+ *
+ * Returns -1 if conn->addr is incompatible with the proxy protocol, and
+ * 0 otherwise.
+ */
+static int
+connection_socks5_proxy_connect(connection_t *conn)
+{
+ tor_assert(conn);
- connection_buf_add((char *)buf, buf_size, conn);
- tor_free(buf);
+ const or_options_t *options = get_options();
+ unsigned char buf[4]; /* fields: vers, num methods, method list */
- conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
- break;
- }
+ /* Send a SOCKS5 greeting (connect request must wait) */
- case PROXY_SOCKS5: {
- unsigned char buf[4]; /* fields: vers, num methods, method list */
+ buf[0] = 5; /* version */
- /* Send a SOCKS5 greeting (connect request must wait) */
+ /* We have to use SOCKS5 authentication, if we have a
+ Socks5ProxyUsername or if we want to pass arguments to our
+ pluggable transport proxy: */
+ if ((options->Socks5ProxyUsername) ||
+ (conn_get_proxy_type(conn) == PROXY_PLUGGABLE &&
+ (get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) {
+ /* number of auth methods */
+ buf[1] = 2;
+ buf[2] = 0x00; /* no authentication */
+ buf[3] = 0x02; /* rfc1929 Username/Passwd auth */
+ conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929;
+ } else {
+ buf[1] = 1;
+ buf[2] = 0x00; /* no authentication */
+ conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_NONE;
+ }
- buf[0] = 5; /* version */
+ connection_buf_add((char *)buf, 2 + buf[1], conn);
+ return 0;
+}
- /* We have to use SOCKS5 authentication, if we have a
- Socks5ProxyUsername or if we want to pass arguments to our
- pluggable transport proxy: */
- if ((options->Socks5ProxyUsername) ||
- (conn_get_proxy_type(conn) == PROXY_PLUGGABLE &&
- (get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) {
- /* number of auth methods */
- buf[1] = 2;
- buf[2] = 0x00; /* no authentication */
- buf[3] = 0x02; /* rfc1929 Username/Passwd auth */
- conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929;
- } else {
- buf[1] = 1;
- buf[2] = 0x00; /* no authentication */
- conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_NONE;
- }
+/** Write a proxy request of haproxy to conn for conn->addr:conn->port.
+ *
+ * Returns -1 if conn->addr is incompatible with the proxy protocol, and
+ * 0 otherwise.
+ */
+static int
+connection_haproxy_proxy_connect(connection_t *conn)
+{
+ int ret = 0;
+ tor_addr_port_t *addr_port = tor_addr_port_new(&conn->addr, conn->port);
+ char *buf = haproxy_format_proxy_header_line(addr_port);
+
+ if (buf == NULL) {
+ ret = -1;
+ goto done;
+ }
- connection_buf_add((char *)buf, 2 + buf[1], conn);
+ connection_buf_add(buf, strlen(buf), conn);
+ /* In haproxy, we don't have to wait for the response, but we wait for ack.
+ * So we can set the state to be PROXY_HAPROXY_WAIT_FOR_FLUSH. */
+ conn->proxy_state = PROXY_HAPROXY_WAIT_FOR_FLUSH;
+
+ ret = 0;
+ done:
+ tor_free(buf);
+ tor_free(addr_port);
+ return ret;
+}
+
+/** Write a proxy request of <b>type</b> (socks4, socks5, https, haproxy)
+ * to conn for conn->addr:conn->port, authenticating with the auth details
+ * given in the configuration (if available). SOCKS 5 and HTTP CONNECT
+ * proxies support authentication.
+ *
+ * Returns -1 if conn->addr is incompatible with the proxy protocol, and
+ * 0 otherwise.
+ *
+ * Use connection_read_proxy_handshake() to complete the handshake.
+ */
+int
+connection_proxy_connect(connection_t *conn, int type)
+{
+ int ret = 0;
+
+ tor_assert(conn);
+
+ switch (type) {
+ case PROXY_CONNECT:
+ ret = connection_https_proxy_connect(conn);
+ break;
+
+ case PROXY_SOCKS4:
+ ret = connection_socks4_proxy_connect(conn);
+ break;
+
+ case PROXY_SOCKS5:
+ ret = connection_socks5_proxy_connect(conn);
+ break;
+
+ case PROXY_HAPROXY:
+ ret = connection_haproxy_proxy_connect(conn);
break;
- }
default:
log_err(LD_BUG, "Invalid proxy protocol, %d", type);
tor_fragile_assert();
- return -1;
+ ret = -1;
+ break;
}
- log_debug(LD_NET, "set state %s",
- connection_proxy_state_to_string(conn->proxy_state));
+ if (ret == 0) {
+ log_debug(LD_NET, "set state %s",
+ connection_proxy_state_to_string(conn->proxy_state));
+ }
- return 0;
+ return ret;
}
/** Read conn's inbuf. If the http response from the proxy is all
@@ -3057,6 +3150,7 @@ connection_is_rate_limited(const connection_t *conn)
if (conn->linked)
return 0; /* Internal connection */
else if (! options->CountPrivateBandwidth &&
+ ! conn->always_rate_limit_as_remote &&
(tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */
tor_addr_family(&conn->addr) == AF_UNIX || /* no address */
tor_addr_is_internal(&conn->addr, 0)))
@@ -3215,7 +3309,7 @@ connection_dir_is_global_write_low(const connection_t *conn, size_t attempt)
/* Special case for authorities (directory only). */
if (authdir_mode_v3(get_options())) {
/* Are we configured to possibly reject requests under load? */
- if (!get_options()->AuthDirRejectRequestsUnderLoad) {
+ if (!dirauth_should_reject_requests_under_load()) {
/* Answer request no matter what. */
return false;
}
@@ -3260,8 +3354,17 @@ record_num_bytes_transferred_impl(connection_t *conn,
rep_hist_note_dir_bytes_written(num_written, now);
}
+ /* Linked connections and internal IPs aren't counted for statistics or
+ * accounting:
+ * - counting linked connections would double-count BEGINDIR bytes, because
+ * they are sent as Dir bytes on the linked connection, and OR bytes on
+ * the OR connection;
+ * - relays and clients don't connect to internal IPs, unless specifically
+ * configured to do so. If they are configured that way, we don't count
+ * internal bytes.
+ */
if (!connection_is_rate_limited(conn))
- return; /* local IPs are free */
+ return;
if (conn->type == CONN_TYPE_OR)
rep_hist_note_or_conn_bytes(conn->global_identifier, num_read,
@@ -3717,6 +3820,12 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read,
at_most = connection_bucket_read_limit(conn, approx_time());
}
+ /* Do not allow inbuf to grow past BUF_MAX_LEN. */
+ const ssize_t maximum = BUF_MAX_LEN - buf_datalen(conn->inbuf);
+ if (at_most > maximum) {
+ at_most = maximum;
+ }
+
slack_in_buf = buf_slack(conn->inbuf);
again:
if ((size_t)at_most > slack_in_buf && slack_in_buf >= 1024) {
@@ -4101,6 +4210,7 @@ connection_handle_write_impl(connection_t *conn, int force)
switch (result) {
CASE_TOR_TLS_ERROR_ANY:
case TOR_TLS_CLOSE:
+ or_conn->tls_error = result;
log_info(LD_NET, result != TOR_TLS_CLOSE ?
"tls error. breaking.":"TLS connection closed on flush");
/* Don't flush; connection is dead. */
@@ -4885,10 +4995,10 @@ connection_finished_flushing(connection_t *conn)
}
}
-/** Called when our attempt to connect() to another server has just
- * succeeded.
+/** Called when our attempt to connect() to a server has just succeeded.
*
- * This function just passes conn to the connection-specific
+ * This function checks if the interface address has changed (clients only),
+ * and then passes conn to the connection-specific
* connection_*_finished_connecting() function.
*/
static int
@@ -5452,6 +5562,13 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
*port = options->Socks5ProxyPort;
*proxy_type = PROXY_SOCKS5;
return 0;
+ } else if (options->TCPProxy) {
+ tor_addr_copy(addr, &options->TCPProxyAddr);
+ *port = options->TCPProxyPort;
+ /* The only supported protocol in TCPProxy is haproxy. */
+ tor_assert(options->TCPProxyProtocol == TCP_PROXY_PROTOCOL_HAPROXY);
+ *proxy_type = PROXY_HAPROXY;
+ return 0;
}
tor_addr_make_unspec(addr);
@@ -5489,6 +5606,7 @@ proxy_type_to_string(int proxy_type)
case PROXY_CONNECT: return "HTTP";
case PROXY_SOCKS4: return "SOCKS4";
case PROXY_SOCKS5: return "SOCKS5";
+ case PROXY_HAPROXY: return "HAPROXY";
case PROXY_PLUGGABLE: return "pluggable transports SOCKS";
case PROXY_NONE: return "NULL";
default: tor_assert(0);
diff --git a/src/core/mainloop/connection.h b/src/core/mainloop/connection.h
index 668c740042..bcd3d590a5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,7 +12,25 @@
#ifndef TOR_CONNECTION_H
#define TOR_CONNECTION_H
-listener_connection_t *TO_LISTENER_CONN(connection_t *);
+#include "lib/smartlist_core/smartlist_core.h"
+#include "lib/log/log.h"
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+struct listener_connection_t;
+struct connection_t;
+struct dir_connection_t;
+struct or_connection_t;
+struct edge_connection_t;
+struct entry_connection_t;
+struct control_connection_t;
+struct port_cfg_t;
+struct tor_addr_t;
+struct or_options_t;
+
+struct listener_connection_t *TO_LISTENER_CONN(struct connection_t *);
struct buf_t;
@@ -56,7 +74,7 @@ struct buf_t;
#define CONN_TYPE_MAX_ 19
/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in
- * connection_t. */
+ * struct connection_t. */
/* Proxy client handshake states */
/* We use a proxy but we haven't even connected to it yet. */
@@ -75,8 +93,10 @@ struct buf_t;
#define PROXY_SOCKS5_WANT_AUTH_RFC1929_OK 6
/* We use a SOCKS5 proxy and we just sent our CONNECT command. */
#define PROXY_SOCKS5_WANT_CONNECT_OK 7
+/* We use an HAPROXY proxy and we just sent the proxy header. */
+#define PROXY_HAPROXY_WAIT_FOR_FLUSH 8
/* We use a proxy and we CONNECTed successfully!. */
-#define PROXY_CONNECTED 8
+#define PROXY_CONNECTED 9
/** State for any listener connection. */
#define LISTENER_STATE_READY 0
@@ -88,34 +108,36 @@ struct buf_t;
*/
typedef struct
{
- connection_t *old_conn; /* Old listener connection to be replaced */
- const port_cfg_t *new_port; /* New port configuration */
+ struct connection_t *old_conn; /* Old listener connection to be replaced */
+ const struct port_cfg_t *new_port; /* New port configuration */
} listener_replacement_t;
const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
int conn_listener_type_supports_af_unix(int type);
-dir_connection_t *dir_connection_new(int socket_family);
-or_connection_t *or_connection_new(int type, int socket_family);
-edge_connection_t *edge_connection_new(int type, int socket_family);
-entry_connection_t *entry_connection_new(int type, int socket_family);
-control_connection_t *control_connection_new(int socket_family);
-listener_connection_t *listener_connection_new(int type, int socket_family);
-connection_t *connection_new(int type, int socket_family);
-int connection_init_accepted_conn(connection_t *conn,
- const listener_connection_t *listener);
-void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
-MOCK_DECL(void,connection_free_,(connection_t *conn));
+struct dir_connection_t *dir_connection_new(int socket_family);
+struct or_connection_t *or_connection_new(int type, int socket_family);
+struct edge_connection_t *edge_connection_new(int type, int socket_family);
+struct entry_connection_t *entry_connection_new(int type, int socket_family);
+struct control_connection_t *control_connection_new(int socket_family);
+struct listener_connection_t *listener_connection_new(int type,
+ int socket_family);
+struct connection_t *connection_new(int type, int socket_family);
+int connection_init_accepted_conn(struct connection_t *conn,
+ const struct listener_connection_t *listener);
+void connection_link_connections(struct connection_t *conn_a,
+ struct connection_t *conn_b);
+MOCK_DECL(void,connection_free_,(struct connection_t *conn));
#define connection_free(conn) \
- FREE_AND_NULL(connection_t, connection_free_, (conn))
+ FREE_AND_NULL(struct connection_t, connection_free_, (conn))
void connection_free_all(void);
-void connection_about_to_close_connection(connection_t *conn);
-void connection_close_immediate(connection_t *conn);
-void connection_mark_for_close_(connection_t *conn,
+void connection_about_to_close_connection(struct connection_t *conn);
+void connection_close_immediate(struct connection_t *conn);
+void connection_mark_for_close_(struct connection_t *conn,
int line, const char *file);
MOCK_DECL(void, connection_mark_for_close_internal_,
- (connection_t *conn, int line, const char *file));
+ (struct connection_t *conn, int line, const char *file));
#define connection_mark_for_close(c) \
connection_mark_for_close_((c), __LINE__, SHORT_FILE__)
@@ -130,11 +152,11 @@ MOCK_DECL(void, connection_mark_for_close_internal_,
* connection_or_notify_error()), or you actually are the
* connection_or_close_for_error() or connection_or_close_normally function.
* For all other cases, use connection_mark_and_flush() instead, which
- * checks for or_connection_t properly, instead. See below.
+ * checks for struct or_connection_t properly, instead. See below.
*/
#define connection_mark_and_flush_internal_(c,line,file) \
do { \
- connection_t *tmp_conn__ = (c); \
+ struct connection_t *tmp_conn__ = (c); \
connection_mark_for_close_internal_(tmp_conn__, (line), (file)); \
tmp_conn__->hold_open_until_flushed = 1; \
} while (0)
@@ -147,7 +169,7 @@ MOCK_DECL(void, connection_mark_for_close_internal_,
*/
#define connection_mark_and_flush_(c,line,file) \
do { \
- connection_t *tmp_conn_ = (c); \
+ struct connection_t *tmp_conn_ = (c); \
if (tmp_conn_->type == CONN_TYPE_OR) { \
log_warn(LD_CHANNEL | LD_BUG, \
"Something tried to close (and flush) an or_connection_t" \
@@ -164,13 +186,13 @@ MOCK_DECL(void, connection_mark_for_close_internal_,
void connection_expire_held_open(void);
-int connection_connect(connection_t *conn, const char *address,
- const tor_addr_t *addr,
+int connection_connect(struct connection_t *conn, const char *address,
+ const struct tor_addr_t *addr,
uint16_t port, int *socket_error);
#ifdef HAVE_SYS_UN_H
-int connection_connect_unix(connection_t *conn, const char *socket_path,
+int connection_connect_unix(struct connection_t *conn, const char *socket_path,
int *socket_error);
#endif /* defined(HAVE_SYS_UN_H) */
@@ -183,13 +205,14 @@ int connection_connect_unix(connection_t *conn, const char *socket_path,
username and password fields. */
#define MAX_SOCKS5_AUTH_SIZE_TOTAL 2*MAX_SOCKS5_AUTH_FIELD_SIZE
-int connection_proxy_connect(connection_t *conn, int type);
-int connection_read_proxy_handshake(connection_t *conn);
-void log_failed_proxy_connection(connection_t *conn);
-int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
- int *is_pt_out, const connection_t *conn);
+int connection_proxy_connect(struct connection_t *conn, int type);
+int connection_read_proxy_handshake(struct connection_t *conn);
+void log_failed_proxy_connection(struct connection_t *conn);
+int get_proxy_addrport(struct tor_addr_t *addr, uint16_t *port,
+ int *proxy_type,
+ int *is_pt_out, const struct connection_t *conn);
-int retry_all_listeners(smartlist_t *new_conns,
+int retry_all_listeners(struct smartlist_t *new_conns,
int close_all_noncontrol);
void connection_mark_all_noncontrol_listeners(void);
@@ -199,63 +222,69 @@ ssize_t connection_bucket_write_limit(struct connection_t *conn, time_t now);
bool connection_dir_is_global_write_low(const struct connection_t *conn,
size_t attempt);
void connection_bucket_init(void);
-void connection_bucket_adjust(const or_options_t *options);
+void connection_bucket_adjust(const struct or_options_t *options);
void connection_bucket_refill_all(time_t now,
uint32_t now_ts);
-void connection_read_bw_exhausted(connection_t *conn, bool is_global_bw);
-void connection_write_bw_exhausted(connection_t *conn, bool is_global_bw);
-void connection_consider_empty_read_buckets(connection_t *conn);
-void connection_consider_empty_write_buckets(connection_t *conn);
-
-int connection_handle_read(connection_t *conn);
-
-int connection_buf_get_bytes(char *string, size_t len, connection_t *conn);
-int connection_buf_get_line(connection_t *conn, char *data,
- size_t *data_len);
-int connection_fetch_from_buf_http(connection_t *conn,
+void connection_read_bw_exhausted(struct connection_t *conn,
+ bool is_global_bw);
+void connection_write_bw_exhausted(struct connection_t *conn,
+ bool is_global_bw);
+void connection_consider_empty_read_buckets(struct connection_t *conn);
+void connection_consider_empty_write_buckets(struct connection_t *conn);
+
+int connection_handle_read(struct connection_t *conn);
+
+int connection_buf_get_bytes(char *string, size_t len,
+ struct connection_t *conn);
+int connection_buf_get_line(struct connection_t *conn, char *data,
+ size_t *data_len);
+int connection_fetch_from_buf_http(struct connection_t *conn,
char **headers_out, size_t max_headerlen,
char **body_out, size_t *body_used,
size_t max_bodylen, int force_complete);
-int connection_wants_to_flush(connection_t *conn);
-int connection_outbuf_too_full(connection_t *conn);
-int connection_handle_write(connection_t *conn, int force);
-int connection_flush(connection_t *conn);
+int connection_wants_to_flush(struct connection_t *conn);
+int connection_outbuf_too_full(struct connection_t *conn);
+int connection_handle_write(struct connection_t *conn, int force);
+int connection_flush(struct connection_t *conn);
MOCK_DECL(void, connection_write_to_buf_impl_,
- (const char *string, size_t len, connection_t *conn, int zlib));
+ (const char *string, size_t len, struct connection_t *conn,
+ int zlib));
/* DOCDOC connection_write_to_buf */
static void connection_buf_add(const char *string, size_t len,
- connection_t *conn);
+ struct connection_t *conn);
void connection_dir_buf_add(const char *string, size_t len,
- dir_connection_t *dir_conn, int done);
+ struct dir_connection_t *dir_conn, int done);
static inline void
-connection_buf_add(const char *string, size_t len, connection_t *conn)
+connection_buf_add(const char *string, size_t len, struct connection_t *conn)
{
connection_write_to_buf_impl_(string, len, conn, 0);
}
void connection_buf_add_compress(const char *string, size_t len,
- dir_connection_t *conn, int done);
-void connection_buf_add_buf(connection_t *conn, struct buf_t *buf);
-
-size_t connection_get_inbuf_len(connection_t *conn);
-size_t connection_get_outbuf_len(connection_t *conn);
-connection_t *connection_get_by_global_id(uint64_t id);
-
-connection_t *connection_get_by_type(int type);
-MOCK_DECL(connection_t *,connection_get_by_type_nonlinked,(int type));
-MOCK_DECL(connection_t *,connection_get_by_type_addr_port_purpose,(int type,
- const tor_addr_t *addr,
- uint16_t port, int purpose));
-connection_t *connection_get_by_type_state(int type, int state);
-connection_t *connection_get_by_type_state_rendquery(int type, int state,
+ 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);
+struct connection_t *connection_get_by_global_id(uint64_t id);
+
+struct connection_t *connection_get_by_type(int type);
+MOCK_DECL(struct connection_t *,connection_get_by_type_nonlinked,(int type));
+MOCK_DECL(struct connection_t *,connection_get_by_type_addr_port_purpose,
+ (int type,
+ const struct tor_addr_t *addr,
+ uint16_t port, int purpose));
+struct connection_t *connection_get_by_type_state(int type, int state);
+struct connection_t *connection_get_by_type_state_rendquery(
+ int type, int state,
const char *rendquery);
-smartlist_t *connection_list_by_type_state(int type, int state);
-smartlist_t *connection_list_by_type_purpose(int type, int purpose);
-smartlist_t *connection_dir_list_by_purpose_and_resource(
+struct smartlist_t *connection_list_by_type_state(int type, int state);
+struct smartlist_t *connection_list_by_type_purpose(int type, int purpose);
+struct smartlist_t *connection_dir_list_by_purpose_and_resource(
int purpose,
const char *resource);
-smartlist_t *connection_dir_list_by_purpose_resource_and_state(
+struct smartlist_t *connection_dir_list_by_purpose_resource_and_state(
int purpose,
const char *resource,
int state);
@@ -274,7 +303,7 @@ connection_dir_count_by_purpose_and_resource(
int purpose,
const char *resource)
{
- smartlist_t *conns = connection_dir_list_by_purpose_and_resource(
+ struct smartlist_t *conns = connection_dir_list_by_purpose_and_resource(
purpose,
resource);
CONN_LEN_AND_FREE_TEMPLATE(conns);
@@ -288,7 +317,7 @@ connection_dir_count_by_purpose_resource_and_state(
const char *resource,
int state)
{
- smartlist_t *conns =
+ struct smartlist_t *conns =
connection_dir_list_by_purpose_resource_and_state(
purpose,
resource,
@@ -298,26 +327,26 @@ connection_dir_count_by_purpose_resource_and_state(
#undef CONN_LEN_AND_FREE_TEMPLATE
-int any_other_active_or_conns(const or_connection_t *this_conn);
+int any_other_active_or_conns(const struct or_connection_t *this_conn);
/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
#define connection_speaks_cells(conn) (((conn)->type == CONN_TYPE_OR) || 0)
-int connection_is_listener(connection_t *conn);
-int connection_state_is_open(connection_t *conn);
-int connection_state_is_connecting(connection_t *conn);
+int connection_is_listener(struct connection_t *conn);
+int connection_state_is_open(struct connection_t *conn);
+int connection_state_is_connecting(struct connection_t *conn);
char *alloc_http_authenticator(const char *authenticator);
-void assert_connection_ok(connection_t *conn, time_t now);
-int connection_or_nonopen_was_started_here(or_connection_t *conn);
+void assert_connection_ok(struct connection_t *conn, time_t now);
+int connection_or_nonopen_was_started_here(struct or_connection_t *conn);
void connection_dump_buffer_mem_stats(int severity);
MOCK_DECL(void, clock_skew_warning,
- (const connection_t *conn, long apparent_skew, int trusted,
+ (const struct connection_t *conn, long apparent_skew, int trusted,
log_domain_mask_t domain, const char *received,
const char *source));
-int connection_is_moribund(connection_t *conn);
+int connection_is_moribund(struct connection_t *conn);
void connection_check_oos(int n_socks, int failed);
/** Execute the statement <b>stmt</b>, which may log events concerning the
@@ -339,18 +368,18 @@ void connection_check_oos(int n_socks, int failed);
STMT_END
#ifdef CONNECTION_PRIVATE
-STATIC void connection_free_minimal(connection_t *conn);
+STATIC void connection_free_minimal(struct connection_t *conn);
/* Used only by connection.c and test*.c */
MOCK_DECL(STATIC int,connection_connect_sockaddr,
- (connection_t *conn,
+ (struct connection_t *conn,
const struct sockaddr *sa,
socklen_t sa_len,
const struct sockaddr *bindaddr,
socklen_t bindaddr_len,
int *socket_error));
-MOCK_DECL(STATIC void, kill_conn_list_for_oos, (smartlist_t *conns));
-MOCK_DECL(STATIC smartlist_t *, pick_oos_victims, (int n));
+MOCK_DECL(STATIC void, kill_conn_list_for_oos, (struct smartlist_t *conns));
+MOCK_DECL(STATIC struct smartlist_t *, pick_oos_victims, (int n));
#endif /* defined(CONNECTION_PRIVATE) */
diff --git a/src/core/mainloop/core_mainloop.md b/src/core/mainloop/core_mainloop.md
new file mode 100644
index 0000000000..fee8a8179c
--- /dev/null
+++ b/src/core/mainloop/core_mainloop.md
@@ -0,0 +1,10 @@
+@dir /core/mainloop
+@brief core/mainloop: Non-onion-routing mainloop functionality
+
+This module uses the event-loop code of \refdir{lib/evloop} to implement an
+asynchronous connection-oriented protocol handler.
+
+The layering here is imperfect: the code here was split from \refdir{core/or}
+without refactoring how the two modules call one another. Probably many
+functions should be moved and refactored.
+
diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c
index 436fcd28c3..485ddb9741 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,7 +19,6 @@
**/
#include "core/or/or.h"
#include "core/or/channel.h"
-#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_or.h"
#include "app/config/config.h"
@@ -27,6 +26,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "core/or/onion.h"
+#include "feature/relay/circuitbuild_relay.h"
#include "feature/relay/onion_queue.h"
#include "feature/stats/rephist.h"
#include "feature/relay/router.h"
@@ -37,7 +37,7 @@
static void queue_pending_tasks(void);
-typedef struct worker_state_s {
+typedef struct worker_state_t {
int generation;
server_onion_keys_t *onion_keys;
} worker_state_t;
@@ -160,7 +160,7 @@ typedef struct cpuworker_reply_t {
uint8_t rend_auth_material[DIGEST_LEN];
} cpuworker_reply_t;
-typedef struct cpuworker_job_u {
+typedef struct cpuworker_job_u_t {
or_circuit_t *circ;
union {
cpuworker_request_t request;
diff --git a/src/core/mainloop/cpuworker.h b/src/core/mainloop/cpuworker.h
index 77e2c42508..7e71961750 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,10 +14,10 @@
void cpu_init(void);
void cpuworkers_rotate_keyinfo(void);
-struct workqueue_entry_s;
+struct workqueue_entry_t;
enum workqueue_reply_t;
enum workqueue_priority_t;
-MOCK_DECL(struct workqueue_entry_s *, cpuworker_queue_work, (
+MOCK_DECL(struct workqueue_entry_t *, cpuworker_queue_work, (
enum workqueue_priority_t priority,
enum workqueue_reply_t (*fn)(void *, void *),
void (*reply_fn)(void *),
diff --git a/src/core/mainloop/include.am b/src/core/mainloop/include.am
new file mode 100644
index 0000000000..63643127f3
--- /dev/null
+++ b/src/core/mainloop/include.am
@@ -0,0 +1,22 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/core/mainloop/connection.c \
+ src/core/mainloop/cpuworker.c \
+ src/core/mainloop/mainloop.c \
+ src/core/mainloop/mainloop_pubsub.c \
+ src/core/mainloop/mainloop_sys.c \
+ src/core/mainloop/netstatus.c \
+ src/core/mainloop/periodic.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/core/mainloop/connection.h \
+ src/core/mainloop/cpuworker.h \
+ src/core/mainloop/mainloop.h \
+ src/core/mainloop/mainloop_pubsub.h \
+ src/core/mainloop/mainloop_state.inc \
+ src/core/mainloop/mainloop_state_st.h \
+ src/core/mainloop/mainloop_sys.h \
+ src/core/mainloop/netstatus.h \
+ src/core/mainloop/periodic.h
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index c47e440774..e4e17f6b76 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -71,12 +71,13 @@
#include "feature/client/bridges.h"
#include "feature/client/dnsserv.h"
#include "feature/client/entrynodes.h"
+#include "feature/client/proxymode.h"
#include "feature/client/transports.h"
#include "feature/control/control.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
#include "feature/dircache/consdiffmgr.h"
-#include "feature/dircache/dirserv.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dircommon/directory.h"
#include "feature/hibernate/hibernate.h"
#include "feature/hs/hs_cache.h"
@@ -965,7 +966,6 @@ conn_close_if_marked(int i)
return 0; /* nothing to see here, move along */
now = time(NULL);
assert_connection_ok(conn, now);
- /* assert_all_pending_dns_resolves_ok(); */
log_debug(LD_NET,"Cleaning up connection (fd "TOR_SOCKET_T_FORMAT").",
conn->s);
@@ -1132,14 +1132,14 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs)
if (!router_have_minimum_dir_info()) {
int quiet = suppress_logs || from_cache ||
- directory_too_idle_to_fetch_descriptors(options, now);
+ dirclient_too_idle_to_fetch_descriptors(options, now);
tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
"I learned some more directory information, but not enough to "
"build a circuit: %s", get_dir_info_status_string());
update_all_descriptor_downloads(now);
return;
} else {
- if (directory_fetches_from_authorities(options)) {
+ if (dirclient_fetches_from_authorities(options)) {
update_all_descriptor_downloads(now);
}
@@ -1352,9 +1352,11 @@ get_signewnym_epoch(void)
static int periodic_events_initialized = 0;
/* Declare all the timer callback functions... */
+#ifndef COCCI
#undef CALLBACK
#define CALLBACK(name) \
static int name ## _callback(time_t, const or_options_t *)
+
CALLBACK(add_entropy);
CALLBACK(check_expired_networkstatus);
CALLBACK(clean_caches);
@@ -1377,9 +1379,10 @@ CALLBACK(second_elapsed);
#undef CALLBACK
/* Now we declare an array of periodic_event_item_t for each periodic event */
-#define CALLBACK(name, r, f) \
+#define CALLBACK(name, r, f) \
PERIODIC_EVENT(name, PERIODIC_EVENT_ROLE_ ## r, f)
#define FL(name) (PERIODIC_EVENT_FLAG_ ## name)
+#endif /* !defined(COCCI) */
STATIC periodic_event_item_t mainloop_periodic_events[] = {
@@ -1430,8 +1433,10 @@ STATIC periodic_event_item_t mainloop_periodic_events[] = {
END_OF_PERIODIC_EVENTS
};
+#ifndef COCCI
#undef CALLBACK
#undef FL
+#endif
/* These are pointers to members of periodic_events[] that are used to
* implement particular callbacks. We keep them separate here so that we
@@ -1530,8 +1535,10 @@ initialize_periodic_events(void)
/* Set up all periodic events. We'll launch them by roles. */
+#ifndef COCCI
#define NAMED_CALLBACK(name) \
STMT_BEGIN name ## _event = periodic_events_find( #name ); STMT_END
+#endif
NAMED_CALLBACK(prune_old_routers);
NAMED_CALLBACK(fetch_networkstatus);
@@ -2061,7 +2068,7 @@ fetch_networkstatus_callback(time_t now, const or_options_t *options)
* documents? */
const int we_are_bootstrapping = networkstatus_consensus_is_bootstrapping(
now);
- const int prefer_mirrors = !directory_fetches_from_authorities(
+ const int prefer_mirrors = !dirclient_fetches_from_authorities(
get_options());
int networkstatus_dl_check_interval = 60;
/* check more often when testing, or when bootstrapping from mirrors
@@ -2265,18 +2272,23 @@ systemd_watchdog_callback(periodic_timer_t *timer, void *arg)
#define UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST (6*60*60)
-/** Called when our IP address seems to have changed. <b>at_interface</b>
- * should be true if we detected a change in our interface, and false if we
- * detected a change in our published address. */
+/** Called when our IP address seems to have changed. <b>on_client_conn</b>
+ * should be true if:
+ * - we detected a change in our interface address, using an outbound
+ * connection, and therefore
+ * - our client TLS keys need to be rotated.
+ * Otherwise, it should be false, and:
+ * - we detected a change in our published address
+ * (using some other method), and therefore
+ * - the published addresses in our descriptor need to change.
+ */
void
-ip_address_changed(int at_interface)
+ip_address_changed(int on_client_conn)
{
const or_options_t *options = get_options();
int server = server_mode(options);
- int exit_reject_interfaces = (server && options->ExitRelay
- && options->ExitPolicyRejectLocalInterfaces);
- if (at_interface) {
+ if (on_client_conn) {
if (! server) {
/* Okay, change our keys. */
if (init_keys_client() < 0)
@@ -2288,15 +2300,14 @@ ip_address_changed(int at_interface)
reset_bandwidth_test();
reset_uptime();
router_reset_reachability();
+ /* All relays include their IP addresses as their ORPort addresses in
+ * their descriptor.
+ * Exit relays also incorporate interface addresses in their exit
+ * policies, when ExitPolicyRejectLocalInterfaces is set. */
+ mark_my_descriptor_dirty("IP address changed");
}
}
- /* Exit relays incorporate interface addresses in their exit policies when
- * ExitPolicyRejectLocalInterfaces is set */
- if (exit_reject_interfaces || (server && !at_interface)) {
- mark_my_descriptor_dirty("IP address changed");
- }
-
dns_servers_relaunch_checks();
}
diff --git a/src/core/mainloop/mainloop.h b/src/core/mainloop/mainloop.h
index caef736c15..1ddfec2162 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -56,7 +56,7 @@ MOCK_DECL(int, connection_count_moribund, (void));
void directory_all_unreachable(time_t now);
void directory_info_has_arrived(time_t now, int from_cache, int suppress_logs);
-void ip_address_changed(int at_interface);
+void ip_address_changed(int on_client_conn);
void dns_servers_relaunch_checks(void);
void reset_all_main_loop_timers(void);
void reschedule_directory_downloads(void);
@@ -94,7 +94,6 @@ void tor_mainloop_free_all(void);
struct token_bucket_rw_t;
extern time_t time_of_process_start;
-extern int quiet_level;
extern struct token_bucket_rw_t global_bucket;
extern struct token_bucket_rw_t global_relayed_bucket;
diff --git a/src/core/mainloop/mainloop_pubsub.c b/src/core/mainloop/mainloop_pubsub.c
index 53275d8119..0e982d4c40 100644
--- a/src/core/mainloop/mainloop_pubsub.c
+++ b/src/core/mainloop/mainloop_pubsub.c
@@ -1,9 +1,18 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file mainloop_pubsub.c
+ * @brief Connect the publish-subscribe code to the main-loop.
+ *
+ * This module is responsible for instantiating all the channels used by the
+ * publish-subscribe code, and making sure that each one's messages are
+ * processed when appropriate.
+ **/
+
#include "orconfig.h"
#include "core/or/or.h"
diff --git a/src/core/mainloop/mainloop_pubsub.h b/src/core/mainloop/mainloop_pubsub.h
index 365a3dd565..3698fd8d03 100644
--- a/src/core/mainloop/mainloop_pubsub.h
+++ b/src/core/mainloop/mainloop_pubsub.h
@@ -1,17 +1,54 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file mainloop_pubsub.h
+ * @brief Header for mainloop_pubsub.c
+ **/
+
#ifndef TOR_MAINLOOP_PUBSUB_H
#define TOR_MAINLOOP_PUBSUB_H
struct pubsub_builder_t;
+/**
+ * Describe when and how messages are delivered on message channel.
+ *
+ * Every message channel must be associated with one of these strategies.
+ **/
typedef enum {
+ /**
+ * Never deliver messages automatically.
+ *
+ * If a message channel uses this strategy, then no matter now many
+ * messages are published on it, they are not delivered until something
+ * manually calls dispatch_flush() for that channel
+ **/
DELIV_NEVER=0,
+ /**
+ * Deliver messages promptly, via the event loop.
+ *
+ * If a message channel uses this strategy, then publishing a messages
+ * that channel activates an event that causes messages to be handled
+ * later in the mainloop. The messages will be processed at some point
+ * very soon, delaying only for pending IO events and the like.
+ *
+ * Generally this is the best choice for a delivery strategy, since
+ * it avoids stack explosion.
+ **/
DELIV_PROMPT,
+ /**
+ * Deliver messages immediately, skipping the event loop.
+ *
+ * Every event on this channel is flushed immediately after it is queued,
+ * using the stack.
+ *
+ * This delivery type should be used with caution, since it can cause
+ * unexpected call chains, resource starvation, and the like.
+ **/
DELIV_IMMEDIATE,
} deliv_strategy_t;
diff --git a/src/core/mainloop/mainloop_state.inc b/src/core/mainloop/mainloop_state.inc
new file mode 100644
index 0000000000..34a37caaa2
--- /dev/null
+++ b/src/core/mainloop/mainloop_state.inc
@@ -0,0 +1,19 @@
+
+/**
+ * @file mainloop_state.inc
+ * @brief Declare configuration options for the crypto_ops module.
+ **/
+
+/** Holds state for the mainloop, corresponding to part of the state
+ * file in Tor's DataDirectory. */
+BEGIN_CONF_STRUCT(mainloop_state_t)
+
+/** Number of minutes since the last user-initiated request (as defined by
+ * the dormant net-status system.) Set to zero if we are dormant. */
+CONF_VAR(MinutesSinceUserActivity, POSINT, 0, NULL)
+
+/** True if we were dormant when we last wrote the file; false if we
+ * weren't. "auto" on initial startup. */
+CONF_VAR(Dormant, AUTOBOOL, 0, "auto")
+
+END_CONF_STRUCT(mainloop_state_t)
diff --git a/src/core/mainloop/mainloop_state_st.h b/src/core/mainloop/mainloop_state_st.h
new file mode 100644
index 0000000000..5649b536f9
--- /dev/null
+++ b/src/core/mainloop/mainloop_state_st.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file mainloop_state_st.h
+ * @brief Declare a state structure for mainloop-relevant fields
+ **/
+
+#ifndef TOR_CORE_MAINLOOP_MAINLOOP_STATE_ST_H
+#define TOR_CORE_MAINLOOP_MAINLOOP_STATE_ST_H
+
+#include "lib/conf/confdecl.h"
+
+#define CONF_CONTEXT STRUCT
+#include "core/mainloop/mainloop_state.inc"
+#undef CONF_CONTEXT
+
+typedef struct mainloop_state_t mainloop_state_t;
+
+#endif /* !defined(TOR_CORE_MAINLOOP_MAINLOOP_STATE_ST_H) */
diff --git a/src/core/mainloop/mainloop_sys.c b/src/core/mainloop/mainloop_sys.c
index fbd5a40327..884bae1c59 100644
--- a/src/core/mainloop/mainloop_sys.c
+++ b/src/core/mainloop/mainloop_sys.c
@@ -1,12 +1,21 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file mainloop_sys.c
+ * @brief Declare the "mainloop" subsystem.
+ **/
+
#include "core/or/or.h"
#include "core/mainloop/mainloop_sys.h"
#include "core/mainloop/mainloop.h"
+#include "core/mainloop/mainloop_state_st.h"
+#include "core/mainloop/netstatus.h"
+#include "lib/conf/conftypes.h"
+#include "lib/conf/confdecl.h"
#include "lib/subsys/subsys.h"
@@ -23,10 +32,59 @@ subsys_mainloop_shutdown(void)
tor_mainloop_free_all();
}
+/** Declare a list of state variables for mainloop state. */
+#define CONF_CONTEXT TABLE
+#include "core/mainloop/mainloop_state.inc"
+#undef CONF_CONTEXT
+
+/** Magic number for mainloop state objects */
+#define MAINLOOP_STATE_MAGIC 0x59455449
+
+/**
+ * Format object for mainloop state.
+ **/
+static config_format_t mainloop_state_fmt = {
+ .size = sizeof(mainloop_state_t),
+ .magic = { "mainloop_state",
+ MAINLOOP_STATE_MAGIC,
+ offsetof(mainloop_state_t, magic)
+ },
+ .vars = mainloop_state_t_vars,
+};
+
+/**
+ */
+static int
+mainloop_set_state(void *arg)
+{
+ const mainloop_state_t *state = arg;
+ tor_assert(state->magic == MAINLOOP_STATE_MAGIC);
+
+ netstatus_load_from_state(state, approx_time());
+
+ return 0;
+}
+
+static int
+mainloop_flush_state(void *arg)
+{
+ mainloop_state_t *state = arg;
+ tor_assert(state->magic == MAINLOOP_STATE_MAGIC);
+
+ netstatus_flush_to_state(state, approx_time());
+
+ return 0;
+}
+
const struct subsys_fns_t sys_mainloop = {
.name = "mainloop",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = 5,
.initialize = subsys_mainloop_initialize,
.shutdown = subsys_mainloop_shutdown,
+
+ .state_format = &mainloop_state_fmt,
+ .set_state = mainloop_set_state,
+ .flush_state = mainloop_flush_state,
};
diff --git a/src/core/mainloop/mainloop_sys.h b/src/core/mainloop/mainloop_sys.h
index fa74fe5d4b..b3ade33cd1 100644
--- a/src/core/mainloop/mainloop_sys.h
+++ b/src/core/mainloop/mainloop_sys.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file mainloop_sys.h
+ * @brief Header for mainloop_sys.c
+ **/
+
#ifndef MAINLOOP_SYS_H
#define MAINLOOP_SYS_H
diff --git a/src/core/mainloop/netstatus.c b/src/core/mainloop/netstatus.c
index 4924888598..61a3469eaa 100644
--- a/src/core/mainloop/netstatus.c
+++ b/src/core/mainloop/netstatus.c
@@ -1,12 +1,18 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file netstatus.c
+ * @brief Track whether the network is disabled, dormant, etc.
+ **/
+
#include "core/or/or.h"
#include "core/mainloop/netstatus.h"
#include "core/mainloop/mainloop.h"
+#include "core/mainloop/mainloop_state_st.h"
#include "app/config/config.h"
#include "feature/hibernate/hibernate.h"
@@ -110,7 +116,7 @@ is_participating_on_network(void)
* Update 'state' with the last time at which we were active on the network.
**/
void
-netstatus_flush_to_state(or_state_t *state, time_t now)
+netstatus_flush_to_state(mainloop_state_t *state, time_t now)
{
state->Dormant = ! participating_on_network;
if (participating_on_network) {
@@ -125,7 +131,7 @@ netstatus_flush_to_state(or_state_t *state, time_t now)
* Update our current view of network participation from an or_state_t object.
**/
void
-netstatus_load_from_state(const or_state_t *state, time_t now)
+netstatus_load_from_state(const mainloop_state_t *state, time_t now)
{
time_t last_activity;
if (state->Dormant == -1) { // Initial setup.
diff --git a/src/core/mainloop/netstatus.h b/src/core/mainloop/netstatus.h
index e8469ff558..5f54e54553 100644
--- a/src/core/mainloop/netstatus.h
+++ b/src/core/mainloop/netstatus.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file netstatus.h
+ * @brief Header for netstatus.c
+ **/
+
#ifndef TOR_NETSTATUS_H
#define TOR_NETSTATUS_H
@@ -17,8 +22,11 @@ time_t get_last_user_activity_time(void);
void set_network_participation(bool participation);
bool is_participating_on_network(void);
-void netstatus_flush_to_state(or_state_t *state, time_t now);
-void netstatus_load_from_state(const or_state_t *state, time_t now);
+struct mainloop_state_t;
+
+void netstatus_flush_to_state(struct mainloop_state_t *state, time_t now);
+void netstatus_load_from_state(const struct mainloop_state_t *state,
+ time_t now);
void netstatus_note_clock_jumped(time_t seconds_diff);
#endif /* !defined(TOR_NETSTATUS_H) */
diff --git a/src/core/mainloop/periodic.c b/src/core/mainloop/periodic.c
index 5c2f6f2b36..b5fd8fab61 100644
--- a/src/core/mainloop/periodic.c
+++ b/src/core/mainloop/periodic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,7 +29,6 @@
#include "app/config/config.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/periodic.h"
-#include "lib/evloop/compat_libevent.h"
/** We disable any interval greater than this number of seconds, on the
* grounds that it is probably an absolute time mistakenly passed in as a
@@ -39,7 +38,7 @@ static const int MAX_INTERVAL = 10 * 365 * 86400;
/**
* Global list of periodic events that have been registered with
- * <b>periodic_event_register</a>.
+ * <b>periodic_event_register</b>.
**/
static smartlist_t *the_periodic_events = NULL;
diff --git a/src/core/mainloop/periodic.h b/src/core/mainloop/periodic.h
index a9aa461969..de556a6bdb 100644
--- a/src/core/mainloop/periodic.h
+++ b/src/core/mainloop/periodic.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file periodic.h
+ * @brief Header for periodic.c
+ **/
+
#ifndef TOR_PERIODIC_H
#define TOR_PERIODIC_H
@@ -71,8 +76,10 @@ typedef struct periodic_event_item_t {
} periodic_event_item_t;
/** events will get their interval from first execution */
+#ifndef COCCI
#define PERIODIC_EVENT(fn, r, f) { fn##_callback, 0, NULL, #fn, r, f, 0 }
#define END_OF_PERIODIC_EVENTS { NULL, 0, NULL, NULL, 0, 0, 0 }
+#endif
/* Return true iff the given event was setup before thus is enabled to be
* scheduled. */
diff --git a/src/core/or/.may_include b/src/core/or/.may_include
index 5173e8a2b6..beb12f155d 100644
--- a/src/core/or/.may_include
+++ b/src/core/or/.may_include
@@ -35,4 +35,6 @@ trunnel/*.h
core/mainloop/*.h
core/proto/*.h
core/crypto/*.h
-core/or/*.h \ No newline at end of file
+core/or/*.h
+
+ext/*.h
diff --git a/src/core/or/addr_policy_st.h b/src/core/or/addr_policy_st.h
index 11442d29b4..08d16ee616 100644
--- a/src/core/or/addr_policy_st.h
+++ b/src/core/or/addr_policy_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file addr_policy_st.h
+ * @brief Address policy structures.
+ **/
+
#ifndef TOR_ADDR_POLICY_ST_H
#define TOR_ADDR_POLICY_ST_H
@@ -33,7 +38,7 @@ struct addr_policy_t {
/** Base address to accept or reject.
*
* Note that wildcards are treated
- * differntly depending on address family. An AF_UNSPEC address means
+ * differently depending on address family. An AF_UNSPEC address means
* "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means
* "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means
* "All IPv6 addresses".
diff --git a/src/core/or/address_set.c b/src/core/or/address_set.c
index 758fba4aac..d618ffc3d6 100644
--- a/src/core/or/address_set.c
+++ b/src/core/or/address_set.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,7 +17,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "siphash.h"
-/* Wrap our hash function to have the signature that the bloom filter
+/** Wrap our hash function to have the signature that the bloom filter
* needs. */
static uint64_t
bloomfilt_addr_hash(const struct sipkey *key,
diff --git a/src/core/or/address_set.h b/src/core/or/address_set.h
index 95608a9a53..33887a7c9e 100644
--- a/src/core/or/address_set.h
+++ b/src/core/or/address_set.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 7ba339b965..0681dba1b8 100644
--- a/src/core/or/cell_queue_st.h
+++ b/src/core/or/cell_queue_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file cell_queue_st.h
+ * @brief Cell queue structures
+ **/
+
#ifndef PACKED_CELL_ST_H
#define PACKED_CELL_ST_H
@@ -22,7 +27,7 @@ struct packed_cell_t {
* or_connection_t's outbuf. */
struct cell_queue_t {
/** Linked list of packed_cell_t*/
- TOR_SIMPLEQ_HEAD(cell_simpleq, packed_cell_t) head;
+ TOR_SIMPLEQ_HEAD(cell_simpleq_t, packed_cell_t) head;
int n; /**< The number of cells in the queue. */
};
diff --git a/src/core/or/cell_st.h b/src/core/or/cell_st.h
index c4eec4f4b5..a640d6a456 100644
--- a/src/core/or/cell_st.h
+++ b/src/core/or/cell_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file cell_st.h
+ * @brief Fixed-size cell structure.
+ **/
+
#ifndef CELL_ST_H
#define CELL_ST_H
@@ -17,4 +22,3 @@ struct cell_t {
};
#endif /* !defined(CELL_ST_H) */
-
diff --git a/src/core/or/channel.c b/src/core/or/channel.c
index 596932b008..5ed6bb9272 100644
--- a/src/core/or/channel.c
+++ b/src/core/or/channel.c
@@ -1,5 +1,4 @@
-
-/* * Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -52,10 +51,10 @@
* Define this so channel.h gives us things only channel_t subclasses
* should touch.
*/
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
/* This one's for stuff only channel.c and the test suite should see */
-#define CHANNEL_PRIVATE_
+#define CHANNEL_FILE_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
@@ -72,6 +71,7 @@
#include "core/or/relay.h"
#include "core/or/scheduler.h"
#include "feature/client/entrynodes.h"
+#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
@@ -84,6 +84,13 @@
#include "core/or/cell_queue_st.h"
+/* Static function prototypes */
+
+static bool channel_matches_target_addr_for_extend(
+ channel_t *chan,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr);
+
/* Global lists of channels */
/* All channel_t instances */
@@ -106,7 +113,7 @@ static smartlist_t *finished_listeners = NULL;
/** Map from channel->global_identifier to channel. Contains the same
* elements as all_channels. */
-static HT_HEAD(channel_gid_map, channel_s) channel_gid_map = HT_INITIALIZER();
+static HT_HEAD(channel_gid_map, channel_t) channel_gid_map = HT_INITIALIZER();
static unsigned
channel_id_hash(const channel_t *chan)
@@ -118,13 +125,13 @@ channel_id_eq(const channel_t *a, const channel_t *b)
{
return a->global_identifier == b->global_identifier;
}
-HT_PROTOTYPE(channel_gid_map, channel_s, gidmap_node,
- channel_id_hash, channel_id_eq)
-HT_GENERATE2(channel_gid_map, channel_s, gidmap_node,
+HT_PROTOTYPE(channel_gid_map, channel_t, gidmap_node,
+ channel_id_hash, channel_id_eq);
+HT_GENERATE2(channel_gid_map, channel_t, gidmap_node,
channel_id_hash, channel_id_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
-HANDLE_IMPL(channel, channel_s,)
+HANDLE_IMPL(channel, channel_t,)
/* Counter for ID numbers */
static uint64_t n_channels_allocated = 0;
@@ -137,13 +144,13 @@ static uint64_t n_channels_allocated = 0;
* If more than one channel exists, follow the next_with_same_id pointer
* as a linked list.
*/
-static HT_HEAD(channel_idmap, channel_idmap_entry_s) channel_identity_map =
+static HT_HEAD(channel_idmap, channel_idmap_entry_t) channel_identity_map =
HT_INITIALIZER();
-typedef struct channel_idmap_entry_s {
- HT_ENTRY(channel_idmap_entry_s) node;
+typedef struct channel_idmap_entry_t {
+ HT_ENTRY(channel_idmap_entry_t) node;
uint8_t digest[DIGEST_LEN];
- TOR_LIST_HEAD(channel_list_s, channel_s) channel_list;
+ TOR_LIST_HEAD(channel_list_t, channel_t) channel_list;
} channel_idmap_entry_t;
static inline unsigned
@@ -159,10 +166,10 @@ channel_idmap_eq(const channel_idmap_entry_t *a,
return tor_memeq(a->digest, b->digest, DIGEST_LEN);
}
-HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
- channel_idmap_eq)
-HT_GENERATE2(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
- channel_idmap_eq, 0.5, tor_reallocarray_, tor_free_)
+HT_PROTOTYPE(channel_idmap, channel_idmap_entry_t, node, channel_idmap_hash,
+ channel_idmap_eq);
+HT_GENERATE2(channel_idmap, channel_idmap_entry_t, node, channel_idmap_hash,
+ channel_idmap_eq, 0.5, tor_reallocarray_, tor_free_);
/* Functions to maintain the digest map */
static void channel_remove_from_digest_map(channel_t *chan);
@@ -749,6 +756,7 @@ channel_check_for_duplicates(void)
{
channel_idmap_entry_t **iter;
channel_t *chan;
+ int total_dirauth_connections = 0, total_dirauths = 0;
int total_relay_connections = 0, total_relays = 0, total_canonical = 0;
int total_half_canonical = 0;
int total_gt_one_connection = 0, total_gt_two_connections = 0;
@@ -756,13 +764,18 @@ channel_check_for_duplicates(void)
HT_FOREACH(iter, channel_idmap, &channel_identity_map) {
int connections_to_relay = 0;
+ const char *id_digest = (char *) (*iter)->digest;
/* Only consider relay connections */
- if (!connection_or_digest_is_known_relay((char*)(*iter)->digest))
+ if (!connection_or_digest_is_known_relay(id_digest))
continue;
total_relays++;
+ const bool is_dirauth = router_digest_is_trusted_dir(id_digest);
+ if (is_dirauth)
+ total_dirauths++;
+
for (chan = TOR_LIST_FIRST(&(*iter)->channel_list); chan;
chan = channel_next_with_rsa_identity(chan)) {
@@ -771,11 +784,12 @@ channel_check_for_duplicates(void)
connections_to_relay++;
total_relay_connections++;
+ if (is_dirauth)
+ total_dirauth_connections++;
- if (chan->is_canonical(chan, 0)) total_canonical++;
+ if (chan->is_canonical(chan)) total_canonical++;
- if (!chan->is_canonical_to_peer && chan->is_canonical(chan, 0)
- && chan->is_canonical(chan, 1)) {
+ if (!chan->is_canonical_to_peer && chan->is_canonical(chan)) {
total_half_canonical++;
}
}
@@ -785,11 +799,28 @@ channel_check_for_duplicates(void)
if (connections_to_relay > 4) total_gt_four_connections++;
}
-#define MIN_RELAY_CONNECTIONS_TO_WARN 5
+ /* Don't bother warning about excessive connections unless we have
+ * at least this many connections, total.
+ */
+#define MIN_RELAY_CONNECTIONS_TO_WARN 25
+ /* If the average number of connections for a regular relay is more than
+ * this, that's too high.
+ */
+#define MAX_AVG_RELAY_CONNECTIONS 1.5
+ /* If the average number of connections for a dirauth is more than
+ * this, that's too high.
+ */
+#define MAX_AVG_DIRAUTH_CONNECTIONS 4
+
+ /* How many connections total would be okay, given the number of
+ * relays and dirauths that we have connections to? */
+ const int max_tolerable_connections = (int)(
+ (total_relays-total_dirauths) * MAX_AVG_RELAY_CONNECTIONS +
+ total_dirauths * MAX_AVG_DIRAUTH_CONNECTIONS);
/* If we average 1.5 or more connections per relay, something is wrong */
if (total_relays > MIN_RELAY_CONNECTIONS_TO_WARN &&
- total_relay_connections >= 1.5*total_relays) {
+ total_relay_connections > max_tolerable_connections) {
log_notice(LD_OR,
"Your relay has a very large number of connections to other relays. "
"Is your outbound address the same as your relay address? "
@@ -1067,23 +1098,6 @@ channel_get_cell_handler(channel_t *chan)
}
/**
- * Return the variable-length cell handler for a channel.
- *
- * This function gets the handler for incoming variable-length cells
- * installed on a channel.
- */
-channel_var_cell_handler_fn_ptr
-channel_get_var_cell_handler(channel_t *chan)
-{
- tor_assert(chan);
-
- if (CHANNEL_CAN_HANDLE_CELLS(chan))
- return chan->var_cell_handler;
-
- return NULL;
-}
-
-/**
* Set both cell handlers for a channel.
*
* This function sets both the fixed-length and variable length cell handlers
@@ -1091,9 +1105,7 @@ channel_get_var_cell_handler(channel_t *chan)
*/
void
channel_set_cell_handlers(channel_t *chan,
- channel_cell_handler_fn_ptr cell_handler,
- channel_var_cell_handler_fn_ptr
- var_cell_handler)
+ channel_cell_handler_fn_ptr cell_handler)
{
tor_assert(chan);
tor_assert(CHANNEL_CAN_HANDLE_CELLS(chan));
@@ -1101,13 +1113,9 @@ channel_set_cell_handlers(channel_t *chan,
log_debug(LD_CHANNEL,
"Setting cell_handler callback for channel %p to %p",
chan, cell_handler);
- log_debug(LD_CHANNEL,
- "Setting var_cell_handler callback for channel %p to %p",
- chan, var_cell_handler);
/* Change them */
chan->cell_handler = cell_handler;
- chan->var_cell_handler = var_cell_handler;
}
/*
@@ -2358,7 +2366,7 @@ channel_is_better(channel_t *a, channel_t *b)
if (!a->is_canonical_to_peer && b->is_canonical_to_peer) return 0;
/*
- * Okay, if we're here they tied on canonicity, the prefer the older
+ * Okay, if we're here they tied on canonicity. Prefer the older
* connection, so that the adversary can't create a new connection
* and try to switch us over to it (which will leak information
* about long-lived circuits). Additionally, switching connections
@@ -2383,19 +2391,23 @@ channel_is_better(channel_t *a, channel_t *b)
/**
* Get a channel to extend a circuit.
*
- * Pick a suitable channel to extend a circuit to given the desired digest
- * the address we believe is correct for that digest; this tries to see
- * if we already have one for the requested endpoint, but if there is no good
- * channel, set *msg_out to a message describing the channel's state
- * and our next action, and set *launch_out to a boolean indicated whether
- * the caller should try to launch a new channel with channel_connect().
+ * Given the desired relay identity, pick a suitable channel to extend a
+ * circuit to the target IPv4 or IPv6 address requsted by the client. Search
+ * for an existing channel for the requested endpoint. Make sure the channel
+ * is usable for new circuits, and matches one of the target addresses.
+ *
+ * Try to return the best channel. But if there is no good channel, set
+ * *msg_out to a message describing the channel's state and our next action,
+ * and set *launch_out to a boolean indicated whether the caller should try to
+ * launch a new channel with channel_connect().
*/
-channel_t *
-channel_get_for_extend(const char *rsa_id_digest,
- const ed25519_public_key_t *ed_id,
- const tor_addr_t *target_addr,
- const char **msg_out,
- int *launch_out)
+MOCK_IMPL(channel_t *,
+channel_get_for_extend,(const char *rsa_id_digest,
+ const ed25519_public_key_t *ed_id,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr,
+ const char **msg_out,
+ int *launch_out))
{
channel_t *chan, *best = NULL;
int n_inprogress_goodaddr = 0, n_old = 0;
@@ -2406,9 +2418,7 @@ channel_get_for_extend(const char *rsa_id_digest,
chan = channel_find_by_remote_identity(rsa_id_digest, ed_id);
- /* Walk the list, unrefing the old one and refing the new at each
- * iteration.
- */
+ /* Walk the list of channels */
for (; chan; chan = channel_next_with_rsa_identity(chan)) {
tor_assert(tor_memeq(chan->identity_digest,
rsa_id_digest, DIGEST_LEN));
@@ -2427,11 +2437,15 @@ channel_get_for_extend(const char *rsa_id_digest,
continue;
}
+ const bool matches_target =
+ channel_matches_target_addr_for_extend(chan,
+ target_ipv4_addr,
+ target_ipv6_addr);
/* Never return a non-open connection. */
if (!CHANNEL_IS_OPEN(chan)) {
/* If the address matches, don't launch a new connection for this
* circuit. */
- if (channel_matches_target_addr_for_extend(chan, target_addr))
+ if (matches_target)
++n_inprogress_goodaddr;
continue;
}
@@ -2442,22 +2456,9 @@ channel_get_for_extend(const char *rsa_id_digest,
continue;
}
- /* Never return a non-canonical connection using a recent link protocol
- * if the address is not what we wanted.
- *
- * The channel_is_canonical_is_reliable() function asks the lower layer
- * if we should trust channel_is_canonical(). The below is from the
- * comments of the old circuit_or_get_for_extend() and applies when
- * the lower-layer transport is channel_tls_t.
- *
- * (For old link protocols, we can't rely on is_canonical getting
- * set properly if we're talking to the right address, since we might
- * have an out-of-date descriptor, and we will get no NETINFO cell to
- * tell us about the right address.)
- */
- if (!channel_is_canonical(chan) &&
- channel_is_canonical_is_reliable(chan) &&
- !channel_matches_target_addr_for_extend(chan, target_addr)) {
+ /* Only return canonical connections or connections where the address
+ * is the address we wanted. */
+ if (!channel_is_canonical(chan) && !matches_target) {
++n_noncanonical;
continue;
}
@@ -2598,16 +2599,12 @@ channel_dump_statistics, (channel_t *chan, int severity))
/* Handle marks */
tor_log(severity, LD_GENERAL,
- " * Channel %"PRIu64 " has these marks: %s %s %s "
- "%s %s %s",
+ " * Channel %"PRIu64 " has these marks: %s %s %s %s %s",
(chan->global_identifier),
channel_is_bad_for_new_circs(chan) ?
"bad_for_new_circs" : "!bad_for_new_circs",
channel_is_canonical(chan) ?
"canonical" : "!canonical",
- channel_is_canonical_is_reliable(chan) ?
- "is_canonical_is_reliable" :
- "!is_canonical_is_reliable",
channel_is_client(chan) ?
"client" : "!client",
channel_is_local(chan) ?
@@ -2843,8 +2840,8 @@ channel_get_actual_remote_address(channel_t *chan)
* Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
* may invalidate the return value from this function.
*/
-const char *
-channel_get_canonical_remote_descr(channel_t *chan)
+MOCK_IMPL(const char *,
+channel_get_canonical_remote_descr,(channel_t *chan))
{
tor_assert(chan);
tor_assert(chan->get_remote_descr);
@@ -2966,22 +2963,7 @@ channel_is_canonical(channel_t *chan)
tor_assert(chan);
tor_assert(chan->is_canonical);
- return chan->is_canonical(chan, 0);
-}
-
-/**
- * Test if the canonical flag is reliable.
- *
- * This function asks if the lower layer thinks it's safe to trust the
- * result of channel_is_canonical().
- */
-int
-channel_is_canonical_is_reliable(channel_t *chan)
-{
- tor_assert(chan);
- tor_assert(chan->is_canonical);
-
- return chan->is_canonical(chan, 1);
+ return chan->is_canonical(chan);
}
/**
@@ -3320,20 +3302,33 @@ channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
}
/**
- * Check if a channel matches a given target address; return true iff we do.
+ * Check if a channel matches the given target IPv4 or IPv6 addresses.
+ * If either address matches, return true. If neither address matches,
+ * return false.
+ *
+ * Both addresses can't be NULL.
*
* This function calls into the lower layer and asks if this channel thinks
- * it matches a given target address for circuit extension purposes.
+ * it matches the target addresses for circuit extension purposes.
*/
-int
+static bool
channel_matches_target_addr_for_extend(channel_t *chan,
- const tor_addr_t *target)
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr)
{
tor_assert(chan);
tor_assert(chan->matches_target);
- tor_assert(target);
- return chan->matches_target(chan, target);
+ IF_BUG_ONCE(!target_ipv4_addr && !target_ipv6_addr)
+ return false;
+
+ if (target_ipv4_addr && chan->matches_target(chan, target_ipv4_addr))
+ return true;
+
+ if (target_ipv6_addr && chan->matches_target(chan, target_ipv6_addr))
+ return true;
+
+ return false;
}
/**
@@ -3406,7 +3401,7 @@ channel_sort_by_ed25519_identity(const void **a_, const void **b_)
* all of which MUST have the same RSA ID. (They MAY have different
* Ed25519 IDs.) */
static void
-channel_rsa_id_group_set_badness(struct channel_list_s *lst, int force)
+channel_rsa_id_group_set_badness(struct channel_list_t *lst, int force)
{
/*XXXX This function should really be about channels. 15056 */
channel_t *chan = TOR_LIST_FIRST(lst);
diff --git a/src/core/or/channel.h b/src/core/or/channel.h
index 97aa000337..82d89471b4 100644
--- a/src/core/or/channel.h
+++ b/src/core/or/channel.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@
#include "lib/container/handles.h"
#include "lib/crypt_ops/crypto_ed25519.h"
+#include "ext/ht.h"
#include "tor_queue.h"
#define tor_timer_t timeout
@@ -22,7 +23,6 @@ struct tor_timer_t;
/* Channel handler function pointer typedefs */
typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *);
typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *);
-typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *);
/**
* This enum is used by channelpadding to decide when to pad channels.
@@ -48,7 +48,7 @@ typedef enum {
/* channel states for channel_t */
typedef enum {
- /*
+ /**
* Closed state - channel is inactive
*
* Permitted transitions from:
@@ -57,7 +57,7 @@ typedef enum {
* - CHANNEL_STATE_OPENING
*/
CHANNEL_STATE_CLOSED = 0,
- /*
+ /**
* Opening state - channel is trying to connect
*
* Permitted transitions from:
@@ -68,7 +68,7 @@ typedef enum {
* - CHANNEL_STATE_OPEN
*/
CHANNEL_STATE_OPENING,
- /*
+ /**
* Open state - channel is active and ready for use
*
* Permitted transitions from:
@@ -80,7 +80,7 @@ typedef enum {
* - CHANNEL_STATE_MAINT
*/
CHANNEL_STATE_OPEN,
- /*
+ /**
* Maintenance state - channel is temporarily offline for subclass specific
* maintenance activities such as TLS renegotiation.
*
@@ -92,7 +92,7 @@ typedef enum {
* - CHANNEL_STATE_OPEN
*/
CHANNEL_STATE_MAINT,
- /*
+ /**
* Closing state - channel is shutting down
*
* Permitted transitions from:
@@ -103,7 +103,7 @@ typedef enum {
* - CHANNEL_STATE_ERROR
*/
CHANNEL_STATE_CLOSING,
- /*
+ /**
* Error state - channel has experienced a permanent error
*
* Permitted transitions from:
@@ -115,7 +115,7 @@ typedef enum {
* - None
*/
CHANNEL_STATE_ERROR,
- /*
+ /**
* Placeholder for maximum state value
*/
CHANNEL_STATE_LAST
@@ -124,7 +124,7 @@ typedef enum {
/* channel listener states for channel_listener_t */
typedef enum {
- /*
+ /**
* Closed state - channel listener is inactive
*
* Permitted transitions from:
@@ -133,7 +133,7 @@ typedef enum {
* - CHANNEL_LISTENER_STATE_LISTENING
*/
CHANNEL_LISTENER_STATE_CLOSED = 0,
- /*
+ /**
* Listening state - channel listener is listening for incoming
* connections
*
@@ -144,7 +144,7 @@ typedef enum {
* - CHANNEL_LISTENER_STATE_ERROR
*/
CHANNEL_LISTENER_STATE_LISTENING,
- /*
+ /**
* Closing state - channel listener is shutting down
*
* Permitted transitions from:
@@ -154,7 +154,7 @@ typedef enum {
* - CHANNEL_LISTENER_STATE_ERROR
*/
CHANNEL_LISTENER_STATE_CLOSING,
- /*
+ /**
* Error state - channel listener has experienced a permanent error
*
* Permitted transitions from:
@@ -164,7 +164,7 @@ typedef enum {
* - None
*/
CHANNEL_LISTENER_STATE_ERROR,
- /*
+ /**
* Placeholder for maximum state value
*/
CHANNEL_LISTENER_STATE_LAST
@@ -178,15 +178,15 @@ typedef enum {
* to a particular node, and once constructed support the abstract operations
* defined below.
*/
-struct channel_s {
+struct channel_t {
/** Magic number for type-checking cast macros */
uint32_t magic;
/** List entry for hashtable for global-identifier lookup. */
- HT_ENTRY(channel_s) gidmap_node;
+ HT_ENTRY(channel_t) gidmap_node;
/** Handle entry for handle-based lookup */
- HANDLE_ENTRY(channel, channel_s);
+ HANDLE_ENTRY(channel, channel_t);
/** Current channel state */
channel_state_t state;
@@ -267,21 +267,21 @@ struct channel_s {
/** State variable for use by the scheduler */
enum {
- /*
+ /**
* The channel is not open, or it has a full output buffer but no queued
* cells.
*/
SCHED_CHAN_IDLE = 0,
- /*
+ /**
* The channel has space on its output buffer to write, but no queued
* cells.
*/
SCHED_CHAN_WAITING_FOR_CELLS,
- /*
+ /**
* The scheduler has queued cells but no output buffer space to write.
*/
SCHED_CHAN_WAITING_TO_WRITE,
- /*
+ /**
* The scheduler has both queued cells and output buffer space, and is
* eligible for the scheduler loop.
*/
@@ -320,7 +320,6 @@ struct channel_s {
/** Registered handlers for incoming cells */
channel_cell_handler_fn_ptr cell_handler;
- channel_var_cell_handler_fn_ptr var_cell_handler;
/* Methods implemented by the lower layer */
@@ -351,12 +350,10 @@ struct channel_s {
/** Check if the lower layer has queued writes */
int (*has_queued_writes)(channel_t *);
/**
- * If the second param is zero, ask the lower layer if this is
- * 'canonical', for a transport-specific definition of canonical; if
- * it is 1, ask if the answer to the preceding query is safe to rely
- * on.
+ * Ask the lower layer if this is 'canonical', for a transport-specific
+ * definition of canonical.
*/
- int (*is_canonical)(channel_t *, int);
+ int (*is_canonical)(channel_t *);
/** Check if this channel matches a specified extend_info_t */
int (*matches_extend_info)(channel_t *, extend_info_t *);
/** Check if this channel matches a target address when extending */
@@ -397,7 +394,7 @@ struct channel_s {
* Linked list of channels with the same RSA identity digest, for use with
* the digest->channel map
*/
- TOR_LIST_ENTRY(channel_s) next_with_same_id;
+ TOR_LIST_ENTRY(channel_t) next_with_same_id;
/** Circuit mux for circuits sending on this channel */
circuitmux_t *cmux;
@@ -444,9 +441,9 @@ struct channel_s {
ratelim_t last_warned_circ_ids_exhausted;
/** Channel timestamps for cell channels */
- time_t timestamp_client; /* Client used this, according to relay.c */
- time_t timestamp_recv; /* Cell received from lower layer */
- time_t timestamp_xmit; /* Cell sent to lower layer */
+ time_t timestamp_client; /*(< Client used this, according to relay.c */
+ time_t timestamp_recv; /**< Cell received from lower layer */
+ time_t timestamp_xmit; /**< Cell sent to lower layer */
/** Timestamp for run_connection_housekeeping(). We update this once a
* second when we run housekeeping and find a circuit on this channel, and
@@ -458,16 +455,17 @@ struct channel_s {
* distinct namespace. */
uint64_t dirreq_id;
- /** Channel counters for cell channels */
+ /** Channel counters for cells and bytes we have received. */
uint64_t n_cells_recved, n_bytes_recved;
+ /** Channel counters for cells and bytes we have sent. */
uint64_t n_cells_xmitted, n_bytes_xmitted;
};
-struct channel_listener_s {
- /* Current channel listener state */
+struct channel_listener_t {
+ /** Current channel listener state */
channel_listener_state_t state;
- /* Globally unique ID number for a channel over the lifetime of a Tor
+ /** Globally unique ID number for a channel over the lifetime of a Tor
* process.
*/
uint64_t global_identifier;
@@ -541,13 +539,8 @@ void channel_listener_set_listener_fn(channel_listener_t *chan,
/* Incoming cell callbacks */
channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan);
-channel_var_cell_handler_fn_ptr
-channel_get_var_cell_handler(channel_t *chan);
-
void channel_set_cell_handlers(channel_t *chan,
- channel_cell_handler_fn_ptr cell_handler,
- channel_var_cell_handler_fn_ptr
- var_cell_handler);
+ channel_cell_handler_fn_ptr cell_handler);
/* Clean up closed channels and channel listeners periodically; these are
* called from run_scheduled_events() in main.c.
@@ -562,13 +555,13 @@ void channel_free_all(void);
void channel_dumpstats(int severity);
void channel_listener_dumpstats(int severity);
-#ifdef TOR_CHANNEL_INTERNAL_
+#ifdef CHANNEL_OBJECT_PRIVATE
-#ifdef CHANNEL_PRIVATE_
+#ifdef CHANNEL_FILE_PRIVATE
STATIC void channel_add_to_digest_map(channel_t *chan);
-#endif /* defined(CHANNEL_PRIVATE_) */
+#endif /* defined(CHANNEL_FILE_PRIVATE) */
/* Channel operations for subclasses and internal use only */
@@ -647,7 +640,7 @@ void channel_notify_flushed(channel_t *chan);
/* Handle stuff we need to do on open like notifying circuits */
void channel_do_open_actions(channel_t *chan);
-#endif /* defined(TOR_CHANNEL_INTERNAL_) */
+#endif /* defined(CHANNEL_OBJECT_PRIVATE) */
/* Helper functions to perform operations on channels */
@@ -663,11 +656,13 @@ channel_t * channel_connect(const tor_addr_t *addr, uint16_t port,
const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id);
-channel_t * channel_get_for_extend(const char *rsa_id_digest,
+MOCK_DECL(channel_t *, channel_get_for_extend,(
+ const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id,
- const tor_addr_t *target_addr,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr,
const char **msg_out,
- int *launch_out);
+ int *launch_out));
/* Ask which of two channels is better for circuit-extension purposes */
int channel_is_better(channel_t *a, channel_t *b);
@@ -728,12 +723,11 @@ const char * channel_get_actual_remote_descr(channel_t *chan);
const char * channel_get_actual_remote_address(channel_t *chan);
MOCK_DECL(int, channel_get_addr_if_possible, (channel_t *chan,
tor_addr_t *addr_out));
-const char * channel_get_canonical_remote_descr(channel_t *chan);
+MOCK_DECL(const char *, channel_get_canonical_remote_descr,(channel_t *chan));
int channel_has_queued_writes(channel_t *chan);
int channel_is_bad_for_new_circs(channel_t *chan);
void channel_mark_bad_for_new_circs(channel_t *chan);
int channel_is_canonical(channel_t *chan);
-int channel_is_canonical_is_reliable(channel_t *chan);
int channel_is_client(const channel_t *chan);
int channel_is_local(channel_t *chan);
int channel_is_incoming(channel_t *chan);
@@ -741,8 +735,6 @@ int channel_is_outgoing(channel_t *chan);
void channel_mark_client(channel_t *chan);
void channel_clear_client(channel_t *chan);
int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info);
-int channel_matches_target_addr_for_extend(channel_t *chan,
- const tor_addr_t *target);
unsigned int channel_num_circuits(channel_t *chan);
MOCK_DECL(void,channel_set_circid_type,(channel_t *chan,
crypto_pk_t *identity_rcvd,
@@ -772,7 +764,7 @@ int packed_cell_is_destroy(channel_t *chan,
circid_t *circid_out);
/* Declare the handle helpers */
-HANDLE_DECL(channel, channel_s,)
+HANDLE_DECL(channel, channel_t,)
#define channel_handle_free(h) \
FREE_AND_NULL(channel_handle_t, channel_handle_free_, (h))
#undef tor_timer_t
diff --git a/src/core/or/channelpadding.c b/src/core/or/channelpadding.c
index 4a0f0e00da..be2ce78a17 100644
--- a/src/core/or/channelpadding.c
+++ b/src/core/or/channelpadding.c
@@ -1,12 +1,17 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-/* TOR_CHANNEL_INTERNAL_ define needed for an O(1) implementation of
+/**
+ * @file channelpadding.c
+ * @brief Link-level padding code.
+ **/
+
+/* CHANNEL_OBJECT_PRIVATE define needed for an O(1) implementation of
* channelpadding_channel_to_channelinfo() */
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#include "core/or/or.h"
#include "core/or/channel.h"
diff --git a/src/core/or/channelpadding.h b/src/core/or/channelpadding.h
index 48002eedb7..d1c7192ffd 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c
index d6c9e21631..56552f0095 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -34,7 +34,7 @@
* Define this so channel.h gives us things only channel_t subclasses
* should touch.
*/
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CHANNELTLS_PRIVATE
@@ -45,8 +45,10 @@
#include "core/or/circuitmux_ewma.h"
#include "core/or/command.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
+#include "feature/relay/relay_handshake.h"
#include "feature/control/control.h"
#include "feature/client/entrynodes.h"
#include "trunnel/link_handshake.h"
@@ -107,7 +109,7 @@ channel_tls_get_transport_name_method(channel_t *chan, char **transport_out);
static const char *
channel_tls_get_remote_descr_method(channel_t *chan, int flags);
static int channel_tls_has_queued_writes_method(channel_t *chan);
-static int channel_tls_is_canonical_method(channel_t *chan, int req);
+static int channel_tls_is_canonical_method(channel_t *chan);
static int
channel_tls_matches_extend_info_method(channel_t *chan,
extend_info_t *extend_info);
@@ -563,9 +565,7 @@ channel_tls_get_transport_name_method(channel_t *chan, char **transport_out)
static const char *
channel_tls_get_remote_descr_method(channel_t *chan, int flags)
{
-#define MAX_DESCR_LEN 32
-
- static char buf[MAX_DESCR_LEN + 1];
+ static char buf[TOR_ADDRPORT_BUF_LEN];
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
connection_t *conn;
const char *answer = NULL;
@@ -578,15 +578,14 @@ channel_tls_get_remote_descr_method(channel_t *chan, int flags)
switch (flags) {
case 0:
/* Canonical address with port*/
- tor_snprintf(buf, MAX_DESCR_LEN + 1,
+ tor_snprintf(buf, TOR_ADDRPORT_BUF_LEN,
"%s:%u", conn->address, conn->port);
answer = buf;
break;
case GRD_FLAG_ORIGINAL:
/* Actual address with port */
addr_str = tor_addr_to_str_dup(&(tlschan->conn->real_addr));
- tor_snprintf(buf, MAX_DESCR_LEN + 1,
- "%s:%u", addr_str, conn->port);
+ tor_snprintf(buf, TOR_ADDRPORT_BUF_LEN, "%s:%u", addr_str, conn->port);
tor_free(addr_str);
answer = buf;
break;
@@ -644,12 +643,11 @@ channel_tls_has_queued_writes_method(channel_t *chan)
/**
* Tell the upper layer if we're canonical.
*
- * This implements the is_canonical method for channel_tls_t; if req is zero,
- * it returns whether this is a canonical channel, and if it is one it returns
- * whether that can be relied upon.
+ * This implements the is_canonical method for channel_tls_t:
+ * it returns whether this is a canonical channel.
*/
static int
-channel_tls_is_canonical_method(channel_t *chan, int req)
+channel_tls_is_canonical_method(channel_t *chan)
{
int answer = 0;
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
@@ -657,24 +655,13 @@ channel_tls_is_canonical_method(channel_t *chan, int req)
tor_assert(tlschan);
if (tlschan->conn) {
- switch (req) {
- case 0:
- answer = tlschan->conn->is_canonical;
- break;
- case 1:
- /*
- * Is the is_canonical bit reliable? In protocols version 2 and up
- * we get the canonical address from a NETINFO cell, but in older
- * versions it might be based on an obsolete descriptor.
- */
- answer = (tlschan->conn->link_proto >= 2);
- break;
- default:
- /* This shouldn't happen; channel.c is broken if it does */
- tor_assert_nonfatal_unreached_once();
- }
+ /* If this bit is set to 0, and link_proto is sufficiently old, then we
+ * can't actually _rely_ on this being a non-canonical channel.
+ * Nonetheless, we're going to believe that this is a non-canonical
+ * channel in this case, since nobody should be using these link protocols
+ * any more. */
+ answer = tlschan->conn->is_canonical;
}
- /* else return 0 for tlschan->conn == NULL */
return answer;
}
@@ -737,10 +724,13 @@ channel_tls_matches_target_method(channel_t *chan,
* base_.addr is updated by connection_or_init_conn_from_address()
* to be the address in the descriptor. It may be tempting to
* allow either address to be allowed, but if we did so, it would
- * enable someone who steals a relay's keys to impersonate/MITM it
+ * enable someone who steals a relay's keys to covertly impersonate/MITM it
* from anywhere on the Internet! (Because they could make long-lived
* TLS connections from anywhere to all relays, and wait for them to
* be used for extends).
+ *
+ * An adversary who has stolen a relay's keys could also post a fake relay
+ * descriptor, but that attack is easier to detect.
*/
return tor_addr_eq(&(tlschan->conn->real_addr), target);
}
@@ -1664,7 +1654,7 @@ tor_addr_from_netinfo_addr(tor_addr_t *tor_addr,
} else if (type == NETINFO_ADDR_TYPE_IPV6 && len == 16) {
const uint8_t *ipv6_bytes = netinfo_addr_getconstarray_addr_ipv6(
netinfo_addr);
- tor_addr_from_ipv6_bytes(tor_addr, (const char *)ipv6_bytes);
+ tor_addr_from_ipv6_bytes(tor_addr, ipv6_bytes);
} else {
log_fn(LOG_PROTOCOL_WARN, LD_OR, "Cannot read address from NETINFO "
"- wrong type/length.");
diff --git a/src/core/or/channeltls.h b/src/core/or/channeltls.h
index 634a2a00e9..f04ce0fa9c 100644
--- a/src/core/or/channeltls.h
+++ b/src/core/or/channeltls.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,16 +22,16 @@ struct curve25519_public_key_t;
#define TLS_CHAN_MAGIC 0x8a192427U
-#ifdef TOR_CHANNEL_INTERNAL_
+#ifdef CHANNEL_OBJECT_PRIVATE
-struct channel_tls_s {
+struct channel_tls_t {
/* Base channel_t struct */
channel_t base_;
/* or_connection_t pointer */
or_connection_t *conn;
};
-#endif /* defined(TOR_CHANNEL_INTERNAL_) */
+#endif /* defined(CHANNEL_OBJECT_PRIVATE) */
channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port,
const char *id_digest,
diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h
index eae3c908d5..4baafb1848 100644
--- a/src/core/or/circuit_st.h
+++ b/src/core/or/circuit_st.h
@@ -1,15 +1,23 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file circuit_st.h
+ * @brief Base circuit structure.
+ **/
+
#ifndef CIRCUIT_ST_H
#define CIRCUIT_ST_H
#include "core/or/or.h"
+#include "lib/container/handles.h"
+
#include "core/or/cell_queue_st.h"
+#include "ext/ht.h"
struct hs_token_t;
struct circpad_machine_spec_t;
@@ -54,6 +62,9 @@ struct circuit_t {
uint32_t magic; /**< For memory and type debugging: must equal
* ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
+ /** Handle entry for handle-based lookup */
+ HANDLE_ENTRY(circuit, circuit_t);
+
/** The channel that is next in this circuit. */
channel_t *n_chan;
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 16bb7e7d79..a1b8ba78ab 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,8 +21,7 @@
* cells arrive, the client will invoke circuit_send_next_onion_skin() to send
* CREATE or RELAY_EXTEND cells.
*
- * On the server side, this module also handles the logic of responding to
- * RELAY_EXTEND requests, using circuit_extend().
+ * The server side is handled in feature/relay/circuitbuild_relay.c.
**/
#define CIRCUITBUILD_PRIVATE
@@ -30,12 +29,11 @@
#include "core/or/or.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "core/crypto/hs_ntor.h"
#include "core/crypto/onion_crypto.h"
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_tap.h"
-#include "core/crypto/relay_crypto.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/or/channel.h"
@@ -84,13 +82,6 @@
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerstatus_st.h"
-static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
- uint16_t port,
- const char *id_digest,
- const ed25519_public_key_t *ed_id);
-static int circuit_deliver_create_cell(circuit_t *circ,
- const create_cell_t *create_cell,
- int relayed);
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,
@@ -104,10 +95,10 @@ static const node_t *choose_good_middle_server(uint8_t purpose,
* and then calls command_setup_channel() to give it the right
* callbacks.
*/
-static channel_t *
-channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port,
- const char *id_digest,
- const ed25519_public_key_t *ed_id)
+MOCK_IMPL(channel_t *,
+channel_connect_for_circuit,(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest,
+ const struct ed25519_public_key_t *ed_id))
{
channel_t *chan;
@@ -568,11 +559,17 @@ circuit_handle_first_hop(origin_circuit_t *circ)
fmt_addrport(&firsthop->extend_info->addr,
firsthop->extend_info->port));
- n_chan = channel_get_for_extend(firsthop->extend_info->identity_digest,
- &firsthop->extend_info->ed_identity,
- &firsthop->extend_info->addr,
- &msg,
- &should_launch);
+ /* We'll cleanup this code in #33220, when we add an IPv6 address to
+ * extend_info_t. */
+ const bool addr_is_ipv4 =
+ (tor_addr_family(&firsthop->extend_info->addr) == AF_INET);
+ n_chan = channel_get_for_extend(
+ firsthop->extend_info->identity_digest,
+ &firsthop->extend_info->ed_identity,
+ addr_is_ipv4 ? &firsthop->extend_info->addr : NULL,
+ addr_is_ipv4 ? NULL : &firsthop->extend_info->addr,
+ &msg,
+ &should_launch);
if (!n_chan) {
/* not currently connected in a useful way. */
@@ -707,9 +704,10 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits)
* gave us via an EXTEND cell, so we shouldn't worry if we don't understand
* it. Return -1 if we failed to find a suitable circid, else return 0.
*/
-static int
-circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell,
- int relayed)
+MOCK_IMPL(int,
+circuit_deliver_create_cell,(circuit_t *circ,
+ const struct create_cell_t *create_cell,
+ int relayed))
{
cell_t cell;
circid_t id;
@@ -730,6 +728,8 @@ circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell,
goto error;
}
+ tor_assert_nonfatal_once(circ->n_chan->is_canonical);
+
memset(&cell, 0, sizeof(cell_t));
r = relayed ? create_cell_format_relayed(&cell, create_cell)
: create_cell_format(&cell, create_cell);
@@ -767,40 +767,6 @@ circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell,
return -1;
}
-/** We've decided to start our reachability testing. If all
- * is set, log this to the user. Return 1 if we did, or 0 if
- * we chose not to log anything. */
-int
-inform_testing_reachability(void)
-{
- char dirbuf[128];
- char *address;
- const routerinfo_t *me = router_get_my_routerinfo();
- if (!me)
- return 0;
- address = tor_dup_ip(me->addr);
- control_event_server_status(LOG_NOTICE,
- "CHECKING_REACHABILITY ORADDRESS=%s:%d",
- address, me->or_port);
- if (me->dir_port) {
- tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d",
- address, me->dir_port);
- control_event_server_status(LOG_NOTICE,
- "CHECKING_REACHABILITY DIRADDRESS=%s:%d",
- address, me->dir_port);
- }
- log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... "
- "(this may take up to %d minutes -- look for log "
- "messages indicating success)",
- address, me->or_port,
- me->dir_port ? dirbuf : "",
- me->dir_port ? "are" : "is",
- TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
-
- tor_free(address);
- return 1;
-}
-
/** Return true iff we should send a create_fast cell to start building a given
* circuit */
static inline int
@@ -1200,164 +1166,6 @@ circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle)
}
}
-/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion
- * skin and identity digest for the next hop. If we're already connected,
- * pass the onion skin to the next hop using a create cell; otherwise
- * launch a new OR connection, and <b>circ</b> will notice when the
- * connection succeeds or fails.
- *
- * Return -1 if we want to warn and tear down the circuit, else return 0.
- */
-int
-circuit_extend(cell_t *cell, circuit_t *circ)
-{
- channel_t *n_chan;
- relay_header_t rh;
- extend_cell_t ec;
- const char *msg = NULL;
- int should_launch = 0;
-
- if (circ->n_chan) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "n_chan already set. Bug/attack. Closing.");
- return -1;
- }
- if (circ->n_hop) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "conn to next hop already launched. Bug/attack. Closing.");
- return -1;
- }
-
- if (!server_mode(get_options())) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Got an extend cell, but running as a client. Closing.");
- return -1;
- }
-
- relay_header_unpack(&rh, cell->payload);
-
- if (extend_cell_parse(&ec, rh.command,
- cell->payload+RELAY_HEADER_SIZE,
- rh.length) < 0) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Can't parse extend cell. Closing circuit.");
- return -1;
- }
-
- if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend to zero destination port or addr.");
- return -1;
- }
-
- if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) &&
- !get_options()->ExtendAllowPrivateAddresses) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend to a private address");
- return -1;
- }
-
- /* Check if they asked us for 0000..0000. We support using
- * an empty fingerprint for the first hop (e.g. for a bridge relay),
- * but we don't want to let clients send us extend cells for empty
- * fingerprints -- a) because it opens the user up to a mitm attack,
- * and b) because it lets an attacker force the relay to hold open a
- * new TLS connection for each extend request. */
- if (tor_digest_is_zero((const char*)ec.node_id)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend without specifying an id_digest.");
- return -1;
- }
-
- /* Fill in ed_pubkey if it was not provided and we can infer it from
- * our networkstatus */
- if (ed25519_public_key_is_zero(&ec.ed_pubkey)) {
- const node_t *node = node_get_by_id((const char*)ec.node_id);
- const ed25519_public_key_t *node_ed_id = NULL;
- if (node &&
- node_supports_ed25519_link_authentication(node, 1) &&
- (node_ed_id = node_get_ed25519_id(node))) {
- ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id);
- }
- }
-
- /* Next, check if we're being asked to connect to the hop that the
- * extend cell came from. There isn't any reason for that, and it can
- * assist circular-path attacks. */
- if (tor_memeq(ec.node_id,
- TO_OR_CIRCUIT(circ)->p_chan->identity_digest,
- DIGEST_LEN)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend back to the previous hop.");
- return -1;
- }
-
- /* Check the previous hop Ed25519 ID too */
- if (! ed25519_public_key_is_zero(&ec.ed_pubkey) &&
- ed25519_pubkey_eq(&ec.ed_pubkey,
- &TO_OR_CIRCUIT(circ)->p_chan->ed25519_identity)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend back to the previous hop "
- "(by Ed25519 ID).");
- return -1;
- }
-
- n_chan = channel_get_for_extend((const char*)ec.node_id,
- &ec.ed_pubkey,
- &ec.orport_ipv4.addr,
- &msg,
- &should_launch);
-
- if (!n_chan) {
- log_debug(LD_CIRC|LD_OR,"Next router (%s): %s",
- fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port),
- msg?msg:"????");
-
- circ->n_hop = extend_info_new(NULL /*nickname*/,
- (const char*)ec.node_id,
- &ec.ed_pubkey,
- NULL, /*onion_key*/
- NULL, /*curve25519_key*/
- &ec.orport_ipv4.addr,
- ec.orport_ipv4.port);
-
- circ->n_chan_create_cell = tor_memdup(&ec.create_cell,
- sizeof(ec.create_cell));
-
- circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
-
- if (should_launch) {
- /* we should try to open a connection */
- n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr,
- ec.orport_ipv4.port,
- (const char*)ec.node_id,
- &ec.ed_pubkey);
- if (!n_chan) {
- log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
- circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
- return 0;
- }
- log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
- }
- /* return success. The onion/circuit/etc will be taken care of
- * automatically (may already have been) whenever n_chan reaches
- * OR_CONN_STATE_OPEN.
- */
- return 0;
- }
-
- tor_assert(!circ->n_hop); /* Connection is already established. */
- circ->n_chan = n_chan;
- log_debug(LD_CIRC,
- "n_chan is %s",
- channel_get_canonical_remote_descr(n_chan));
-
- if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
- return -1;
-
- return 0;
-}
-
/** A "created" cell <b>reply</b> came back to us on circuit <b>circ</b>.
* (The body of <b>reply</b> varies depending on what sort of handshake
* this is.)
@@ -1467,61 +1275,6 @@ circuit_truncated(origin_circuit_t *circ, int reason)
#endif /* 0 */
}
-/** Given a response payload and keys, initialize, then send a created
- * cell back.
- */
-int
-onionskin_answer(or_circuit_t *circ,
- const created_cell_t *created_cell,
- const char *keys, size_t keys_len,
- const uint8_t *rend_circ_nonce)
-{
- cell_t cell;
-
- tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
-
- if (created_cell_format(&cell, created_cell) < 0) {
- log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d)",
- (int)created_cell->cell_type, (int)created_cell->handshake_len);
- return -1;
- }
- cell.circ_id = circ->p_circ_id;
-
- circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
-
- log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
- (unsigned int)get_uint32(keys),
- (unsigned int)get_uint32(keys+20));
- if (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) {
- log_warn(LD_BUG,"Circuit initialization failed");
- return -1;
- }
-
- memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
-
- int used_create_fast = (created_cell->cell_type == CELL_CREATED_FAST);
-
- append_cell_to_circuit_queue(TO_CIRCUIT(circ),
- circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
- log_debug(LD_CIRC,"Finished sending '%s' cell.",
- used_create_fast ? "created_fast" : "created");
-
- /* Ignore the local bit when ExtendAllowPrivateAddresses is set:
- * it violates the assumption that private addresses are local.
- * Also, many test networks run on local addresses, and
- * TestingTorNetwork sets ExtendAllowPrivateAddresses. */
- if ((!channel_is_local(circ->p_chan)
- || get_options()->ExtendAllowPrivateAddresses)
- && !channel_is_outgoing(circ->p_chan)) {
- /* record that we could process create cells from a non-local conn
- * that we didn't initiate; presumably this means that create cells
- * can reach us too. */
- router_orport_found_reachable();
- }
-
- return 0;
-}
-
/** Helper for new_route_len(). Choose a circuit length for purpose
* <b>purpose</b>: DEFAULT_ROUTE_LEN (+ 1 if someone else chose the
* exit). If someone else chose the exit, they could be colluding
@@ -2819,8 +2572,8 @@ extend_info_dup(extend_info_t *info)
* If there is no chosen exit, or if we don't know the node_t for
* the chosen exit, return NULL.
*/
-const node_t *
-build_state_get_exit_node(cpath_build_state_t *state)
+MOCK_IMPL(const node_t *,
+build_state_get_exit_node,(cpath_build_state_t *state))
{
if (!state || !state->chosen_exit)
return NULL;
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index ad7d032cd4..e62bb41de9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,19 +29,13 @@ struct circuit_guard_state_t *origin_circuit_get_guard_state(
int circuit_handle_first_hop(origin_circuit_t *circ);
void circuit_n_chan_done(channel_t *chan, int status,
int close_origin_circuits);
-int inform_testing_reachability(void);
int circuit_timeout_want_to_count_circ(const origin_circuit_t *circ);
int circuit_send_next_onion_skin(origin_circuit_t *circ);
void circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle);
-int circuit_extend(cell_t *cell, circuit_t *circ);
struct created_cell_t;
int circuit_finish_handshake(origin_circuit_t *circ,
const struct created_cell_t *created_cell);
int circuit_truncated(origin_circuit_t *circ, int reason);
-int onionskin_answer(or_circuit_t *circ,
- const struct created_cell_t *created_cell,
- const char *keys, size_t keys_len,
- const uint8_t *rend_circ_nonce);
MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
int *need_uptime,
int *need_capacity));
@@ -66,7 +60,8 @@ int circuit_can_use_tap(const origin_circuit_t *circ);
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
-const node_t *build_state_get_exit_node(cpath_build_state_t *state);
+MOCK_DECL(const node_t *,
+ build_state_get_exit_node,(cpath_build_state_t *state));
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
struct circuit_guard_state_t;
@@ -76,6 +71,20 @@ const node_t *choose_good_entry_server(uint8_t purpose,
struct circuit_guard_state_t **guard_state_out);
void circuit_upgrade_circuits_from_guard_wait(void);
+struct ed25519_public_key_t;
+
+MOCK_DECL(channel_t *,
+channel_connect_for_circuit,(const tor_addr_t *addr,
+ uint16_t port,
+ const char *id_digest,
+ const struct ed25519_public_key_t *ed_id));
+
+struct create_cell_t;
+MOCK_DECL(int,
+circuit_deliver_create_cell,(circuit_t *circ,
+ const struct create_cell_t *create_cell,
+ int relayed));
+
#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 4102cf3d4c..90cce47490 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -99,7 +99,6 @@
#include "lib/compress/compress_zstd.h"
#include "lib/buf/buffers.h"
-#define OCIRC_EVENT_PRIVATE
#include "core/or/ocirc_event.h"
#include "ht.h"
@@ -147,6 +146,9 @@ static int any_opened_circs_cached_val = 0;
/********* END VARIABLES ************/
+/* Implement circuit handle helpers. */
+HANDLE_IMPL(circuit, circuit_t,)
+
or_circuit_t *
TO_OR_CIRCUIT(circuit_t *x)
{
@@ -213,10 +215,10 @@ chan_circid_entry_hash_(chan_circid_circuit_map_t *a)
static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t)
chan_circid_map = HT_INITIALIZER();
HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node,
- chan_circid_entry_hash_, chan_circid_entries_eq_)
+ chan_circid_entry_hash_, chan_circid_entries_eq_);
HT_GENERATE2(chan_circid_map, chan_circid_circuit_map_t, node,
chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
/** The most recently returned entry from circuit_get_by_circid_chan;
* used to improve performance when many cells arrive in a row from the
@@ -1134,7 +1136,7 @@ circuit_free_(circuit_t *circ)
* circuit is closed. This is to avoid any code path that free registered
* circuits without closing them before. This needs to be done before the
* hs identifier is freed. */
- hs_circ_cleanup(circ);
+ hs_circ_cleanup_on_free(circ);
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -1247,6 +1249,9 @@ circuit_free_(circuit_t *circ)
/* Free any circuit padding structures */
circpad_circuit_free_all_machineinfos(circ);
+ /* Clear all dangling handle references. */
+ circuit_handles_clear(circ);
+
if (should_free) {
memwipe(mem, 0xAA, memlen); /* poison memory */
tor_free(mem);
@@ -2255,7 +2260,7 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
}
/* Notify the HS subsystem that this circuit is closing. */
- hs_circ_cleanup(circ);
+ hs_circ_cleanup_on_close(circ);
if (circuits_pending_close == NULL)
circuits_pending_close = smartlist_new();
@@ -2337,43 +2342,6 @@ circuit_about_to_free(circuit_t *circ)
orig_reason);
}
- if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
- origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
- int timed_out = (reason == END_CIRC_REASON_TIMEOUT);
- tor_assert(circ->state == CIRCUIT_STATE_OPEN);
- tor_assert(ocirc->build_state->chosen_exit);
- if (orig_reason != END_CIRC_REASON_IP_NOW_REDUNDANT &&
- ocirc->rend_data) {
- /* 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)),
- timed_out ? "Recording timeout." : "Removing from descriptor.");
- rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
- ocirc->rend_data,
- timed_out ?
- INTRO_POINT_FAILURE_TIMEOUT :
- INTRO_POINT_FAILURE_GENERIC);
- }
- } else if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING &&
- reason != END_CIRC_REASON_TIMEOUT) {
- origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
- if (ocirc->build_state->chosen_exit && ocirc->rend_data) {
- if (orig_reason != END_CIRC_REASON_IP_NOW_REDUNDANT &&
- ocirc->rend_data) {
- 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);
- }
- }
- }
-
if (circ->n_chan) {
circuit_clear_cell_queue(circ, circ->n_chan);
/* Only send destroy if the channel isn't closing anyway */
diff --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h
index 80c1f7ac4e..fd7e22e4c0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,7 @@
#ifndef TOR_CIRCUITLIST_H
#define TOR_CIRCUITLIST_H
+#include "lib/container/handles.h"
#include "lib/testsupport/testsupport.h"
#include "feature/hs/hs_ident.h"
#include "core/or/ocirc_event.h"
@@ -242,6 +243,11 @@ MOCK_DECL(void, channel_note_destroy_not_pending,
smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void);
+/* Declare the handle helpers */
+HANDLE_DECL(circuit, circuit_t, )
+#define circuit_handle_free(h) \
+ FREE_AND_NULL(circuit_handle_t, circuit_handle_free_, (h))
+
#ifdef CIRCUITLIST_PRIVATE
STATIC void circuit_free_(circuit_t *circ);
#define circuit_free(circ) FREE_AND_NULL(circuit_t, circuit_free_, (circ))
diff --git a/src/core/or/circuitmux.c b/src/core/or/circuitmux.c
index 4b19a12e3c..b770e40bf2 100644
--- a/src/core/or/circuitmux.c
+++ b/src/core/or/circuitmux.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -69,14 +69,14 @@
* made to attach all existing circuits to the new policy.
**/
+#define CIRCUITMUX_PRIVATE
+
#include "core/or/or.h"
#include "core/or/channel.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitmux.h"
#include "core/or/relay.h"
-#include "core/or/cell_queue_st.h"
-#include "core/or/destroy_cell_queue_st.h"
#include "core/or/or_circuit_st.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -86,12 +86,6 @@
*/
/*
- * Map of muxinfos for circuitmux_t to use; struct is defined below (name
- * of struct must match HT_HEAD line).
- */
-typedef struct chanid_circid_muxinfo_map chanid_circid_muxinfo_map_t;
-
-/*
* Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to
* break the hash table code).
*/
@@ -102,57 +96,14 @@ typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t;
* a count of queued cells.
*/
-typedef struct circuit_muxinfo_s circuit_muxinfo_t;
-
-/*
- * Structures for circuitmux.c
- */
-
-struct circuitmux_s {
- /* Keep count of attached, active circuits */
- unsigned int n_circuits, n_active_circuits;
-
- /* Total number of queued cells on all circuits */
- unsigned int n_cells;
-
- /*
- * Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t
- */
- chanid_circid_muxinfo_map_t *chanid_circid_map;
-
- /** List of queued destroy cells */
- destroy_cell_queue_t destroy_cell_queue;
- /** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
- * returned the destroy queue. Used to force alternation between
- * destroy/non-destroy cells.
- *
- * XXXX There is no reason to think that alternating is a particularly good
- * approach -- it's just designed to prevent destroys from starving other
- * cells completely.
- */
- unsigned int last_cell_was_destroy : 1;
- /** Destroy counter: increment this when a destroy gets queued, decrement
- * when we unqueue it, so we can test to make sure they don't starve.
- */
- int64_t destroy_ctr;
-
- /*
- * Circuitmux policy; if this is non-NULL, it can override the built-
- * in round-robin active circuits behavior. This is how EWMA works in
- * the new circuitmux_t world.
- */
- const circuitmux_policy_t *policy;
-
- /* Policy-specific data */
- circuitmux_policy_data_t *policy_data;
-};
+typedef struct circuit_muxinfo_t circuit_muxinfo_t;
/*
* This struct holds whatever we want to store per attached circuit on a
* circuitmux_t; right now, just the count of queued cells and the direction.
*/
-struct circuit_muxinfo_s {
+struct circuit_muxinfo_t {
/* Count of cells on this circuit at last update */
unsigned int cell_count;
/* Direction of flow */
@@ -223,15 +174,12 @@ chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
((unsigned int)(a->chan_id & 0xffffffff)));
}
-/* Declare the struct chanid_circid_muxinfo_map type */
-HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t);
-
/* Emit a bunch of hash table stuff */
HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
- chanid_circid_entry_hash, chanid_circid_entries_eq)
+ chanid_circid_entry_hash, chanid_circid_entries_eq);
HT_GENERATE2(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
/*
* Circuitmux alloc/free functions
diff --git a/src/core/or/circuitmux.h b/src/core/or/circuitmux.h
index 67cd9bcdd8..191ca12e30 100644
--- a/src/core/or/circuitmux.h
+++ b/src/core/or/circuitmux.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,11 +12,11 @@
#include "core/or/or.h"
#include "lib/testsupport/testsupport.h"
-typedef struct circuitmux_policy_s circuitmux_policy_t;
-typedef struct circuitmux_policy_data_s circuitmux_policy_data_t;
-typedef struct circuitmux_policy_circ_data_s circuitmux_policy_circ_data_t;
+typedef struct circuitmux_policy_t circuitmux_policy_t;
+typedef struct circuitmux_policy_data_t circuitmux_policy_data_t;
+typedef struct circuitmux_policy_circ_data_t circuitmux_policy_circ_data_t;
-struct circuitmux_policy_s {
+struct circuitmux_policy_t {
/* Allocate cmux-wide policy-specific data */
circuitmux_policy_data_t * (*alloc_cmux_data)(circuitmux_t *cmux);
/* Free cmux-wide policy-specific data */
@@ -67,7 +67,7 @@ struct circuitmux_policy_s {
* wide data; it just has the magic number in the base struct.
*/
-struct circuitmux_policy_data_s {
+struct circuitmux_policy_data_t {
uint32_t magic;
};
@@ -76,7 +76,7 @@ struct circuitmux_policy_data_s {
* specific data; it just has the magic number in the base struct.
*/
-struct circuitmux_policy_circ_data_s {
+struct circuitmux_policy_circ_data_t {
uint32_t magic;
};
@@ -158,5 +158,61 @@ void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux,
MOCK_DECL(int, circuitmux_compare_muxes,
(circuitmux_t *cmux_1, circuitmux_t *cmux_2));
+#ifdef CIRCUITMUX_PRIVATE
+
+#include "core/or/destroy_cell_queue_st.h"
+
+/*
+ * Map of muxinfos for circuitmux_t to use; struct is defined below (name
+ * of struct must match HT_HEAD line).
+ */
+typedef HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t)
+ chanid_circid_muxinfo_map_t;
+
+/*
+ * Structures for circuitmux.c
+ */
+
+struct circuitmux_t {
+ /* Keep count of attached, active circuits */
+ unsigned int n_circuits, n_active_circuits;
+
+ /* Total number of queued cells on all circuits */
+ unsigned int n_cells;
+
+ /*
+ * Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t
+ */
+ chanid_circid_muxinfo_map_t *chanid_circid_map;
+
+ /** List of queued destroy cells */
+ destroy_cell_queue_t destroy_cell_queue;
+ /** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
+ * returned the destroy queue. Used to force alternation between
+ * destroy/non-destroy cells.
+ *
+ * XXXX There is no reason to think that alternating is a particularly good
+ * approach -- it's just designed to prevent destroys from starving other
+ * cells completely.
+ */
+ unsigned int last_cell_was_destroy : 1;
+ /** Destroy counter: increment this when a destroy gets queued, decrement
+ * when we unqueue it, so we can test to make sure they don't starve.
+ */
+ int64_t destroy_ctr;
+
+ /*
+ * Circuitmux policy; if this is non-NULL, it can override the built-
+ * in round-robin active circuits behavior. This is how EWMA works in
+ * the new circuitmux_t world.
+ */
+ const circuitmux_policy_t *policy;
+
+ /* Policy-specific data */
+ circuitmux_policy_data_t *policy_data;
+};
+
+#endif /* defined(CIRCUITMUX_PRIVATE) */
+
#endif /* !defined(TOR_CIRCUITMUX_H) */
diff --git a/src/core/or/circuitmux_ewma.c b/src/core/or/circuitmux_ewma.c
index 07f83af0f1..0dcd22e8a7 100644
--- a/src/core/or/circuitmux_ewma.c
+++ b/src/core/or/circuitmux_ewma.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -59,119 +59,6 @@
/** The natural logarithm of 0.5. */
#define LOG_ONEHALF -0.69314718055994529
-/*** EWMA structures ***/
-
-typedef struct cell_ewma_s cell_ewma_t;
-typedef struct ewma_policy_data_s ewma_policy_data_t;
-typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t;
-
-/**
- * The cell_ewma_t structure keeps track of how many cells a circuit has
- * transferred recently. It keeps an EWMA (exponentially weighted moving
- * average) of the number of cells flushed from the circuit queue onto a
- * connection in channel_flush_from_first_active_circuit().
- */
-
-struct cell_ewma_s {
- /** The last 'tick' at which we recalibrated cell_count.
- *
- * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
- * since the start of this tick have weight greater than 1.0; ones sent
- * earlier have less weight. */
- unsigned int last_adjusted_tick;
- /** The EWMA of the cell count. */
- double cell_count;
- /** True iff this is the cell count for a circuit's previous
- * channel. */
- unsigned int is_for_p_chan : 1;
- /** The position of the circuit within the OR connection's priority
- * queue. */
- int heap_index;
-};
-
-struct ewma_policy_data_s {
- circuitmux_policy_data_t base_;
-
- /**
- * Priority queue of cell_ewma_t for circuits with queued cells waiting
- * for room to free up on the channel that owns this circuitmux. Kept
- * in heap order according to EWMA. This was formerly in channel_t, and
- * in or_connection_t before that.
- */
- smartlist_t *active_circuit_pqueue;
-
- /**
- * The tick on which the cell_ewma_ts in active_circuit_pqueue last had
- * their ewma values rescaled. This was formerly in channel_t, and in
- * or_connection_t before that.
- */
- unsigned int active_circuit_pqueue_last_recalibrated;
-};
-
-struct ewma_policy_circ_data_s {
- circuitmux_policy_circ_data_t base_;
-
- /**
- * The EWMA count for the number of cells flushed from this circuit
- * onto this circuitmux. Used to determine which circuit to flush
- * from next. This was formerly in circuit_t and or_circuit_t.
- */
- cell_ewma_t cell_ewma;
-
- /**
- * Pointer back to the circuit_t this is for; since we're separating
- * out circuit selection policy like this, we can't attach cell_ewma_t
- * to the circuit_t any more, so we can't use SUBTYPE_P directly to a
- * circuit_t like before; instead get it here.
- */
- circuit_t *circ;
-};
-
-#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
-#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U
-
-/*** Downcasts for the above types ***/
-
-static ewma_policy_data_t *
-TO_EWMA_POL_DATA(circuitmux_policy_data_t *);
-
-static ewma_policy_circ_data_t *
-TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *);
-
-/**
- * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
- * if the cast is impossible.
- */
-
-static inline ewma_policy_data_t *
-TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol)
-{
- if (!pol) return NULL;
- else {
- tor_assertf(pol->magic == EWMA_POL_DATA_MAGIC,
- "Mismatch: %"PRIu32" != %"PRIu32,
- pol->magic, EWMA_POL_DATA_MAGIC);
- return DOWNCAST(ewma_policy_data_t, pol);
- }
-}
-
-/**
- * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
- * and assert if the cast is impossible.
- */
-
-static inline ewma_policy_circ_data_t *
-TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol)
-{
- if (!pol) return NULL;
- else {
- tor_assertf(pol->magic == EWMA_POL_CIRC_DATA_MAGIC,
- "Mismatch: %"PRIu32" != %"PRIu32,
- pol->magic, EWMA_POL_CIRC_DATA_MAGIC);
- return DOWNCAST(ewma_policy_circ_data_t, pol);
- }
-}
-
/*** Static declarations for circuitmux_ewma.c ***/
static void add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma);
@@ -536,7 +423,7 @@ ewma_cmp_cmux(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
/* Pick whichever one has the better best circuit */
return compare_cell_ewma_counts(ce1, ce2);
} else {
- if (ce1 != NULL ) {
+ if (ce1 != NULL) {
/* We only have a circuit on cmux_1, so prefer it */
return -1;
} else if (ce2 != NULL) {
@@ -722,7 +609,7 @@ cmux_ewma_set_options(const or_options_t *options,
/* convert halflife into halflife-per-tick. */
halflife /= EWMA_TICK_LEN;
/* compute per-tick scale factor. */
- ewma_scale_factor = exp( LOG_ONEHALF / halflife );
+ 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",
diff --git a/src/core/or/circuitmux_ewma.h b/src/core/or/circuitmux_ewma.h
index b45ce1f916..e41cf9e0f0 100644
--- a/src/core/or/circuitmux_ewma.h
+++ b/src/core/or/circuitmux_ewma.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,9 +22,117 @@ void cmux_ewma_set_options(const or_options_t *options,
void circuitmux_ewma_free_all(void);
#ifdef CIRCUITMUX_EWMA_PRIVATE
+
+/*** EWMA structures ***/
+
+typedef struct cell_ewma_t cell_ewma_t;
+typedef struct ewma_policy_data_t ewma_policy_data_t;
+typedef struct ewma_policy_circ_data_t ewma_policy_circ_data_t;
+
+/**
+ * The cell_ewma_t structure keeps track of how many cells a circuit has
+ * transferred recently. It keeps an EWMA (exponentially weighted moving
+ * average) of the number of cells flushed from the circuit queue onto a
+ * connection in channel_flush_from_first_active_circuit().
+ */
+
+struct cell_ewma_t {
+ /** The last 'tick' at which we recalibrated cell_count.
+ *
+ * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
+ * since the start of this tick have weight greater than 1.0; ones sent
+ * earlier have less weight. */
+ unsigned int last_adjusted_tick;
+ /** The EWMA of the cell count. */
+ double cell_count;
+ /** True iff this is the cell count for a circuit's previous
+ * channel. */
+ unsigned int is_for_p_chan : 1;
+ /** The position of the circuit within the OR connection's priority
+ * queue. */
+ int heap_index;
+};
+
+struct ewma_policy_data_t {
+ circuitmux_policy_data_t base_;
+
+ /**
+ * Priority queue of cell_ewma_t for circuits with queued cells waiting
+ * for room to free up on the channel that owns this circuitmux. Kept
+ * in heap order according to EWMA. This was formerly in channel_t, and
+ * in or_connection_t before that.
+ */
+ smartlist_t *active_circuit_pqueue;
+
+ /**
+ * The tick on which the cell_ewma_ts in active_circuit_pqueue last had
+ * their ewma values rescaled. This was formerly in channel_t, and in
+ * or_connection_t before that.
+ */
+ unsigned int active_circuit_pqueue_last_recalibrated;
+};
+
+struct ewma_policy_circ_data_t {
+ circuitmux_policy_circ_data_t base_;
+
+ /**
+ * The EWMA count for the number of cells flushed from this circuit
+ * onto this circuitmux. Used to determine which circuit to flush
+ * from next. This was formerly in circuit_t and or_circuit_t.
+ */
+ cell_ewma_t cell_ewma;
+
+ /**
+ * Pointer back to the circuit_t this is for; since we're separating
+ * out circuit selection policy like this, we can't attach cell_ewma_t
+ * to the circuit_t any more, so we can't use SUBTYPE_P directly to a
+ * circuit_t like before; instead get it here.
+ */
+ circuit_t *circ;
+};
+
+#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
+#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U
+
+/*** Downcasts for the above types ***/
+
+/**
+ * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
+ * if the cast is impossible.
+ */
+
+static inline ewma_policy_data_t *
+TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol)
+{
+ if (!pol) return NULL;
+ else {
+ tor_assertf(pol->magic == EWMA_POL_DATA_MAGIC,
+ "Mismatch: %"PRIu32" != %"PRIu32,
+ pol->magic, EWMA_POL_DATA_MAGIC);
+ return DOWNCAST(ewma_policy_data_t, pol);
+ }
+}
+
+/**
+ * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
+ * and assert if the cast is impossible.
+ */
+
+static inline ewma_policy_circ_data_t *
+TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol)
+{
+ if (!pol) return NULL;
+ else {
+ tor_assertf(pol->magic == EWMA_POL_CIRC_DATA_MAGIC,
+ "Mismatch: %"PRIu32" != %"PRIu32,
+ pol->magic, EWMA_POL_CIRC_DATA_MAGIC);
+ return DOWNCAST(ewma_policy_circ_data_t, pol);
+ }
+}
+
STATIC unsigned cell_ewma_get_current_tick_and_fraction(double *remainder_out);
STATIC void cell_ewma_initialize_ticks(void);
-#endif
-#endif /* !defined(TOR_CIRCUITMUX_EWMA_H) */
+#endif /* defined(CIRCUITMUX_EWMA_PRIVATE) */
+#endif /* !defined(TOR_CIRCUITMUX_EWMA_H) */
diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c
index 7f761fed6b..43f4a31624 100644
--- a/src/core/or/circuitpadding.c
+++ b/src/core/or/circuitpadding.c
@@ -116,6 +116,7 @@ STATIC smartlist_t *origin_padding_machines = NULL;
* runtime and as long as circuits are alive. */
STATIC smartlist_t *relay_padding_machines = NULL;
+#ifndef COCCI
/** Loop over the current padding state machines using <b>loop_var</b> as the
* loop variable. */
#define FOR_EACH_CIRCUIT_MACHINE_BEGIN(loop_var) \
@@ -130,6 +131,7 @@ STATIC smartlist_t *relay_padding_machines = NULL;
if (!(circ)->padding_info[loop_var]) \
continue;
#define FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END } STMT_END ;
+#endif /* !defined(COCCI) */
/**
* Free the machineinfo at an index
@@ -686,7 +688,7 @@ circpad_distribution_sample(circpad_distribution_t dist)
case CIRCPAD_DIST_UNIFORM:
{
// param2 is upper bound, param1 is lower
- const struct uniform my_uniform = {
+ const struct uniform_t my_uniform = {
.base = UNIFORM(my_uniform),
.a = dist.param1,
.b = dist.param2,
@@ -696,7 +698,7 @@ circpad_distribution_sample(circpad_distribution_t dist)
case CIRCPAD_DIST_LOGISTIC:
{
/* param1 is Mu, param2 is sigma. */
- const struct logistic my_logistic = {
+ const struct logistic_t my_logistic = {
.base = LOGISTIC(my_logistic),
.mu = dist.param1,
.sigma = dist.param2,
@@ -706,7 +708,7 @@ circpad_distribution_sample(circpad_distribution_t dist)
case CIRCPAD_DIST_LOG_LOGISTIC:
{
/* param1 is Alpha, param2 is 1.0/Beta */
- const struct log_logistic my_log_logistic = {
+ const struct log_logistic_t my_log_logistic = {
.base = LOG_LOGISTIC(my_log_logistic),
.alpha = dist.param1,
.beta = dist.param2,
@@ -716,7 +718,7 @@ circpad_distribution_sample(circpad_distribution_t dist)
case CIRCPAD_DIST_GEOMETRIC:
{
/* param1 is 'p' (success probability) */
- const struct geometric my_geometric = {
+ const struct geometric_t my_geometric = {
.base = GEOMETRIC(my_geometric),
.p = dist.param1,
};
@@ -725,7 +727,7 @@ circpad_distribution_sample(circpad_distribution_t dist)
case CIRCPAD_DIST_WEIBULL:
{
/* param1 is k, param2 is Lambda */
- const struct weibull my_weibull = {
+ const struct weibull_t my_weibull = {
.base = WEIBULL(my_weibull),
.k = dist.param1,
.lambda = dist.param2,
@@ -735,7 +737,7 @@ circpad_distribution_sample(circpad_distribution_t dist)
case CIRCPAD_DIST_PARETO:
{
/* param1 is sigma, param2 is xi, no more params for mu so we use 0 */
- const struct genpareto my_genpareto = {
+ const struct genpareto_t my_genpareto = {
.base = GENPARETO(my_genpareto),
.mu = 0,
.sigma = dist.param1,
@@ -2179,8 +2181,8 @@ circpad_add_matching_machines(origin_circuit_t *on_circ,
circ->padding_machine[i] = NULL;
on_circ->padding_negotiation_failed = 1;
} else {
- /* Success. Don't try any more machines */
- return;
+ /* Success. Don't try any more machines on this index */
+ break;
}
}
} SMARTLIST_FOREACH_END(machine);
diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h
index e9eb32c618..74b69a1c7a 100644
--- a/src/core/or/circuitpadding.h
+++ b/src/core/or/circuitpadding.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, The Tor Project, Inc. */
+ * Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -301,7 +301,7 @@ typedef struct circpad_state_t {
* | | | | | | |
* | | | | | | |
* 0 +----+----+-----+-----+---------+---------------+
- * 0 100 200 350 500 1000 ∞ microseconds
+ * 0 100 200 350 500 1000 inf microseconds
*
* would be specified the following way:
* histogram_len = 6;
@@ -388,7 +388,7 @@ typedef struct circpad_state_t {
*
* States are allowed to transition to themselves, which means re-schedule
* a new padding timer. They are also allowed to temporarily "transition"
- * to the "IGNORE" and "CANCEL" pseudo-states. See #defines below
+ * to the "IGNORE" and "CANCEL" pseudo-states. See defines below
* for details on state behavior and meaning.
*/
circpad_statenum_t next_state[CIRCPAD_NUM_EVENTS];
diff --git a/src/core/or/circuitpadding_machines.c b/src/core/or/circuitpadding_machines.c
index 7220d657fc..98767f9e8f 100644
--- a/src/core/or/circuitpadding_machines.c
+++ b/src/core/or/circuitpadding_machines.c
@@ -5,8 +5,6 @@
* \file circuitpadding_machines.c
* \brief Circuit padding state machines
*
- * \detail
- *
* Introduce circuit padding machines that will be used by Tor circuits, as
* specified by proposal 302 "Hiding onion service clients using padding".
*
diff --git a/src/core/or/circuitstats.c b/src/core/or/circuitstats.c
index 7a7f3ca600..5875627b93 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,7 +29,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitstats.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "feature/control/control_events.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "core/mainloop/mainloop.h"
@@ -972,7 +972,7 @@ circuit_build_times_update_state(const circuit_build_times_t *cbt,
/**
* Shuffle the build times array.
*
- * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ * Adapted from https://en.wikipedia.org/wiki/Fisher-Yates_shuffle
*/
static void
circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
@@ -1183,7 +1183,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
/**
* Estimates the Xm and Alpha parameters using
- * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation
+ * https://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation
*
* The notable difference is that we use mode instead of min to estimate Xm.
* This is because our distribution is frechet-like. We claim this is
@@ -1198,7 +1198,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
int n=0,i=0,abandoned_count=0;
build_time_t max_time=0;
- /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
+ /* https://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
/* We sort of cheat here and make our samples slightly more pareto-like
* and less frechet-like. */
cbt->Xm = circuit_build_times_get_xm(cbt);
@@ -1270,9 +1270,9 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
* We use it to calculate the timeout and also to generate synthetic
* values of time for circuits that timeout before completion.
*
- * See http://en.wikipedia.org/wiki/Quantile_function,
- * http://en.wikipedia.org/wiki/Inverse_transform_sampling and
- * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_
+ * See https://en.wikipedia.org/wiki/Quantile_function,
+ * https://en.wikipedia.org/wiki/Inverse_transform_sampling and
+ * https://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_
* random_sample_from_Pareto_distribution
* That's right. I'll cite wikipedia all day long.
*
diff --git a/src/core/or/circuitstats.h b/src/core/or/circuitstats.h
index 845d7b6722..52c9100f53 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -175,7 +175,7 @@ typedef struct {
} network_liveness_t;
/** Structure for circuit build times history */
-struct circuit_build_times_s {
+struct circuit_build_times_t {
/** The circular array of recorded build times in milliseconds */
build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE];
/** Current index in the circuit_build_times circular array */
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index 284e315f9c..e2c4df25d0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -42,6 +42,7 @@
#include "feature/client/bridges.h"
#include "feature/client/circpathbias.h"
#include "feature/client/entrynodes.h"
+#include "feature/client/proxymode.h"
#include "feature/control/control_events.h"
#include "feature/dircommon/directory.h"
#include "feature/hs/hs_circuit.h"
@@ -547,9 +548,10 @@ circuit_expire_building(void)
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) {
struct timeval cutoff;
- bool fixed_time = circuit_build_times_disabled(get_options());
if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */
victim->marked_for_close) /* don't mess with marked circs */
@@ -731,7 +733,7 @@ circuit_expire_building(void)
circuit_build_times_enough_to_compute(get_circuit_build_times())) {
log_info(LD_CIRC,
- "Deciding to count the timeout for circuit %"PRIu32"\n",
+ "Deciding to count the timeout for circuit %"PRIu32,
TO_ORIGIN_CIRCUIT(victim)->global_identifier);
/* Circuits are allowed to last longer for measurement.
@@ -774,16 +776,11 @@ circuit_expire_building(void)
if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) {
switch (victim->purpose) {
case CIRCUIT_PURPOSE_C_REND_READY:
- /* We only want to spare a rend circ if it has been specified in
- * an INTRODUCE1 cell sent to a hidden service. A circ's
- * pending_final_cpath field is non-NULL iff it is a rend circ
- * and we have tried to send an INTRODUCE1 cell specifying it.
- * Thus, if the pending_final_cpath field *is* NULL, then we
- * want to not spare it. */
- if (TO_ORIGIN_CIRCUIT(victim)->build_state &&
- TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath ==
- NULL)
+ /* We only want to spare a rend circ iff it has been specified in an
+ * INTRODUCE1 cell sent to a hidden service. */
+ if (!hs_circ_is_rend_sent_in_intro1(CONST_TO_ORIGIN_CIRCUIT(victim))) {
break;
+ }
FALLTHROUGH;
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
@@ -1964,23 +1961,61 @@ have_enough_path_info(int need_exit)
int
circuit_purpose_is_hidden_service(uint8_t purpose)
{
- if (purpose == CIRCUIT_PURPOSE_HS_VANGUARDS) {
- return 1;
- }
-
- /* Client-side purpose */
- if (purpose >= CIRCUIT_PURPOSE_C_HS_MIN_ &&
- purpose <= CIRCUIT_PURPOSE_C_HS_MAX_) {
- return 1;
- }
-
- /* Service-side purpose */
- if (purpose >= CIRCUIT_PURPOSE_S_HS_MIN_ &&
- purpose <= CIRCUIT_PURPOSE_S_HS_MAX_) {
- return 1;
- }
-
- return 0;
+ /* HS Vanguard purpose. */
+ if (circuit_purpose_is_hs_vanguards(purpose)) {
+ return 1;
+ }
+
+ /* Client-side purpose */
+ if (circuit_purpose_is_hs_client(purpose)) {
+ return 1;
+ }
+
+ /* Service-side purpose */
+ if (circuit_purpose_is_hs_service(purpose)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Retrun true iff the given circuit is an HS client circuit. */
+bool
+circuit_purpose_is_hs_client(const uint8_t purpose)
+{
+ return (purpose >= CIRCUIT_PURPOSE_C_HS_MIN_ &&
+ purpose <= CIRCUIT_PURPOSE_C_HS_MAX_);
+}
+
+/** Retrun true iff the given circuit is an HS service circuit. */
+bool
+circuit_purpose_is_hs_service(const uint8_t purpose)
+{
+ return (purpose >= CIRCUIT_PURPOSE_S_HS_MIN_ &&
+ purpose <= CIRCUIT_PURPOSE_S_HS_MAX_);
+}
+
+/** Retrun true iff the given circuit is an HS Vanguards circuit. */
+bool
+circuit_purpose_is_hs_vanguards(const uint8_t purpose)
+{
+ return (purpose == CIRCUIT_PURPOSE_HS_VANGUARDS);
+}
+
+/** Retrun 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));
+}
+
+/** Retrun true iff the given circuit is an HS v3 circuit. */
+bool
+circuit_is_hs_v3(const circuit_t *circ)
+{
+ return (CIRCUIT_IS_ORIGIN(circ) &&
+ (CONST_TO_ORIGIN_CIRCUIT(circ)->hs_ident != NULL));
}
/**
@@ -3085,7 +3120,7 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
/* Take specific actions if we are repurposing a hidden service circuit. */
if (circuit_purpose_is_hidden_service(circ->purpose) &&
!circuit_purpose_is_hidden_service(new_purpose)) {
- hs_circ_cleanup(circ);
+ hs_circ_cleanup_on_repurpose(circ);
}
}
diff --git a/src/core/or/circuituse.h b/src/core/or/circuituse.h
index 25588dbb11..95d36d6474 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -64,6 +64,15 @@ int hostname_in_track_host_exits(const or_options_t *options,
void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ);
int circuit_purpose_is_hidden_service(uint8_t);
+
+/* Series of helper functions for hidden services. */
+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);
void circuit_sent_valid_data(origin_circuit_t *circ, uint16_t relay_body_len);
void circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len);
diff --git a/src/core/or/command.c b/src/core/or/command.c
index 1c97437769..8a1d2066cc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -54,6 +54,7 @@
#include "feature/nodelist/describe.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
+#include "feature/relay/circuitbuild_relay.h"
#include "feature/relay/routermode.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -217,23 +218,6 @@ command_process_cell(channel_t *chan, cell_t *cell)
}
}
-/** Process an incoming var_cell from a channel; in the current protocol all
- * the var_cells are handshake-related and handled below the channel layer,
- * so this just logs a warning and drops the cell.
- */
-
-void
-command_process_var_cell(channel_t *chan, var_cell_t *var_cell)
-{
- tor_assert(chan);
- tor_assert(var_cell);
-
- log_info(LD_PROTOCOL,
- "Received unexpected var_cell above the channel layer of type %d"
- "; dropping it.",
- var_cell->command);
-}
-
/** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a
* new circuit with the p_circ_id specified in cell. Put the circuit in state
* onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
@@ -685,8 +669,7 @@ command_setup_channel(channel_t *chan)
tor_assert(chan);
channel_set_cell_handlers(chan,
- command_process_cell,
- command_process_var_cell);
+ command_process_cell);
}
/** Given a listener, install the right handler to process incoming
diff --git a/src/core/or/command.h b/src/core/or/command.h
index 8c90e1de6f..14ebb4a339 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,7 +15,6 @@
#include "core/or/channel.h"
void command_process_cell(channel_t *chan, cell_t *cell);
-void command_process_var_cell(channel_t *chan, var_cell_t *cell);
void command_setup_channel(channel_t *chan);
void command_setup_listener(channel_listener_t *chan_l);
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index 4f5f038e6c..26595003c1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -432,6 +432,21 @@ warn_if_hs_unreachable(const edge_connection_t *conn, uint8_t reason)
}
}
+/** Given a TTL (in seconds) from a DNS response or from a relay, determine
+ * what TTL clients and relays should actually use for caching it. */
+uint32_t
+clip_dns_ttl(uint32_t ttl)
+{
+ /* This logic is a defense against "DefectTor" DNS-based traffic
+ * confirmation attacks, as in https://nymity.ch/tor-dns/tor-dns.pdf .
+ * We only give two values: a "low" value and a "high" value.
+ */
+ if (ttl < MIN_DNS_TTL)
+ return MIN_DNS_TTL;
+ else
+ return MAX_DNS_TTL;
+}
+
/** Send a relay end cell from stream <b>conn</b> down conn's circuit, and
* remember that we've done so. If this is not a client connection, set the
* relay end cell's reason for closing as <b>reason</b>.
@@ -480,7 +495,7 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason)
memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16);
addrlen = 16;
}
- set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl)));
+ set_uint32(payload+1+addrlen, htonl(clip_dns_ttl(conn->address_ttl)));
payload_len += 4+addrlen;
}
@@ -845,7 +860,7 @@ connected_cell_format_payload(uint8_t *payload_out,
return -1;
}
- set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl)));
+ set_uint32(payload_out + connected_payload_len, htonl(clip_dns_ttl(ttl)));
connected_payload_len += 4;
tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN);
@@ -1553,6 +1568,107 @@ consider_plaintext_ports(entry_connection_t *conn, uint16_t port)
return 0;
}
+/** Parse the given hostname in address. Returns true if the parsing was
+ * successful and type_out contains the type of the hostname. Else, false is
+ * returned which means it was not recognized and type_out is set to
+ * BAD_HOSTNAME.
+ *
+ * The possible recognized forms are (where true is returned):
+ *
+ * If address is of the form "y.onion" with a well-formed handle y:
+ * Put a NUL after y, lower-case it, and return ONION_V2_HOSTNAME or
+ * ONION_V3_HOSTNAME depending on the HS version.
+ *
+ * If address is of the form "x.y.onion" with a well-formed handle x:
+ * Drop "x.", put a NUL after y, lower-case it, and return
+ * ONION_V2_HOSTNAME or ONION_V3_HOSTNAME depending on the HS version.
+ *
+ * If address is of the form "y.onion" with a badly-formed handle y:
+ * Return BAD_HOSTNAME and log a message.
+ *
+ * If address is of the form "y.exit":
+ * Put a NUL after y and return EXIT_HOSTNAME.
+ *
+ * Otherwise:
+ * Return NORMAL_HOSTNAME and change nothing.
+ */
+STATIC bool
+parse_extended_hostname(char *address, hostname_type_t *type_out)
+{
+ char *s;
+ char *q;
+ char query[HS_SERVICE_ADDR_LEN_BASE32+1];
+
+ s = strrchr(address,'.');
+ if (!s) {
+ *type_out = NORMAL_HOSTNAME; /* no dot, thus normal */
+ goto success;
+ }
+ if (!strcmp(s+1,"exit")) {
+ *s = 0; /* NUL-terminate it */
+ *type_out = EXIT_HOSTNAME; /* .exit */
+ goto success;
+ }
+ if (strcmp(s+1,"onion")) {
+ *type_out = NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */
+ goto success;
+ }
+
+ /* so it is .onion */
+ *s = 0; /* NUL-terminate it */
+ /* locate a 'sub-domain' component, in order to remove it */
+ q = strrchr(address, '.');
+ if (q == address) {
+ *type_out = BAD_HOSTNAME;
+ goto failed; /* reject sub-domain, as DNS does */
+ }
+ q = (NULL == q) ? address : q + 1;
+ if (strlcpy(query, q, HS_SERVICE_ADDR_LEN_BASE32+1) >=
+ HS_SERVICE_ADDR_LEN_BASE32+1) {
+ *type_out = BAD_HOSTNAME;
+ goto failed;
+ }
+ if (q != address) {
+ memmove(address, q, strlen(q) + 1 /* also get \0 */);
+ }
+ /* v2 onion address check. */
+ if (strlen(query) == REND_SERVICE_ID_LEN_BASE32) {
+ *type_out = ONION_V2_HOSTNAME;
+ if (rend_valid_v2_service_id(query)) {
+ goto success;
+ }
+ goto failed;
+ }
+
+ /* v3 onion address check. */
+ if (strlen(query) == HS_SERVICE_ADDR_LEN_BASE32) {
+ *type_out = ONION_V3_HOSTNAME;
+ if (hs_address_is_valid(query)) {
+ goto success;
+ }
+ goto failed;
+ }
+
+ /* Reaching this point, nothing was recognized. */
+ *type_out = BAD_HOSTNAME;
+ goto failed;
+
+ success:
+ return true;
+ failed:
+ /* otherwise, return to previous state and return 0 */
+ *s = '.';
+ const bool is_onion = (*type_out == ONION_V2_HOSTNAME) ||
+ (*type_out == ONION_V3_HOSTNAME);
+ log_warn(LD_APP, "Invalid %shostname %s; rejecting",
+ is_onion ? "onion " : "",
+ safe_str_client(address));
+ if (*type_out == ONION_V3_HOSTNAME) {
+ *type_out = BAD_HOSTNAME;
+ }
+ return false;
+}
+
/** How many times do we try connecting with an exit configured via
* TrackHostExits before concluding that it won't work any more and trying a
* different one? */
@@ -2020,16 +2136,15 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
const int automap = rr.automap;
const addressmap_entry_source_t exit_source = rr.exit_source;
- /* Now, we parse the address to see if it's an .onion or .exit or
- * other special address.
- */
- const hostname_type_t addresstype = parse_extended_hostname(socks->address);
-
/* Now see whether the hostname is bogus. This could happen because of an
* onion hostname whose format we don't recognize. */
- if (addresstype == BAD_HOSTNAME) {
+ hostname_type_t addresstype;
+ if (!parse_extended_hostname(socks->address, &addresstype)) {
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
+ if (addresstype == BAD_HOSTNAME) {
+ conn->socks_request->socks_extended_error_code = SOCKS5_HS_BAD_ADDRESS;
+ }
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
@@ -3347,8 +3462,9 @@ tell_controller_about_resolved_result(entry_connection_t *conn,
expires = time(NULL) + ttl;
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) {
char *cp = tor_dup_ip(ntohl(get_uint32(answer)));
- control_event_address_mapped(conn->socks_request->address,
- cp, expires, NULL, 0);
+ if (cp)
+ control_event_address_mapped(conn->socks_request->address,
+ cp, expires, NULL, 0);
tor_free(cp);
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
char *cp = tor_strndup(answer, answer_len);
@@ -3421,7 +3537,7 @@ connection_ap_handshake_socks_resolved,(entry_connection_t *conn,
}
} else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
tor_addr_t a;
- tor_addr_from_ipv6_bytes(&a, (char*)answer);
+ tor_addr_from_ipv6_bytes(&a, answer);
if (! tor_addr_is_null(&a)) {
client_dns_set_addressmap(conn,
conn->socks_request->address, &a,
@@ -3522,11 +3638,17 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
size_t replylen, int endreason)
{
char buf[256];
- socks5_reply_status_t status =
- stream_end_reason_to_socks5_response(endreason);
+ socks5_reply_status_t status;
tor_assert(conn->socks_request); /* make sure it's an AP stream */
+ if (conn->socks_request->socks_use_extended_errors &&
+ conn->socks_request->socks_extended_error_code != 0) {
+ status = conn->socks_request->socks_extended_error_code;
+ } else {
+ status = stream_end_reason_to_socks5_response(endreason);
+ }
+
if (!SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) {
control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ?
STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED,
@@ -4306,68 +4428,6 @@ connection_ap_can_use_exit(const entry_connection_t *conn,
return 1;
}
-/** If address is of the form "y.onion" with a well-formed handle y:
- * Put a NUL after y, lower-case it, and return ONION_V2_HOSTNAME or
- * ONION_V3_HOSTNAME depending on the HS version.
- *
- * If address is of the form "x.y.onion" with a well-formed handle x:
- * Drop "x.", put a NUL after y, lower-case it, and return
- * ONION_V2_HOSTNAME or ONION_V3_HOSTNAME depending on the HS version.
- *
- * If address is of the form "y.onion" with a badly-formed handle y:
- * Return BAD_HOSTNAME and log a message.
- *
- * If address is of the form "y.exit":
- * Put a NUL after y and return EXIT_HOSTNAME.
- *
- * Otherwise:
- * Return NORMAL_HOSTNAME and change nothing.
- */
-hostname_type_t
-parse_extended_hostname(char *address)
-{
- char *s;
- char *q;
- char query[HS_SERVICE_ADDR_LEN_BASE32+1];
-
- s = strrchr(address,'.');
- if (!s)
- return NORMAL_HOSTNAME; /* no dot, thus normal */
- if (!strcmp(s+1,"exit")) {
- *s = 0; /* NUL-terminate it */
- return EXIT_HOSTNAME; /* .exit */
- }
- if (strcmp(s+1,"onion"))
- return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */
-
- /* so it is .onion */
- *s = 0; /* NUL-terminate it */
- /* locate a 'sub-domain' component, in order to remove it */
- q = strrchr(address, '.');
- if (q == address) {
- goto failed; /* reject sub-domain, as DNS does */
- }
- q = (NULL == q) ? address : q + 1;
- if (strlcpy(query, q, HS_SERVICE_ADDR_LEN_BASE32+1) >=
- HS_SERVICE_ADDR_LEN_BASE32+1)
- goto failed;
- if (q != address) {
- memmove(address, q, strlen(q) + 1 /* also get \0 */);
- }
- if (rend_valid_v2_service_id(query)) {
- return ONION_V2_HOSTNAME; /* success */
- }
- if (hs_address_is_valid(query)) {
- return ONION_V3_HOSTNAME;
- }
- failed:
- /* otherwise, return to previous state and return 0 */
- *s = '.';
- log_warn(LD_APP, "Invalid onion hostname %s; rejecting",
- safe_str_client(address));
- return BAD_HOSTNAME;
-}
-
/** Return true iff the (possibly NULL) <b>alen</b>-byte chunk of memory at
* <b>a</b> is equal to the (possibly NULL) <b>blen</b>-byte chunk of memory
* at <b>b</b>. */
diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h
index e82b6bd765..8c06af5664 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -71,6 +71,15 @@ entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *);
#define connection_mark_unattached_ap(conn, endreason) \
connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__)
+/** Possible return values for parse_extended_hostname. */
+typedef enum hostname_type_t {
+ BAD_HOSTNAME,
+ EXIT_HOSTNAME,
+ NORMAL_HOSTNAME,
+ ONION_V2_HOSTNAME,
+ ONION_V3_HOSTNAME,
+} hostname_type_t;
+
MOCK_DECL(void,connection_mark_unattached_ap_,
(entry_connection_t *conn, int endreason,
int line, const char *file));
@@ -155,13 +164,6 @@ int connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
origin_circuit_t *circ,
crypt_path_t *cpath);
-/** Possible return values for parse_extended_hostname. */
-typedef enum hostname_type_t {
- NORMAL_HOSTNAME, ONION_V2_HOSTNAME, ONION_V3_HOSTNAME,
- EXIT_HOSTNAME, BAD_HOSTNAME
-} hostname_type_t;
-hostname_type_t parse_extended_hostname(char *address);
-
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
int get_pf_socket(void);
#endif
@@ -180,6 +182,21 @@ void connection_ap_warn_and_unmark_if_pending_circ(
entry_connection_t *entry_conn,
const char *where);
+/** Lowest value for DNS ttl that a server should give or a client should
+ * believe. */
+#define MIN_DNS_TTL (5*60)
+/** Highest value for DNS ttl that a server should give or a client should
+ * believe. */
+#define MAX_DNS_TTL (60*60)
+/** How long do we keep DNS cache entries before purging them (regardless of
+ * their TTL)? */
+#define MAX_DNS_ENTRY_AGE (3*60*60)
+/** How long do we cache/tell clients to cache DNS records when no TTL is
+ * known? */
+#define DEFAULT_DNS_TTL (30*60)
+
+uint32_t clip_dns_ttl(uint32_t ttl);
+
int connection_half_edge_is_valid_data(const smartlist_t *half_conns,
streamid_t stream_id);
int connection_half_edge_is_valid_sendme(const smartlist_t *half_conns,
@@ -219,6 +236,8 @@ void half_edge_free_(struct half_edge_t *he);
#ifdef CONNECTION_EDGE_PRIVATE
+STATIC bool parse_extended_hostname(char *address, hostname_type_t *type_out);
+
/** A parsed BEGIN or BEGIN_DIR cell */
typedef struct begin_cell_t {
/** The address the client has asked us to connect to, or NULL if this is
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index 4c93351e31..b88d1b6afb 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,7 +18,8 @@
* tortls.c) which it uses as its TLS stream. It is responsible for
* sending and receiving cells over that TLS.
*
- * This module also implements the client side of the v3 Tor link handshake,
+ * This module also implements the client side of the v3 (and greater) Tor
+ * link handshake.
**/
#include "core/or/or.h"
#include "feature/client/bridges.h"
@@ -27,7 +28,7 @@
* Define this so we get channel internal functions, since we're implementing
* part of a subclass (channel_tls_t).
*/
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CONNECTION_OR_PRIVATE
#define ORCONN_EVENT_PRIVATE
#include "core/or/channel.h"
@@ -39,14 +40,13 @@
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
+#include "feature/relay/relay_handshake.h"
#include "feature/control/control_events.h"
-#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/dirauth/reachability.h"
#include "feature/client/entrynodes.h"
#include "lib/geoip/geoip.h"
#include "core/mainloop/mainloop.h"
-#include "trunnel/link_handshake.h"
#include "trunnel/netinfo.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
@@ -78,7 +78,6 @@
#include "lib/crypt_ops/crypto_format.h"
#include "lib/tls/tortls.h"
-#include "lib/tls/x509.h"
#include "core/or/orconn_event.h"
@@ -95,13 +94,6 @@ static unsigned int
connection_or_is_bad_for_new_circs(or_connection_t *or_conn);
static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn);
-/*
- * Call this when changing connection state, so notifications to the owning
- * channel can be handled.
- */
-
-static void connection_or_change_state(or_connection_t *conn, uint8_t state);
-
static void connection_or_check_canonicity(or_connection_t *conn,
int started_here);
@@ -116,10 +108,6 @@ TO_OR_CONN(connection_t *c)
return DOWNCAST(or_connection_t, c);
}
-/** Global map between Extended ORPort identifiers and OR
- * connections. */
-static digestmap_t *orconn_ext_or_id_map = NULL;
-
/** Clear clear conn->identity_digest and update other data
* structures as appropriate.*/
void
@@ -205,71 +193,6 @@ connection_or_set_identity_digest(or_connection_t *conn,
channel_set_identity_digest(chan, rsa_digest, ed_id);
}
-/** 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);
-}
-
-/** 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);
-}
-
-/** 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);
-}
-
/**************************************************************/
/** Map from a string describing what a non-open OR connection was doing when
@@ -457,8 +380,8 @@ connection_or_state_publish(const or_connection_t *conn, uint8_t state)
* be notified.
*/
-static void
-connection_or_change_state(or_connection_t *conn, uint8_t state)
+MOCK_IMPL(STATIC void,
+connection_or_change_state,(or_connection_t *conn, uint8_t state))
{
tor_assert(conn);
@@ -726,6 +649,19 @@ connection_or_finished_flushing(or_connection_t *conn)
switch (conn->base_.state) {
case OR_CONN_STATE_PROXY_HANDSHAKING:
+ /* 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);
+ TO_CONN(conn)->proxy_state = PROXY_CONNECTED;
+
+ if (connection_tls_start_handshake(conn, 0) < 0) {
+ /* TLS handshaking error of some kind. */
+ connection_or_close_for_error(conn, 0);
+ return -1;
+ }
+ break;
+ }
+ break;
case OR_CONN_STATE_OPEN:
case OR_CONN_STATE_OR_HANDSHAKING_V2:
case OR_CONN_STATE_OR_HANDSHAKING_V3:
@@ -765,8 +701,9 @@ connection_or_finished_connecting(or_connection_t *or_conn)
return -1;
}
- connection_start_reading(conn);
connection_or_change_state(or_conn, OR_CONN_STATE_PROXY_HANDSHAKING);
+ connection_start_reading(conn);
+
return 0;
}
@@ -808,10 +745,16 @@ connection_or_about_to_close(or_connection_t *or_conn)
int reason = tls_error_to_orconn_end_reason(or_conn->tls_error);
connection_or_event_status(or_conn, OR_CONN_EVENT_FAILED,
reason);
- if (!authdir_mode_tests_reachability(options))
- control_event_bootstrap_prob_or(
- orconn_end_reason_to_control_string(reason),
- reason, or_conn);
+ if (!authdir_mode_tests_reachability(options)) {
+ const char *warning = NULL;
+ if (reason == END_OR_CONN_REASON_TLS_ERROR && or_conn->tls) {
+ warning = tor_tls_get_last_error_msg(or_conn->tls);
+ }
+ if (warning == NULL) {
+ warning = orconn_end_reason_to_control_string(reason);
+ }
+ control_event_bootstrap_prob_or(warning, reason, or_conn);
+ }
}
}
} else if (conn->hold_open_until_flushed) {
@@ -966,12 +909,21 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here)
}
if (r) {
- tor_addr_port_t node_ap;
- node_get_pref_orport(r, &node_ap);
- /* XXXX proposal 186 is making this more complex. For now, a conn
- is canonical when it uses the _preferred_ address. */
- if (tor_addr_eq(&conn->base_.addr, &node_ap.addr))
+ tor_addr_port_t node_ipv4_ap;
+ tor_addr_port_t node_ipv6_ap;
+ node_get_prim_orport(r, &node_ipv4_ap);
+ node_get_pref_ipv6_orport(r, &node_ipv6_ap);
+ if (tor_addr_eq(&conn->base_.addr, &node_ipv4_ap.addr) ||
+ tor_addr_eq(&conn->base_.addr, &node_ipv6_ap.addr)) {
connection_or_set_canonical(conn, 1);
+ }
+ /* Choose the correct canonical address and port. */
+ tor_addr_port_t *node_ap;
+ if (tor_addr_family(&conn->base_.addr) == AF_INET) {
+ node_ap = &node_ipv4_ap;
+ } else {
+ node_ap = &node_ipv6_ap;
+ }
if (!started_here) {
/* Override the addr/port, so our log messages will make sense.
* This is dangerous, since if we ever try looking up a conn by
@@ -983,13 +935,14 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here)
* right IP address and port 56244, that wouldn't be as helpful. now we
* log the "right" port too, so we know if it's moria1 or moria2.
*/
- tor_addr_copy(&conn->base_.addr, &node_ap.addr);
- conn->base_.port = node_ap.port;
+ /* See #33898 for a ticket that resolves this technical debt. */
+ tor_addr_copy(&conn->base_.addr, &node_ap->addr);
+ conn->base_.port = node_ap->port;
}
tor_free(conn->nickname);
conn->nickname = tor_strdup(node_get_nickname(r));
tor_free(conn->base_.address);
- conn->base_.address = tor_addr_to_str_dup(&node_ap.addr);
+ conn->base_.address = tor_addr_to_str_dup(&node_ap->addr);
} else {
tor_free(conn->nickname);
conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
@@ -1277,11 +1230,11 @@ or_connect_failure_ht_hash(const or_connect_failure_entry_t *entry)
}
HT_PROTOTYPE(or_connect_failure_ht, or_connect_failure_entry_t, node,
- or_connect_failure_ht_hash, or_connect_failure_ht_eq)
+ or_connect_failure_ht_hash, or_connect_failure_ht_eq);
HT_GENERATE2(or_connect_failure_ht, or_connect_failure_entry_t, node,
or_connect_failure_ht_hash, or_connect_failure_ht_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
/* Initialize a given connect failure entry with the given identity_digest,
* addr and port. All field are optional except ocf. */
@@ -1745,7 +1698,8 @@ connection_tls_continue_handshake(or_connection_t *conn)
switch (result) {
CASE_TOR_TLS_ERROR_ANY:
- log_info(LD_OR,"tls error [%s]. breaking connection.",
+ conn->tls_error = result;
+ log_info(LD_OR,"tls error [%s]. breaking connection.",
tor_tls_err_to_string(result));
return -1;
case TOR_TLS_DONE:
@@ -1777,6 +1731,7 @@ connection_tls_continue_handshake(or_connection_t *conn)
log_debug(LD_OR,"wanted read");
return 0;
case TOR_TLS_CLOSE:
+ conn->tls_error = result;
log_info(LD_OR,"tls closed. breaking connection.");
return -1;
}
@@ -2590,533 +2545,3 @@ connection_or_send_netinfo,(or_connection_t *conn))
return r;
}
-
-/** Helper used to add an encoded certs to a cert cell */
-static void
-add_certs_cell_cert_helper(certs_cell_t *certs_cell,
- uint8_t cert_type,
- const uint8_t *cert_encoded,
- size_t cert_len)
-{
- tor_assert(cert_len <= UINT16_MAX);
- certs_cell_cert_t *ccc = certs_cell_cert_new();
- ccc->cert_type = cert_type;
- ccc->cert_len = cert_len;
- certs_cell_cert_setlen_body(ccc, cert_len);
- memcpy(certs_cell_cert_getarray_body(ccc), cert_encoded, cert_len);
-
- certs_cell_add_certs(certs_cell, ccc);
-}
-
-/** Add an encoded X509 cert (stored as <b>cert_len</b> bytes at
- * <b>cert_encoded</b>) to the trunnel certs_cell_t object that we are
- * building in <b>certs_cell</b>. Set its type field to <b>cert_type</b>.
- * (If <b>cert</b> is NULL, take no action.) */
-static void
-add_x509_cert(certs_cell_t *certs_cell,
- uint8_t cert_type,
- const tor_x509_cert_t *cert)
-{
- if (NULL == cert)
- return;
-
- const uint8_t *cert_encoded = NULL;
- size_t cert_len;
- tor_x509_cert_get_der(cert, &cert_encoded, &cert_len);
-
- add_certs_cell_cert_helper(certs_cell, cert_type, cert_encoded, cert_len);
-}
-
-/** Add an Ed25519 cert from <b>cert</b> to the trunnel certs_cell_t object
- * that we are building in <b>certs_cell</b>. Set its type field to
- * <b>cert_type</b>. (If <b>cert</b> is NULL, take no action.) */
-static void
-add_ed25519_cert(certs_cell_t *certs_cell,
- uint8_t cert_type,
- const tor_cert_t *cert)
-{
- if (NULL == cert)
- return;
-
- add_certs_cell_cert_helper(certs_cell, cert_type,
- cert->encoded, cert->encoded_len);
-}
-
-#ifdef TOR_UNIT_TESTS
-int certs_cell_ed25519_disabled_for_testing = 0;
-#else
-#define certs_cell_ed25519_disabled_for_testing 0
-#endif
-
-/** Send a CERTS cell on the connection <b>conn</b>. Return 0 on success, -1
- * on failure. */
-int
-connection_or_send_certs_cell(or_connection_t *conn)
-{
- const tor_x509_cert_t *global_link_cert = NULL, *id_cert = NULL;
- tor_x509_cert_t *own_link_cert = NULL;
- var_cell_t *cell;
-
- certs_cell_t *certs_cell = NULL;
-
- tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
-
- if (! conn->handshake_state)
- return -1;
-
- const int conn_in_server_mode = ! conn->handshake_state->started_here;
-
- /* Get the encoded values of the X509 certificates */
- if (tor_tls_get_my_certs(conn_in_server_mode,
- &global_link_cert, &id_cert) < 0)
- return -1;
-
- if (conn_in_server_mode) {
- own_link_cert = tor_tls_get_own_cert(conn->tls);
- }
- tor_assert(id_cert);
-
- certs_cell = certs_cell_new();
-
- /* Start adding certs. First the link cert or auth1024 cert. */
- if (conn_in_server_mode) {
- tor_assert_nonfatal(own_link_cert);
- add_x509_cert(certs_cell,
- OR_CERT_TYPE_TLS_LINK, own_link_cert);
- } else {
- tor_assert(global_link_cert);
- add_x509_cert(certs_cell,
- OR_CERT_TYPE_AUTH_1024, global_link_cert);
- }
-
- /* Next the RSA->RSA ID cert */
- add_x509_cert(certs_cell,
- OR_CERT_TYPE_ID_1024, id_cert);
-
- /* Next the Ed25519 certs */
- add_ed25519_cert(certs_cell,
- CERTTYPE_ED_ID_SIGN,
- get_master_signing_key_cert());
- if (conn_in_server_mode) {
- tor_assert_nonfatal(conn->handshake_state->own_link_cert ||
- certs_cell_ed25519_disabled_for_testing);
- add_ed25519_cert(certs_cell,
- CERTTYPE_ED_SIGN_LINK,
- conn->handshake_state->own_link_cert);
- } else {
- add_ed25519_cert(certs_cell,
- CERTTYPE_ED_SIGN_AUTH,
- get_current_auth_key_cert());
- }
-
- /* And finally the crosscert. */
- {
- const uint8_t *crosscert=NULL;
- size_t crosscert_len;
- get_master_rsa_crosscert(&crosscert, &crosscert_len);
- if (crosscert) {
- add_certs_cell_cert_helper(certs_cell,
- CERTTYPE_RSA1024_ID_EDID,
- crosscert, crosscert_len);
- }
- }
-
- /* We've added all the certs; make the cell. */
- certs_cell->n_certs = certs_cell_getlen_certs(certs_cell);
-
- ssize_t alloc_len = certs_cell_encoded_len(certs_cell);
- tor_assert(alloc_len >= 0 && alloc_len <= UINT16_MAX);
- cell = var_cell_new(alloc_len);
- cell->command = CELL_CERTS;
- ssize_t enc_len = certs_cell_encode(cell->payload, alloc_len, certs_cell);
- tor_assert(enc_len > 0 && enc_len <= alloc_len);
- cell->payload_len = enc_len;
-
- connection_or_write_var_cell_to_buf(cell, conn);
- var_cell_free(cell);
- certs_cell_free(certs_cell);
- tor_x509_cert_free(own_link_cert);
-
- return 0;
-}
-
-#ifdef TOR_UNIT_TESTS
-int testing__connection_or_pretend_TLSSECRET_is_supported = 0;
-#else
-#define testing__connection_or_pretend_TLSSECRET_is_supported 0
-#endif
-
-/** Return true iff <b>challenge_type</b> is an AUTHCHALLENGE type that
- * we can send and receive. */
-int
-authchallenge_type_is_supported(uint16_t challenge_type)
-{
- switch (challenge_type) {
- case AUTHTYPE_RSA_SHA256_TLSSECRET:
-#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
- return 1;
-#else
- return testing__connection_or_pretend_TLSSECRET_is_supported;
-#endif
- case AUTHTYPE_ED25519_SHA256_RFC5705:
- return 1;
- case AUTHTYPE_RSA_SHA256_RFC5705:
- default:
- return 0;
- }
-}
-
-/** Return true iff <b>challenge_type_a</b> is one that we would rather
- * use than <b>challenge_type_b</b>. */
-int
-authchallenge_type_is_better(uint16_t challenge_type_a,
- uint16_t challenge_type_b)
-{
- /* Any supported type is better than an unsupported one;
- * all unsupported types are equally bad. */
- if (!authchallenge_type_is_supported(challenge_type_a))
- return 0;
- if (!authchallenge_type_is_supported(challenge_type_b))
- return 1;
- /* It happens that types are superior in numerically ascending order.
- * If that ever changes, this must change too. */
- return (challenge_type_a > challenge_type_b);
-}
-
-/** Send an AUTH_CHALLENGE cell on the connection <b>conn</b>. Return 0
- * on success, -1 on failure. */
-int
-connection_or_send_auth_challenge_cell(or_connection_t *conn)
-{
- var_cell_t *cell = NULL;
- int r = -1;
- tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
-
- if (! conn->handshake_state)
- return -1;
-
- auth_challenge_cell_t *ac = auth_challenge_cell_new();
-
- tor_assert(sizeof(ac->challenge) == 32);
- crypto_rand((char*)ac->challenge, sizeof(ac->challenge));
-
- if (authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET))
- auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
- /* Disabled, because everything that supports this method also supports
- * the much-superior ED25519_SHA256_RFC5705 */
- /* auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_RFC5705); */
- if (authchallenge_type_is_supported(AUTHTYPE_ED25519_SHA256_RFC5705))
- auth_challenge_cell_add_methods(ac, AUTHTYPE_ED25519_SHA256_RFC5705);
- auth_challenge_cell_set_n_methods(ac,
- auth_challenge_cell_getlen_methods(ac));
-
- cell = var_cell_new(auth_challenge_cell_encoded_len(ac));
- ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len,
- ac);
- if (len != cell->payload_len) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Encoded auth challenge cell length not as expected");
- goto done;
- /* LCOV_EXCL_STOP */
- }
- cell->command = CELL_AUTH_CHALLENGE;
-
- connection_or_write_var_cell_to_buf(cell, conn);
- r = 0;
-
- done:
- var_cell_free(cell);
- auth_challenge_cell_free(ac);
-
- return r;
-}
-
-/** Compute the main body of an AUTHENTICATE cell that a client can use
- * to authenticate itself on a v3 handshake for <b>conn</b>. Return it
- * in a var_cell_t.
- *
- * If <b>server</b> is true, only calculate the first
- * V3_AUTH_FIXED_PART_LEN bytes -- the part of the authenticator that's
- * determined by the rest of the handshake, and which match the provided value
- * exactly.
- *
- * If <b>server</b> is false and <b>signing_key</b> is NULL, calculate the
- * first V3_AUTH_BODY_LEN bytes of the authenticator (that is, everything
- * that should be signed), but don't actually sign it.
- *
- * If <b>server</b> is false and <b>signing_key</b> is provided, calculate the
- * entire authenticator, signed with <b>signing_key</b>.
- *
- * Return the length of the cell body on success, and -1 on failure.
- */
-var_cell_t *
-connection_or_compute_authenticate_cell_body(or_connection_t *conn,
- const int authtype,
- crypto_pk_t *signing_key,
- const ed25519_keypair_t *ed_signing_key,
- int server)
-{
- auth1_t *auth = NULL;
- auth_ctx_t *ctx = auth_ctx_new();
- var_cell_t *result = NULL;
- int old_tlssecrets_algorithm = 0;
- const char *authtype_str = NULL;
-
- int is_ed = 0;
-
- /* assert state is reasonable XXXX */
- switch (authtype) {
- case AUTHTYPE_RSA_SHA256_TLSSECRET:
- authtype_str = "AUTH0001";
- old_tlssecrets_algorithm = 1;
- break;
- case AUTHTYPE_RSA_SHA256_RFC5705:
- authtype_str = "AUTH0002";
- break;
- case AUTHTYPE_ED25519_SHA256_RFC5705:
- authtype_str = "AUTH0003";
- is_ed = 1;
- break;
- default:
- tor_assert(0);
- break;
- }
-
- auth = auth1_new();
- ctx->is_ed = is_ed;
-
- /* Type: 8 bytes. */
- memcpy(auth1_getarray_type(auth), authtype_str, 8);
-
- {
- const tor_x509_cert_t *id_cert=NULL;
- const common_digests_t *my_digests, *their_digests;
- const uint8_t *my_id, *their_id, *client_id, *server_id;
- if (tor_tls_get_my_certs(server, NULL, &id_cert))
- goto err;
- my_digests = tor_x509_cert_get_id_digests(id_cert);
- their_digests =
- tor_x509_cert_get_id_digests(conn->handshake_state->certs->id_cert);
- tor_assert(my_digests);
- tor_assert(their_digests);
- my_id = (uint8_t*)my_digests->d[DIGEST_SHA256];
- their_id = (uint8_t*)their_digests->d[DIGEST_SHA256];
-
- client_id = server ? their_id : my_id;
- server_id = server ? my_id : their_id;
-
- /* Client ID digest: 32 octets. */
- memcpy(auth->cid, client_id, 32);
-
- /* Server ID digest: 32 octets. */
- memcpy(auth->sid, server_id, 32);
- }
-
- if (is_ed) {
- const ed25519_public_key_t *my_ed_id, *their_ed_id;
- if (!conn->handshake_state->certs->ed_id_sign) {
- log_warn(LD_OR, "Ed authenticate without Ed ID cert from peer.");
- goto err;
- }
- my_ed_id = get_master_identity_key();
- their_ed_id = &conn->handshake_state->certs->ed_id_sign->signing_key;
-
- const uint8_t *cid_ed = (server ? their_ed_id : my_ed_id)->pubkey;
- const uint8_t *sid_ed = (server ? my_ed_id : their_ed_id)->pubkey;
-
- memcpy(auth->u1_cid_ed, cid_ed, ED25519_PUBKEY_LEN);
- memcpy(auth->u1_sid_ed, sid_ed, ED25519_PUBKEY_LEN);
- }
-
- {
- crypto_digest_t *server_d, *client_d;
- if (server) {
- server_d = conn->handshake_state->digest_sent;
- client_d = conn->handshake_state->digest_received;
- } else {
- client_d = conn->handshake_state->digest_sent;
- server_d = conn->handshake_state->digest_received;
- }
-
- /* Server log digest : 32 octets */
- crypto_digest_get_digest(server_d, (char*)auth->slog, 32);
-
- /* Client log digest : 32 octets */
- crypto_digest_get_digest(client_d, (char*)auth->clog, 32);
- }
-
- {
- /* Digest of cert used on TLS link : 32 octets. */
- tor_x509_cert_t *cert = NULL;
- if (server) {
- cert = tor_tls_get_own_cert(conn->tls);
- } else {
- cert = tor_tls_get_peer_cert(conn->tls);
- }
- if (!cert) {
- log_warn(LD_OR, "Unable to find cert when making %s data.",
- authtype_str);
- goto err;
- }
-
- memcpy(auth->scert,
- tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
-
- tor_x509_cert_free(cert);
- }
-
- /* HMAC of clientrandom and serverrandom using master key : 32 octets */
- if (old_tlssecrets_algorithm) {
- if (tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets) < 0) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR, "Somebody asked us for an older TLS "
- "authentication method (AUTHTYPE_RSA_SHA256_TLSSECRET) "
- "which we don't support.");
- }
- } else {
- char label[128];
- tor_snprintf(label, sizeof(label),
- "EXPORTER FOR TOR TLS CLIENT BINDING %s", authtype_str);
- int r = tor_tls_export_key_material(conn->tls, auth->tlssecrets,
- auth->cid, sizeof(auth->cid),
- label);
- if (r < 0) {
- if (r != -2)
- log_warn(LD_BUG, "TLS key export failed for unknown reason.");
- // If r == -2, this was openssl bug 7712.
- goto err;
- }
- }
-
- /* 8 octets were reserved for the current time, but we're trying to get out
- * of the habit of sending time around willynilly. Fortunately, nothing
- * checks it. That's followed by 16 bytes of nonce. */
- crypto_rand((char*)auth->rand, 24);
-
- ssize_t maxlen = auth1_encoded_len(auth, ctx);
- if (ed_signing_key && is_ed) {
- maxlen += ED25519_SIG_LEN;
- } else if (signing_key && !is_ed) {
- maxlen += crypto_pk_keysize(signing_key);
- }
-
- const int AUTH_CELL_HEADER_LEN = 4; /* 2 bytes of type, 2 bytes of length */
- result = var_cell_new(AUTH_CELL_HEADER_LEN + maxlen);
- uint8_t *const out = result->payload + AUTH_CELL_HEADER_LEN;
- const size_t outlen = maxlen;
- ssize_t len;
-
- result->command = CELL_AUTHENTICATE;
- set_uint16(result->payload, htons(authtype));
-
- if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Unable to encode signed part of AUTH1 data.");
- goto err;
- /* LCOV_EXCL_STOP */
- }
-
- if (server) {
- auth1_t *tmp = NULL;
- ssize_t len2 = auth1_parse(&tmp, out, len, ctx);
- if (!tmp) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Unable to parse signed part of AUTH1 data that "
- "we just encoded");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- result->payload_len = (tmp->end_of_signed - result->payload);
-
- auth1_free(tmp);
- if (len2 != len) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Mismatched length when re-parsing AUTH1 data.");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- goto done;
- }
-
- if (ed_signing_key && is_ed) {
- ed25519_signature_t sig;
- if (ed25519_sign(&sig, out, len, ed_signing_key) < 0) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Unable to sign ed25519 authentication data");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- auth1_setlen_sig(auth, ED25519_SIG_LEN);
- memcpy(auth1_getarray_sig(auth), sig.sig, ED25519_SIG_LEN);
-
- } else if (signing_key && !is_ed) {
- auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
-
- char d[32];
- crypto_digest256(d, (char*)out, len, DIGEST_SHA256);
- int siglen = crypto_pk_private_sign(signing_key,
- (char*)auth1_getarray_sig(auth),
- auth1_getlen_sig(auth),
- d, 32);
- if (siglen < 0) {
- log_warn(LD_OR, "Unable to sign AUTH1 data.");
- goto err;
- }
-
- auth1_setlen_sig(auth, siglen);
- }
-
- len = auth1_encode(out, outlen, auth, ctx);
- if (len < 0) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Unable to encode signed AUTH1 data.");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- tor_assert(len + AUTH_CELL_HEADER_LEN <= result->payload_len);
- result->payload_len = len + AUTH_CELL_HEADER_LEN;
- set_uint16(result->payload+2, htons(len));
-
- goto done;
-
- err:
- var_cell_free(result);
- result = NULL;
- done:
- auth1_free(auth);
- auth_ctx_free(ctx);
- return result;
-}
-
-/** Send an AUTHENTICATE cell on the connection <b>conn</b>. Return 0 on
- * success, -1 on failure */
-MOCK_IMPL(int,
-connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype))
-{
- var_cell_t *cell;
- crypto_pk_t *pk = tor_tls_get_my_client_auth_key();
- /* XXXX make sure we're actually supposed to send this! */
-
- if (!pk) {
- log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key");
- return -1;
- }
- if (! authchallenge_type_is_supported(authtype)) {
- log_warn(LD_BUG, "Tried to send authenticate cell with unknown "
- "authentication type %d", authtype);
- return -1;
- }
-
- cell = connection_or_compute_authenticate_cell_body(conn,
- authtype,
- pk,
- get_current_auth_keypair(),
- 0 /* not server */);
- if (! cell) {
- log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unable to compute authenticate cell!");
- return -1;
- }
- connection_or_write_var_cell_to_buf(cell, conn);
- var_cell_free(cell);
-
- return 0;
-}
diff --git a/src/core/or/connection_or.h b/src/core/or/connection_or.h
index 272f536b83..e9ace56ab4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,10 +22,6 @@ or_connection_t *TO_OR_CONN(connection_t *);
void connection_or_clear_identity(or_connection_t *conn);
void connection_or_clear_identity_map(void);
void clear_broken_connection_map(int disable);
-or_connection_t *connection_or_get_for_extend(const char *digest,
- const tor_addr_t *target_addr,
- const char **msg_out,
- int *launch_out);
void connection_or_block_renegotiation(or_connection_t *conn);
int connection_or_reached_eof(or_connection_t *conn);
@@ -97,19 +93,6 @@ MOCK_DECL(void,connection_or_write_var_cell_to_buf,(const var_cell_t *cell,
or_connection_t *conn));
int connection_or_send_versions(or_connection_t *conn, int v3_plus);
MOCK_DECL(int,connection_or_send_netinfo,(or_connection_t *conn));
-int connection_or_send_certs_cell(or_connection_t *conn);
-int connection_or_send_auth_challenge_cell(or_connection_t *conn);
-int authchallenge_type_is_supported(uint16_t challenge_type);
-int authchallenge_type_is_better(uint16_t challenge_type_a,
- uint16_t challenge_type_b);
-var_cell_t *connection_or_compute_authenticate_cell_body(
- or_connection_t *conn,
- const int authtype,
- crypto_pk_t *signing_key,
- const struct ed25519_keypair_t *ed_signing_key,
- int server);
-MOCK_DECL(int,connection_or_send_authenticate_cell,
- (or_connection_t *conn, int type));
int is_or_protocol_version_known(uint16_t version);
@@ -134,10 +117,16 @@ void connection_or_group_set_badness_(smartlist_t *group, int force);
#ifdef CONNECTION_OR_PRIVATE
STATIC int should_connect_to_relay(const or_connection_t *or_conn);
STATIC void note_or_connect_failed(const or_connection_t *or_conn);
-#endif
+
+/*
+ * Call this when changing connection state, so notifications to the owning
+ * channel can be handled.
+ */
+MOCK_DECL(STATIC void,connection_or_change_state,
+ (or_connection_t *conn, uint8_t state));
+#endif /* defined(CONNECTION_OR_PRIVATE) */
#ifdef TOR_UNIT_TESTS
-extern int certs_cell_ed25519_disabled_for_testing;
extern int testing__connection_or_pretend_TLSSECRET_is_supported;
#endif
diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h
index 1c42a56d6b..685c9f89f4 100644
--- a/src/core/or/connection_st.h
+++ b/src/core/or/connection_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file connection_st.h
+ * @brief Base connection structure.
+ **/
+
#ifndef CONNECTION_ST_H
#define CONNECTION_ST_H
@@ -64,6 +69,9 @@ struct connection_t {
/** True if connection_handle_write is currently running on this connection.
*/
unsigned int in_connection_handle_write:1;
+ /** If true, then we treat this connection as remote for the purpose of
+ * rate-limiting, no matter what its address is. */
+ unsigned int always_rate_limit_as_remote:1;
/* For linked connections:
*/
diff --git a/src/core/or/core_or.md b/src/core/or/core_or.md
new file mode 100644
index 0000000000..0b4d430a00
--- /dev/null
+++ b/src/core/or/core_or.md
@@ -0,0 +1,62 @@
+@dir core/or
+@brief core/or: **Onion routing happens here!**
+
+This is the central part of Tor that handles the core tasks of onion routing:
+building circuit, handling circuits, attaching circuit to streams, moving
+data around, and so forth.
+
+Some aspects of this module should probably be refactored into others.
+
+Notable files here include:
+
+`channel.c`
+: Generic channel implementation. Channels handle sending and receiving cells
+among tor nodes.
+
+`channeltls.c`
+: Channel implementation for TLS-based OR connections. Uses `connection_or.c`.
+
+`circuitbuild.c`
+: Code for constructing circuits and choosing their paths. (*Note*:
+this module could plausibly be split into handling the client side,
+the server side, and the path generation aspects of circuit building.)
+
+`circuitlist.c`
+: Code for maintaining and navigating the global list of circuits.
+
+`circuitmux.c`
+: Generic circuitmux implementation. A circuitmux handles deciding, for a
+particular channel, which circuit should write next.
+
+`circuitmux_ewma.c`
+: A circuitmux implementation based on the EWMA (exponentially
+weighted moving average) algorithm.
+
+`circuituse.c`
+: Code to actually send and receive data on circuits.
+
+`command.c`
+: Handles incoming cells on channels.
+
+`connection.c`
+: Generic and common connection tools, and implementation for the simpler
+connection types.
+
+`connection_edge.c`
+: Implementation for entry and exit connections.
+
+`connection_or.c`
+: Implementation for OR connections (the ones that send cells over TLS).
+
+`onion.c`
+: Generic code for generating and responding to CREATE and CREATED
+cells, and performing the appropriate onion handshakes. Also contains
+code to manage the server-side onion queue.
+
+`relay.c`
+: Handles particular types of relay cells, and provides code to receive,
+encrypt, route, and interpret relay cells.
+
+`scheduler.c`
+: Decides which channel/circuit pair is ready to receive the next cell.
+
diff --git a/src/core/or/cpath_build_state_st.h b/src/core/or/cpath_build_state_st.h
index 4572a10430..ee9a0d972c 100644
--- a/src/core/or/cpath_build_state_st.h
+++ b/src/core/or/cpath_build_state_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file cpath_build_state_st.h
+ * @brief Circuit-build-stse structure
+ **/
+
#ifndef CIRCUIT_BUILD_STATE_ST_ST_H
#define CIRCUIT_BUILD_STATE_ST_ST_H
@@ -35,4 +40,3 @@ struct cpath_build_state_t {
};
#endif /* !defined(CIRCUIT_BUILD_STATE_ST_ST_H) */
-
diff --git a/src/core/or/crypt_path.c b/src/core/or/crypt_path.c
index 9b7efc28bf..8f41540848 100644
--- a/src/core/or/crypt_path.c
+++ b/src/core/or/crypt_path.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, The Tor Project, Inc. */
+ * Copyright (c) 2019-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/crypt_path_reference_st.h b/src/core/or/crypt_path_reference_st.h
index 1827022b4e..71f9cb8c36 100644
--- a/src/core/or/crypt_path_reference_st.h
+++ b/src/core/or/crypt_path_reference_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file crypt_path_reference_st.h
+ * @brief reference-counting structure for crypt_path_t
+ **/
+
#ifndef CRYPT_PATH_REFERENCE_ST_H
#define CRYPT_PATH_REFERENCE_ST_H
@@ -20,4 +25,3 @@ struct crypt_path_reference_t {
};
#endif /* !defined(CRYPT_PATH_REFERENCE_ST_H) */
-
diff --git a/src/core/or/crypt_path_st.h b/src/core/or/crypt_path_st.h
index 249ac6aaa3..2b69728a6d 100644
--- a/src/core/or/crypt_path_st.h
+++ b/src/core/or/crypt_path_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file crypt_path_st.h
+ * @brief Path structures for origin circuits.
+ **/
+
#ifndef CRYPT_PATH_ST_H
#define CRYPT_PATH_ST_H
diff --git a/src/core/or/dataflow.md b/src/core/or/dataflow.md
new file mode 100644
index 0000000000..1098701780
--- /dev/null
+++ b/src/core/or/dataflow.md
@@ -0,0 +1,236 @@
+@tableofcontents
+
+@page dataflow Data flow in the Tor process
+
+We read bytes from the network, we write bytes to the network. For the
+most part, the bytes we write correspond roughly to bytes we have read,
+with bits of cryptography added in.
+
+The rest is a matter of details.
+
+### Connections and buffers: reading, writing, and interpreting.
+
+At a low level, Tor's networking code is based on "connections". Each
+connection represents an object that can send or receive network-like
+events. For the most part, each connection has a single underlying TCP
+stream (I'll discuss counterexamples below).
+
+A connection that behaves like a TCP stream has an input buffer and an
+output buffer. Incoming data is
+written into the input buffer ("inbuf"); data to be written to the
+network is queued on an output buffer ("outbuf").
+
+Buffers are implemented in buffers.c. Each of these buffers is
+implemented as a linked queue of memory extents, in the style of classic
+BSD mbufs, or Linux skbufs.
+
+A connection's reading and writing can be enabled or disabled. Under
+the hood, this functionality is implemented using libevent events: one
+for reading, one for writing. These events are turned on/off in
+main.c, in the functions connection_{start,stop}_{reading,writing}.
+
+When a read or write event is turned on, the main libevent loop polls
+the kernel, asking which sockets are ready to read or write. (This
+polling happens in the event_base_loop() call in run_main_loop_once()
+in main.c.) When libevent finds a socket that's ready to read or write,
+it invokes conn_{read,write}_callback(), also in main.c
+
+These callback functions delegate to connection_handle_read() and
+connection_handle_write() in connection.c, which read or write on the
+network as appropriate, possibly delegating to openssl.
+
+After data is read or written, or other event occurs, these
+connection_handle_read_write() functions call logic functions whose job is
+to respond to the information. Some examples included:
+
+ * connection_flushed_some() -- called after a connection writes any
+ amount of data from its outbuf.
+ * connection_finished_flushing() -- called when a connection has
+ emptied its outbuf.
+ * connection_finished_connecting() -- called when an in-process connection
+ finishes making a remote connection.
+ * connection_reached_eof() -- called after receiving a FIN from the
+ remote server.
+ * connection_process_inbuf() -- called when more data arrives on
+ the inbuf.
+
+These functions then call into specific implementations depending on
+the type of the connection. For example, if the connection is an
+edge_connection_t, connection_reached_eof() will call
+connection_edge_reached_eof().
+
+> **Note:** "Also there are bufferevents!" We have vestigial
+> code for an alternative low-level networking
+> implementation, based on Libevent's evbuffer and bufferevent
+> code. These two object types take on (most of) the roles of
+> buffers and connections respectively. It isn't working in today's
+> Tor, due to code rot and possible lingering libevent bugs. More
+> work is needed; it would be good to get this working efficiently
+> again, to have IOCP support on Windows.
+
+
+#### Controlling connections ####
+
+A connection can have reading or writing enabled or disabled for a
+wide variety of reasons, including:
+
+ * Writing is disabled when there is no more data to write
+ * For some connection types, reading is disabled when the inbuf is
+ too full.
+ * Reading/writing is temporarily disabled on connections that have
+ recently read/written enough data up to their bandwidth
+ * Reading is disabled on connections when reading more data from them
+ would require that data to be buffered somewhere else that is
+ already full.
+
+Currently, these conditions are checked in a diffuse set of
+increasingly complex conditional expressions. In the future, it could
+be helpful to transition to a unified model for handling temporary
+read/write suspensions.
+
+#### Kinds of connections ####
+
+Today Tor has the following connection and pseudoconnection types.
+For the most part, each type of channel has an associated C module
+that implements its underlying logic.
+
+**Edge connections** receive data from and deliver data to points
+outside the onion routing network. See `connection_edge.c`. They fall into two types:
+
+**Entry connections** are a type of edge connection. They receive data
+from the user running a Tor client, and deliver data to that user.
+They are used to implement SOCKSPort, TransPort, NATDPort, and so on.
+Sometimes they are called "AP" connections for historical reasons (it
+used to stand for "Application Proxy").
+
+**Exit connections** are a type of edge connection. They exist at an
+exit node, and transmit traffic to and from the network.
+
+(Entry connections and exit connections are also used as placeholders
+when performing a remote DNS request; they are not decoupled from the
+notion of "stream" in the Tor protocol. This is implemented partially
+in `connection_edge.c`, and partially in `dnsserv.c` and `dns.c`.)
+
+**OR connections** send and receive Tor cells over TLS, using some
+version of the Tor link protocol. Their implementation is spread
+across `connection_or.c`, with a bit of logic in `command.c`,
+`relay.c`, and `channeltls.c`.
+
+**Extended OR connections** are a type of OR connection for use on
+bridges using pluggable transports, so that the PT can tell the bridge
+some information about the incoming connection before passing on its
+data. They are implemented in `ext_orport.c`.
+
+**Directory connections** are server-side or client-side connections
+that implement Tor's HTTP-based directory protocol. These are
+instantiated using a socket when Tor is making an unencrypted HTTP
+connection. When Tor is tunneling a directory request over a Tor
+circuit, directory connections are implemented using a linked
+connection pair (see below). Directory connections are implemented in
+`directory.c`; some of the server-side logic is implemented in
+`dirserver.c`.
+
+**Controller connections** are local connections to a controller
+process implementing the controller protocol from
+control-spec.txt. These are in `control.c`.
+
+**Listener connections** are not stream oriented! Rather, they wrap a
+listening socket in order to detect new incoming connections. They
+bypass most of stream logic. They don't have associated buffers.
+They are implemented in `connection.c`.
+
+![structure hierarchy for connection types](./diagrams/02/02-connection-types.png "structure hierarchy for connection types")
+
+>**Note**: "History Time!" You might occasionally find reference to a couple types of connections
+> which no longer exist in modern Tor. A *CPUWorker connection*
+>connected the main Tor process to a thread or process used for
+>computation. (Nowadays we use in-process communication.) Even more
+>anciently, a *DNSWorker connection* connected the main tor process to
+>a separate thread or process used for running `gethostbyname()` or
+>`getaddrinfo()`. (Nowadays we use Libevent's evdns facility to
+>perform DNS requests asynchronously.)
+
+#### Linked connections ####
+
+Sometimes two channels are joined together, such that data which the
+Tor process sends on one should immediately be received by the same
+Tor process on the other. (For example, when Tor makes a tunneled
+directory connection, this is implemented on the client side as a
+directory connection whose output goes, not to the network, but to a
+local entry connection. And when a directory receives a tunnelled
+directory connection, this is implemented as an exit connection whose
+output goes, not to the network, but to a local directory connection.)
+
+The earliest versions of Tor to support linked connections used
+socketpairs for the purpose. But using socketpairs forced us to copy
+data through kernelspace, and wasted limited file descriptors. So
+instead, a pair of connections can be linked in-process. Each linked
+connection has a pointer to the other, such that data written on one
+is immediately readable on the other, and vice versa.
+
+### From connections to channels ###
+
+There's an abstraction layer above OR connections (the ones that
+handle cells) and below cells called **Channels**. A channel's
+purpose is to transmit authenticated cells from one Tor instance
+(relay or client) to another.
+
+Currently, only one implementation exists: Channel_tls, which sends
+and receiveds cells over a TLS-based OR connection.
+
+Cells are sent on a channel using
+`channel_write_{,packed_,var_}cell()`. Incoming cells arrive on a
+channel from its backend using `channel_queue*_cell()`, and are
+immediately processed using `channel_process_cells()`.
+
+Some cell types are handled below the channel layer, such as those
+that affect handshaking only. And some others are passed up to the
+generic cross-channel code in `command.c`: cells like `DESTROY` and
+`CREATED` are all trivial to handle. But relay cells
+require special handling...
+
+### From channels through circuits ###
+
+When a relay cell arrives on an existing circuit, it is handled in
+`circuit_receive_relay_cell()` -- one of the innermost functions in
+Tor. This function encrypts or decrypts the relay cell as
+appropriate, and decides whether the cell is intended for the current
+hop of the circuit.
+
+If the cell *is* intended for the current hop, we pass it to
+`connection_edge_process_relay_cell()` in `relay.c`, which acts on it
+based on its relay command, and (possibly) queues its data on an
+`edge_connection_t`.
+
+If the cell *is not* intended for the current hop, we queue it for the
+next channel in sequence with `append cell_to_circuit_queue()`. This
+places the cell on a per-circuit queue for cells headed out on that
+particular channel.
+
+### Sending cells on circuits: the complicated bit.
+
+Relay cells are queued onto circuits from one of two (main) sources:
+reading data from edge connections, and receiving a cell to be relayed
+on a circuit. Both of these sources place their cells on cell queue:
+each circuit has one cell queue for each direction that it travels.
+
+A naive implementation would skip using cell queues, and instead write
+each outgoing relay cell. (Tor did this in its earlier versions.)
+But such an approach tends to give poor performance, because it allows
+high-volume circuits to clog channels, and it forces the Tor server to
+send data queued on a circuit even after that circuit has been closed.
+
+So by using queues on each circuit, we can add cells to each channel
+on a just-in-time basis, choosing the cell at each moment based on
+a performance-aware algorithm.
+
+This logic is implemented in two main modules: `scheduler.c` and
+`circuitmux*.c`. The scheduler code is responsible for determining
+globally, across all channels that could write cells, which one should
+next receive queued cells. The circuitmux code determines, for all
+of the circuits with queued cells for a channel, which one should
+queue the next cell.
+
+(This logic applies to outgoing relay cells only; incoming relay cells
+are processed as they arrive.)
+
diff --git a/src/core/or/destroy_cell_queue_st.h b/src/core/or/destroy_cell_queue_st.h
index e917afc700..aa28289be5 100644
--- a/src/core/or/destroy_cell_queue_st.h
+++ b/src/core/or/destroy_cell_queue_st.h
@@ -1,12 +1,19 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file destroy_cell_queue_st.h
+ * @brief Destroy-cell queue structures
+ **/
+
#ifndef DESTROY_CELL_QUEUE_ST_H
#define DESTROY_CELL_QUEUE_ST_H
+#include "core/or/cell_queue_st.h"
+
/** A single queued destroy cell. */
struct destroy_cell_t {
TOR_SIMPLEQ_ENTRY(destroy_cell_t) next;
@@ -19,9 +26,8 @@ struct destroy_cell_t {
/** A queue of destroy cells on a channel. */
struct destroy_cell_queue_t {
/** Linked list of packed_cell_t */
- TOR_SIMPLEQ_HEAD(dcell_simpleq, destroy_cell_t) head;
+ TOR_SIMPLEQ_HEAD(dcell_simpleq_t, destroy_cell_t) head;
int n; /**< The number of cells in the queue. */
};
#endif /* !defined(DESTROY_CELL_QUEUE_ST_H) */
-
diff --git a/src/core/or/dos.c b/src/core/or/dos.c
index d06eaa6d05..5f99280030 100644
--- a/src/core/or/dos.c
+++ b/src/core/or/dos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
@@ -15,6 +15,7 @@
#include "core/or/channel.h"
#include "core/or/connection_or.h"
#include "core/or/relay.h"
+#include "feature/hs/hs_dos.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
#include "feature/relay/routermode.h"
@@ -629,6 +630,7 @@ dos_log_heartbeat(void)
char *cc_msg = NULL;
char *single_hop_client_msg = NULL;
char *circ_stats_msg = NULL;
+ char *hs_dos_intro2_msg = NULL;
/* Stats number coming from relay.c append_cell_to_circuit_queue(). */
tor_asprintf(&circ_stats_msg,
@@ -654,17 +656,24 @@ dos_log_heartbeat(void)
num_single_hop_client_refused);
}
+ /* HS DoS stats. */
+ tor_asprintf(&hs_dos_intro2_msg,
+ " %" PRIu64 " INTRODUCE2 rejected.",
+ hs_dos_get_intro2_rejected_count());
+
log_notice(LD_HEARTBEAT,
- "DoS mitigation since startup:%s%s%s%s",
+ "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 : "");
+ (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;
}
diff --git a/src/core/or/dos.h b/src/core/or/dos.h
index a46f65d767..b3eca058b8 100644
--- a/src/core/or/dos.h
+++ b/src/core/or/dos.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
diff --git a/src/core/or/edge_connection_st.h b/src/core/or/edge_connection_st.h
index 8922a3a9cf..9b2f031b9d 100644
--- a/src/core/or/edge_connection_st.h
+++ b/src/core/or/edge_connection_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file edge_connection_st.h
+ * @brief Edge-connection structure.
+ **/
+
#ifndef EDGE_CONNECTION_ST_H
#define EDGE_CONNECTION_ST_H
@@ -74,4 +79,3 @@ struct edge_connection_t {
};
#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 e65c545d17..495ffd85dd 100644
--- a/src/core/or/entry_connection_st.h
+++ b/src/core/or/entry_connection_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file entry_connection_st.h
+ * @brief Entry connection structure.
+ **/
+
#ifndef ENTRY_CONNECTION_ST_H
#define ENTRY_CONNECTION_ST_H
@@ -97,4 +102,3 @@ struct entry_connection_t {
#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_))
#endif /* !defined(ENTRY_CONNECTION_ST_H) */
-
diff --git a/src/core/or/entry_port_cfg_st.h b/src/core/or/entry_port_cfg_st.h
index b84838d44f..ef1095086d 100644
--- a/src/core/or/entry_port_cfg_st.h
+++ b/src/core/or/entry_port_cfg_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file entry_port_cfg_st.h
+ * @brief Configuration structure for client ports.
+ **/
+
#ifndef ENTRY_PORT_CFG_ST_H
#define ENTRY_PORT_CFG_ST_H
@@ -48,7 +53,9 @@ struct entry_port_cfg_t {
* do we prefer IPv6? */
unsigned int prefer_ipv6_virtaddr : 1;
+ /** For socks listeners: can we send back the extended SOCKS5 error code? */
+ unsigned int extended_socks5_codes : 1;
+
};
#endif /* !defined(ENTRY_PORT_CFG_ST_H) */
-
diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h
index 7704ff16b5..a66ce24cfa 100644
--- a/src/core/or/extend_info_st.h
+++ b/src/core/or/extend_info_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file extend_info_st.h
+ * @brief Extend-info structure.
+ **/
+
#ifndef EXTEND_INFO_ST_H
#define EXTEND_INFO_ST_H
diff --git a/src/core/or/half_edge_st.h b/src/core/or/half_edge_st.h
index 1fe47ad3f1..c6b6e518fc 100644
--- a/src/core/or/half_edge_st.h
+++ b/src/core/or/half_edge_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file half_edge_st.h
+ * @brief Half-open connection structure.
+ **/
+
#ifndef HALF_EDGE_ST_H
#define HALF_EDGE_ST_H
@@ -31,4 +36,3 @@ typedef struct half_edge_t {
} half_edge_t;
#endif /* !defined(HALF_EDGE_ST_H) */
-
diff --git a/src/core/or/include.am b/src/core/or/include.am
new file mode 100644
index 0000000000..3626e76bed
--- /dev/null
+++ b/src/core/or/include.am
@@ -0,0 +1,96 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/core/or/address_set.c \
+ src/core/or/channel.c \
+ src/core/or/channelpadding.c \
+ src/core/or/channeltls.c \
+ src/core/or/circuitbuild.c \
+ src/core/or/circuitlist.c \
+ src/core/or/circuitmux.c \
+ src/core/or/circuitmux_ewma.c \
+ src/core/or/circuitpadding.c \
+ src/core/or/circuitpadding_machines.c \
+ src/core/or/circuitstats.c \
+ src/core/or/circuituse.c \
+ src/core/or/crypt_path.c \
+ src/core/or/command.c \
+ src/core/or/connection_edge.c \
+ src/core/or/connection_or.c \
+ src/core/or/dos.c \
+ src/core/or/onion.c \
+ src/core/or/ocirc_event.c \
+ src/core/or/or_periodic.c \
+ src/core/or/or_sys.c \
+ src/core/or/orconn_event.c \
+ src/core/or/policies.c \
+ src/core/or/protover.c \
+ 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/status.c \
+ src/core/or/versions.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/core/or/addr_policy_st.h \
+ src/core/or/address_set.h \
+ src/core/or/cell_queue_st.h \
+ src/core/or/cell_st.h \
+ src/core/or/channel.h \
+ src/core/or/channelpadding.h \
+ src/core/or/channeltls.h \
+ src/core/or/circuit_st.h \
+ src/core/or/circuitbuild.h \
+ src/core/or/circuitlist.h \
+ src/core/or/circuitmux.h \
+ src/core/or/circuitmux_ewma.h \
+ src/core/or/circuitstats.h \
+ src/core/or/circuitpadding.h \
+ src/core/or/circuitpadding_machines.h \
+ src/core/or/circuituse.h \
+ src/core/or/command.h \
+ src/core/or/connection_edge.h \
+ src/core/or/connection_or.h \
+ src/core/or/connection_st.h \
+ src/core/or/crypt_path.h \
+ src/core/or/cpath_build_state_st.h \
+ src/core/or/crypt_path_reference_st.h \
+ src/core/or/crypt_path_st.h \
+ src/core/or/destroy_cell_queue_st.h \
+ src/core/or/dos.h \
+ src/core/or/edge_connection_st.h \
+ src/core/or/half_edge_st.h \
+ src/core/or/entry_connection_st.h \
+ src/core/or/entry_port_cfg_st.h \
+ src/core/or/extend_info_st.h \
+ src/core/or/listener_connection_st.h \
+ src/core/or/onion.h \
+ src/core/or/or.h \
+ src/core/or/or_periodic.h \
+ src/core/or/or_sys.h \
+ src/core/or/orconn_event.h \
+ src/core/or/or_circuit_st.h \
+ src/core/or/or_connection_st.h \
+ src/core/or/or_handshake_certs_st.h \
+ src/core/or/or_handshake_state_st.h \
+ src/core/or/ocirc_event.h \
+ src/core/or/origin_circuit_st.h \
+ src/core/or/policies.h \
+ src/core/or/port_cfg_st.h \
+ src/core/or/protover.h \
+ src/core/or/reasons.h \
+ src/core/or/relay.h \
+ src/core/or/relay_crypto_st.h \
+ src/core/or/scheduler.h \
+ src/core/or/sendme.h \
+ src/core/or/server_port_cfg_st.h \
+ src/core/or/socks_request_st.h \
+ src/core/or/status.h \
+ src/core/or/tor_version_st.h \
+ src/core/or/var_cell_st.h \
+ src/core/or/versions.h
diff --git a/src/core/or/listener_connection_st.h b/src/core/or/listener_connection_st.h
index 1250d9c9b4..78175ea061 100644
--- a/src/core/or/listener_connection_st.h
+++ b/src/core/or/listener_connection_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file listener_connection_st.h
+ * @brief Listener connection structure.
+ **/
+
#ifndef LISTENER_CONNECTION_ST_H
#define LISTENER_CONNECTION_ST_H
@@ -22,4 +27,3 @@ struct listener_connection_t {
};
#endif /* !defined(LISTENER_CONNECTION_ST_H) */
-
diff --git a/src/core/or/ocirc_event.c b/src/core/or/ocirc_event.c
index 3cb9147134..fa16459175 100644
--- a/src/core/or/ocirc_event.c
+++ b/src/core/or/ocirc_event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,7 +22,7 @@
#include "core/or/cpath_build_state_st.h"
#include "core/or/ocirc_event.h"
-#include "core/or/ocirc_event_sys.h"
+#include "core/or/or_sys.h"
#include "core/or/origin_circuit_st.h"
#include "lib/subsys/subsys.h"
@@ -84,7 +84,7 @@ static dispatch_typefns_t ocirc_cevent_fns = {
.fmt_fn = ocirc_cevent_fmt,
};
-static int
+int
ocirc_add_pubsub(struct pubsub_connector_t *connector)
{
if (DISPATCH_REGISTER_TYPE(connector, ocirc_state, &ocirc_state_fns))
@@ -119,10 +119,3 @@ ocirc_cevent_publish(ocirc_cevent_msg_t *msg)
{
PUBLISH(ocirc_cevent, msg);
}
-
-const subsys_fns_t sys_ocirc_event = {
- .name = "ocirc_event",
- .supported = true,
- .level = -32,
- .add_pubsub = ocirc_add_pubsub,
-};
diff --git a/src/core/or/ocirc_event.h b/src/core/or/ocirc_event.h
index 8e9494874f..10307a3664 100644
--- a/src/core/or/ocirc_event.h
+++ b/src/core/or/ocirc_event.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/ocirc_event_sys.h b/src/core/or/ocirc_event_sys.h
deleted file mode 100644
index 61180496da..0000000000
--- a/src/core/or/ocirc_event_sys.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
-
-/**
- * \file ocirc_event_sys.h
- * \brief Declare subsystem object for the origin circuit event module.
- **/
-
-#ifndef TOR_OCIRC_EVENT_SYS_H
-#define TOR_OCIRC_EVENT_SYS_H
-
-extern const struct subsys_fns_t sys_ocirc_event;
-
-#endif /* !defined(TOR_OCIRC_EVENT_SYS_H) */
diff --git a/src/core/or/onion.c b/src/core/or/onion.c
index aeddedd807..a3b5c6922d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -240,11 +240,21 @@ created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
static int
check_extend_cell(const extend_cell_t *cell)
{
+ const bool is_extend2 = (cell->cell_type == RELAY_COMMAND_EXTEND2);
+
if (tor_digest_is_zero((const char*)cell->node_id))
return -1;
- /* We don't currently allow EXTEND2 cells without an IPv4 address */
- if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC)
- return -1;
+ if (!tor_addr_port_is_valid_ap(&cell->orport_ipv4, 0)) {
+ /* EXTEND cells must have an IPv4 address. */
+ if (!is_extend2) {
+ return -1;
+ }
+ /* EXTEND2 cells must have at least one IP address.
+ * It can be IPv4 or IPv6. */
+ if (!tor_addr_port_is_valid_ap(&cell->orport_ipv6, 0)) {
+ return -1;
+ }
+ }
if (cell->create_cell.cell_type == CELL_CREATE) {
if (cell->cell_type != RELAY_COMMAND_EXTEND)
return -1;
@@ -343,7 +353,7 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
continue;
found_ipv6 = 1;
tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr,
- (const char *)ls->un_ipv6_addr);
+ ls->un_ipv6_addr);
cell_out->orport_ipv6.port = ls->un_ipv6_port;
break;
case LS_LEGACY_ID:
@@ -364,7 +374,12 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
}
}
- if (!found_rsa_id || !found_ipv4) /* These are mandatory */
+ /* EXTEND2 cells must have an RSA ID */
+ if (!found_rsa_id)
+ return -1;
+
+ /* EXTEND2 cells must have at least one IP address */
+ if (!found_ipv4 && !found_ipv6)
return -1;
return create_cell_from_create2_cell_body(&cell_out->create_cell,
@@ -374,9 +389,11 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
/** Parse an EXTEND or EXTEND2 cell (according to <b>command</b>) from the
* <b>payload_length</b> bytes of <b>payload</b> into <b>cell_out</b>. Return
* 0 on success, -1 on failure. */
-int
-extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
- const uint8_t *payload, size_t payload_length)
+MOCK_IMPL(int,
+extend_cell_parse,(extend_cell_t *cell_out,
+ const uint8_t command,
+ const uint8_t *payload,
+ size_t payload_length))
{
tor_assert(cell_out);
@@ -618,12 +635,13 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
break;
case RELAY_COMMAND_EXTEND2:
{
- uint8_t n_specifiers = 2;
+ uint8_t n_specifiers = 1;
*command_out = RELAY_COMMAND_EXTEND2;
extend2_cell_body_t *cell = extend2_cell_body_new();
link_specifier_t *ls;
- {
- /* IPv4 specifier first. */
+ if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv4, 0)) {
+ /* Maybe IPv4 specifier first. */
+ ++n_specifiers;
ls = link_specifier_new();
extend2_cell_body_add_ls(cell, ls);
ls->ls_type = LS_IPV4;
@@ -649,6 +667,17 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
ls->ls_len = 32;
memcpy(ls->un_ed25519_id, cell_in->ed_pubkey.pubkey, 32);
}
+ if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv6, 0)) {
+ /* Then maybe IPv6 specifier. */
+ ++n_specifiers;
+ ls = link_specifier_new();
+ extend2_cell_body_add_ls(cell, ls);
+ ls->ls_type = LS_IPV6;
+ ls->ls_len = 18;
+ tor_addr_copy_ipv6_bytes(ls->un_ipv6_addr,
+ &cell_in->orport_ipv6.addr);
+ ls->un_ipv6_port = cell_in->orport_ipv6.port;
+ }
cell->n_spec = n_specifiers;
/* Now, the handshake */
diff --git a/src/core/or/onion.h b/src/core/or/onion.h
index bb0b5b8dfd..256f0a3f31 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -56,8 +56,8 @@ typedef struct extend_cell_t {
/** Ed25519 public identity key. Zero if not set. */
struct ed25519_public_key_t ed_pubkey;
/** The "create cell" embedded in this extend cell. Note that unlike the
- * create cells we generate ourself, this once can have a handshake type we
- * don't recognize. */
+ * create cells we generate ourselves, this create cell can have a handshake
+ * type we don't recognize. */
create_cell_t create_cell;
} extend_cell_t;
@@ -74,8 +74,10 @@ void create_cell_init(create_cell_t *cell_out, uint8_t cell_type,
const uint8_t *onionskin);
int create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in);
int created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in);
-int extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
- const uint8_t *payload_in, size_t payload_len);
+MOCK_DECL(int,extend_cell_parse,(extend_cell_t *cell_out,
+ const uint8_t command,
+ const uint8_t *payload_in,
+ size_t payload_len));
int extended_cell_parse(extended_cell_t *cell_out, const uint8_t command,
const uint8_t *payload_in, size_t payload_len);
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 990cfacbc0..8758a2ec6f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -24,7 +24,6 @@
#include "lib/arch/bytes.h"
#include "lib/cc/compat_compiler.h"
-#include "lib/cc/torint.h"
#include "lib/container/map.h"
#include "lib/buf/buffers.h"
#include "lib/container/smartlist.h"
@@ -168,12 +167,13 @@ struct curve25519_public_key_t;
#define PROXY_CONNECT 1
#define PROXY_SOCKS4 2
#define PROXY_SOCKS5 3
-/* !!!! If there is ever a PROXY_* type over 3, we must grow the proxy_type
+#define PROXY_HAPROXY 4
+/* !!!! If there is ever a PROXY_* type over 7, we must grow the proxy_type
* field in or_connection_t */
/* Pluggable transport proxy type. Don't use this in or_connection_t,
* instead use the actual underlying proxy type (see above). */
-#define PROXY_PLUGGABLE 4
+#define PROXY_PLUGGABLE 5
/** How many circuits do we want simultaneously in-progress to handle
* a given stream? */
@@ -220,7 +220,8 @@ struct curve25519_public_key_t;
#define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */
#define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */
#define END_OR_CONN_REASON_PT_MISSING 9 /* PT failed or not available */
-#define END_OR_CONN_REASON_MISC 10
+#define END_OR_CONN_REASON_TLS_ERROR 10 /* Problem in TLS protocol */
+#define END_OR_CONN_REASON_MISC 11
/* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for
* documentation of these. The values must match. */
@@ -609,21 +610,21 @@ typedef uint32_t circid_t;
/** Identifies a stream on a circuit */
typedef uint16_t streamid_t;
-/* channel_t typedef; struct channel_s is in channel.h */
+/* channel_t typedef; struct channel_t is in channel.h */
-typedef struct channel_s channel_t;
+typedef struct channel_t channel_t;
-/* channel_listener_t typedef; struct channel_listener_s is in channel.h */
+/* channel_listener_t typedef; struct channel_listener_t is in channel.h */
-typedef struct channel_listener_s channel_listener_t;
+typedef struct channel_listener_t channel_listener_t;
/* TLS channel stuff */
-typedef struct channel_tls_s channel_tls_t;
+typedef struct channel_tls_t channel_tls_t;
-/* circuitmux_t typedef; struct circuitmux_s is in circuitmux.h */
+/* circuitmux_t typedef; struct circuitmux_t is in circuitmux.h */
-typedef struct circuitmux_s circuitmux_t;
+typedef struct circuitmux_t circuitmux_t;
typedef struct cell_t cell_t;
typedef struct var_cell_t var_cell_t;
@@ -995,8 +996,6 @@ typedef struct routerset_t routerset_t;
typedef struct or_options_t or_options_t;
-#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level())
-
typedef struct or_state_t or_state_t;
#define MAX_SOCKS_ADDR_LEN 256
@@ -1013,7 +1012,7 @@ typedef struct or_state_t or_state_t;
#define BW_MIN_WEIGHT_SCALE 1
#define BW_MAX_WEIGHT_SCALE INT32_MAX
-typedef struct circuit_build_times_s circuit_build_times_t;
+typedef struct circuit_build_times_t circuit_build_times_t;
/********************************* config.c ***************************/
diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h
index f3eb861613..9bfe999728 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef OR_CIRCUIT_ST_H
@@ -27,7 +27,7 @@ struct or_circuit_t {
/** Pointer to a workqueue entry, if this circuit has given an onionskin to
* a cpuworker and is waiting for a response. Used to decide whether it is
* safe to free a circuit or if it is still in use by a cpuworker. */
- struct workqueue_entry_s *workqueue_entry;
+ struct workqueue_entry_t *workqueue_entry;
/** The circuit_id used in the previous (backward) hop of this circuit. */
circid_t p_circ_id;
diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h
index 051fcd00d3..92956c2847 100644
--- a/src/core/or/or_connection_st.h
+++ b/src/core/or/or_connection_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file or_connection_st.h
+ * @brief OR connection structure.
+ **/
+
#ifndef OR_CONNECTION_ST_H
#define OR_CONNECTION_ST_H
@@ -58,7 +63,7 @@ struct or_connection_t {
/** True iff this is an outgoing connection. */
unsigned int is_outgoing:1;
- unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */
+ unsigned int proxy_type:3; /**< One of PROXY_NONE...PROXY_HAPROXY */
unsigned int wide_circ_ids:1;
/** True iff this connection has had its bootstrap failure logged with
* control_event_bootstrap_problem. */
diff --git a/src/core/or/or_handshake_certs_st.h b/src/core/or/or_handshake_certs_st.h
index 9deb6d6d59..31755f04a1 100644
--- a/src/core/or/or_handshake_certs_st.h
+++ b/src/core/or/or_handshake_certs_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file or_handshake_certs_st.h
+ * @brief OR handshake certs structure
+ **/
+
#ifndef OR_HANDSHAKE_CERTS_ST
#define OR_HANDSHAKE_CERTS_ST
diff --git a/src/core/or/or_handshake_state_st.h b/src/core/or/or_handshake_state_st.h
index 472ce8a302..050404046d 100644
--- a/src/core/or/or_handshake_state_st.h
+++ b/src/core/or/or_handshake_state_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file or_handshake_state_st.h
+ * @brief OR handshake state structure
+ **/
+
#ifndef OR_HANDSHAKE_STATE_ST
#define OR_HANDSHAKE_STATE_ST
@@ -75,4 +80,3 @@ struct or_handshake_state_t {
};
#endif /* !defined(OR_HANDSHAKE_STATE_ST) */
-
diff --git a/src/core/or/or_periodic.c b/src/core/or/or_periodic.c
index fe28c99192..4dfdce14ca 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,11 +20,13 @@
#include "feature/relay/routermode.h"
+#ifndef COCCI
#define DECLARE_EVENT(name, roles, flags) \
static periodic_event_item_t name ## _event = \
PERIODIC_EVENT(name, \
PERIODIC_EVENT_ROLE_##roles, \
flags)
+#endif /* !defined(COCCI) */
#define FL(name) (PERIODIC_EVENT_FLAG_ ## name)
diff --git a/src/core/or/or_periodic.h b/src/core/or/or_periodic.h
index c2f47cf5ef..080573a838 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 6f8c81a4df..73c6087dce 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -34,10 +34,23 @@ subsys_or_shutdown(void)
policies_free_all();
}
+static int
+subsys_or_add_pubsub(struct pubsub_connector_t *connector)
+{
+ int rv = 0;
+ if (orconn_add_pubsub(connector) < 0)
+ rv = -1;
+ if (ocirc_add_pubsub(connector) < 0)
+ rv = -1;
+ return rv;
+}
+
const struct subsys_fns_t sys_or = {
.name = "or",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = 20,
.initialize = subsys_or_initialize,
.shutdown = subsys_or_shutdown,
+ .add_pubsub = subsys_or_add_pubsub,
};
diff --git a/src/core/or/or_sys.h b/src/core/or/or_sys.h
index c37ef01858..7ee56c8682 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,4 +14,8 @@
extern const struct subsys_fns_t sys_or;
+struct pubsub_connector_t;
+int ocirc_add_pubsub(struct pubsub_connector_t *connector);
+int orconn_add_pubsub(struct pubsub_connector_t *connector);
+
#endif /* !defined(TOR_CORE_OR_OR_SYS_H) */
diff --git a/src/core/or/orconn_event.c b/src/core/or/orconn_event.c
index 86f112fc09..c30e2dd22f 100644
--- a/src/core/or/orconn_event.c
+++ b/src/core/or/orconn_event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,7 +22,7 @@
#define ORCONN_EVENT_PRIVATE
#include "core/or/orconn_event.h"
-#include "core/or/orconn_event_sys.h"
+#include "core/or/or_sys.h"
DECLARE_PUBLISH(orconn_state);
DECLARE_PUBLISH(orconn_status);
@@ -65,7 +65,7 @@ static dispatch_typefns_t orconn_status_fns = {
.fmt_fn = orconn_status_fmt,
};
-static int
+int
orconn_add_pubsub(struct pubsub_connector_t *connector)
{
if (DISPATCH_REGISTER_TYPE(connector, orconn_state, &orconn_state_fns))
@@ -90,10 +90,3 @@ orconn_status_publish(orconn_status_msg_t *msg)
{
PUBLISH(orconn_status, msg);
}
-
-const subsys_fns_t sys_orconn_event = {
- .name = "orconn_event",
- .supported = true,
- .level = -33,
- .add_pubsub = orconn_add_pubsub,
-};
diff --git a/src/core/or/orconn_event.h b/src/core/or/orconn_event.h
index fb67a7d183..2653b20d6e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/orconn_event_sys.h b/src/core/or/orconn_event_sys.h
deleted file mode 100644
index 9703b2e3d1..0000000000
--- a/src/core/or/orconn_event_sys.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
-
-/**
- * \file orconn_event_sys.h
- * \brief Declare subsystem object for the OR connection event module.
- **/
-#ifndef TOR_ORCONN_EVENT_SYS_H
-#define TOR_ORCONN_EVENT_SYS_H
-
-extern const struct subsys_fns_t sys_orconn_event;
-
-#endif /* !defined(TOR_ORCONN_EVENT_SYS_H) */
diff --git a/src/core/or/origin_circuit_st.h b/src/core/or/origin_circuit_st.h
index 01bbc84ae2..79e250cd59 100644
--- a/src/core/or/origin_circuit_st.h
+++ b/src/core/or/origin_circuit_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file origin_circuit_st.h
+ * @brief Origin circuit structure.
+ **/
+
#ifndef ORIGIN_CIRCUIT_ST_H
#define ORIGIN_CIRCUIT_ST_H
diff --git a/src/core/or/policies.c b/src/core/or/policies.c
index 39a0817c85..2bf2dc7005 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -167,7 +167,7 @@ policy_expand_unspec(smartlist_t **policy)
}
tor_addr_from_ipv4h(&newpolicy_ipv4.addr, 0);
tor_addr_from_ipv6_bytes(&newpolicy_ipv6.addr,
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
+ (const uint8_t *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv4));
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv6));
addr_policy_free(p);
@@ -463,8 +463,7 @@ fascist_firewall_use_ipv6(const or_options_t *options)
* ClientPreferIPv6DirPort is deprecated, but check it anyway. */
return (options->ClientUseIPv6 == 1 || options->ClientUseIPv4 == 0 ||
options->ClientPreferIPv6ORPort == 1 ||
- options->ClientPreferIPv6DirPort == 1 || options->UseBridges == 1 ||
- options->ClientAutoIPv6ORPort == 1);
+ options->ClientPreferIPv6DirPort == 1 || options->UseBridges == 1);
}
/** Do we prefer to connect to IPv6, ignoring ClientPreferIPv6ORPort and
@@ -491,15 +490,6 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options)
return -1;
}
-/* Choose whether we prefer IPv4 or IPv6 by randomly choosing an address
- * family. Return 0 for IPv4, and 1 for IPv6. */
-MOCK_IMPL(int,
-fascist_firewall_rand_prefer_ipv6_addr, (void))
-{
- /* TODO: Check for failures, and infer our preference based on this. */
- return crypto_rand_int(2);
-}
-
/** Do we prefer to connect to IPv6 ORPorts?
* Use node_ipv6_or_preferred() whenever possible: it supports bridge client
* per-node IPv6 preferences.
@@ -514,10 +504,7 @@ fascist_firewall_prefer_ipv6_orport(const or_options_t *options)
}
/* We can use both IPv4 and IPv6 - which do we prefer? */
- if (options->ClientAutoIPv6ORPort == 1) {
- /* If ClientAutoIPv6ORPort is 1, we prefer IPv4 or IPv6 at random. */
- return fascist_firewall_rand_prefer_ipv6_addr();
- } else if (options->ClientPreferIPv6ORPort == 1) {
+ if (options->ClientPreferIPv6ORPort == 1) {
return 1;
}
@@ -933,49 +920,6 @@ fascist_firewall_choose_address_ipv4h(uint32_t ipv4h_addr,
pref_ipv6, ap);
}
-/* Some microdescriptor consensus methods have no IPv6 addresses in rs: they
- * are in the microdescriptors. For these consensus methods, we can't rely on
- * the node's IPv6 address until its microdescriptor is available (when using
- * microdescs).
- * But for bridges, rewrite_node_address_for_bridge() updates node->ri with
- * the configured address, so we can trust bridge addresses.
- * (Bridges could gain an IPv6 address if their microdescriptor arrives, but
- * this will never be their preferred address: that is in the config.)
- * Returns true if the node needs a microdescriptor for its IPv6 address, and
- * false if the addresses in the node are already up-to-date.
- */
-static int
-node_awaiting_ipv6(const or_options_t* options, const node_t *node)
-{
- tor_assert(node);
-
- /* There's no point waiting for an IPv6 address if we'd never use it */
- if (!fascist_firewall_use_ipv6(options)) {
- return 0;
- }
-
- /* If the node has an IPv6 address, we're not waiting */
- if (node_has_ipv6_addr(node)) {
- return 0;
- }
-
- /* If the current consensus method and flavour has IPv6 addresses, we're not
- * waiting */
- if (networkstatus_consensus_has_ipv6(options)) {
- return 0;
- }
-
- /* Bridge clients never use the address from a bridge's md, so there's no
- * need to wait for it. */
- if (node_is_a_configured_bridge(node)) {
- return 0;
- }
-
- /* We are waiting if we_use_microdescriptors_for_circuits() and we have no
- * md. */
- return (!node->md && we_use_microdescriptors_for_circuits(options));
-}
-
/** Like fascist_firewall_choose_address_base(), but takes <b>rs</b>.
* Consults the corresponding node, then falls back to rs if node is NULL.
* This should only happen when there's no valid consensus, and rs doesn't
@@ -998,7 +942,7 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs,
const or_options_t *options = get_options();
const node_t *node = node_get_by_id(rs->identity_digest);
- if (node && !node_awaiting_ipv6(options, node)) {
+ if (node) {
fascist_firewall_choose_address_node(node, fw_connection, pref_only, ap);
} else {
/* There's no node-specific IPv6 preference, so use the generic IPv6
@@ -1061,7 +1005,7 @@ fascist_firewall_choose_address_ls(const smartlist_t *lspecs,
* direct connection. */
if (have_v6) continue;
tor_addr_from_ipv6_bytes(&addr_v6,
- (const char *) link_specifier_getconstarray_un_ipv6_addr(ls));
+ link_specifier_getconstarray_un_ipv6_addr(ls));
port_v6 = link_specifier_get_un_ipv6_port(ls);
have_v6 = 1;
break;
@@ -1111,17 +1055,6 @@ fascist_firewall_choose_address_node(const node_t *node,
}
node_assert_ok(node);
- /* Calling fascist_firewall_choose_address_node() when the node is missing
- * IPv6 information breaks IPv6-only clients.
- * If the node is a hard-coded fallback directory or authority, call
- * fascist_firewall_choose_address_rs() on the fake (hard-coded) routerstatus
- * for the node.
- * If it is not hard-coded, check that the node has a microdescriptor, full
- * descriptor (routerinfo), or is one of our configured bridges before
- * calling this function. */
- if (BUG(node_awaiting_ipv6(get_options(), node))) {
- return;
- }
const int pref_ipv6_node = (fw_connection == FIREWALL_OR_CONNECTION
? node_ipv6_or_preferred(node)
@@ -1459,9 +1392,9 @@ policy_hash(const policy_map_ent_t *ent)
}
HT_PROTOTYPE(policy_map, policy_map_ent_t, node, policy_hash,
- policy_eq)
+ policy_eq);
HT_GENERATE2(policy_map, policy_map_ent_t, node, policy_hash,
- policy_eq, 0.6, tor_reallocarray_, tor_free_)
+ policy_eq, 0.6, tor_reallocarray_, tor_free_);
/** Given a pointer to an addr_policy_t, return a copy of the pointer to the
* "canonical" copy of that addr_policy_t; the canonical copy is a single
diff --git a/src/core/or/policies.h b/src/core/or/policies.h
index 3c46363c04..72a37d62b0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -70,7 +70,6 @@ typedef struct short_policy_t {
int firewall_is_fascist_or(void);
int firewall_is_fascist_dir(void);
int fascist_firewall_use_ipv6(const or_options_t *options);
-MOCK_DECL(int, fascist_firewall_rand_prefer_ipv6_addr, (void));
int fascist_firewall_prefer_ipv6_orport(const or_options_t *options);
int fascist_firewall_prefer_ipv6_dirport(const or_options_t *options);
diff --git a/src/core/or/port_cfg_st.h b/src/core/or/port_cfg_st.h
index e9e82bb1de..064e679d78 100644
--- a/src/core/or/port_cfg_st.h
+++ b/src/core/or/port_cfg_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file port_cfg_st.h
+ * @brief Listener port configuration structure.
+ **/
+
#ifndef PORT_CFG_ST_H
#define PORT_CFG_ST_H
@@ -32,4 +37,3 @@ struct port_cfg_t {
};
#endif /* !defined(PORT_CFG_ST_H) */
-
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index 905c5e9ed3..c3f443631b 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -40,8 +40,8 @@ static const struct {
protocol_type_t protover_type;
const char *name;
/* If you add a new protocol here, you probably also want to add
- * parsing for it in routerstatus_parse_entry_from_string() so that
- * it is set in routerstatus_t */
+ * parsing for it in summarize_protover_flags(), so that it has a
+ * summary flag in routerstatus_t */
} PROTOCOL_NAMES[] = {
{ PRT_LINK, "Link" },
{ PRT_LINKAUTH, "LinkAuth" },
@@ -391,6 +391,7 @@ protover_get_supported_protocols(void)
"Cons=1-2 "
"Desc=1-2 "
"DirCache=1-2 "
+ "FlowCtrl=1 "
"HSDir=1-2 "
"HSIntro=3-5 "
"HSRend=1-2 "
@@ -401,9 +402,8 @@ protover_get_supported_protocols(void)
"LinkAuth=3 "
#endif
"Microdesc=1-2 "
- "Relay=1-2 "
"Padding=2 "
- "FlowCtrl=1";
+ "Relay=1-2";
}
/** The protocols from protover_get_supported_protocols(), as parsed into a
diff --git a/src/core/or/protover.h b/src/core/or/protover.h
index af45a31aeb..9509f3e8a3 100644
--- a/src/core/or/protover.h
+++ b/src/core/or/protover.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/protover_rust.c b/src/core/or/protover_rust.c
index bc56ea11d0..f44746b6da 100644
--- a/src/core/or/protover_rust.c
+++ b/src/core/or/protover_rust.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
diff --git a/src/core/or/reasons.c b/src/core/or/reasons.c
index e21bfa670a..708f43a689 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -244,6 +244,8 @@ orconn_end_reason_to_control_string(int r)
return "IOERROR";
case END_OR_CONN_REASON_RESOURCE_LIMIT:
return "RESOURCELIMIT";
+ case END_OR_CONN_REASON_TLS_ERROR:
+ return "TLS_ERROR";
case END_OR_CONN_REASON_MISC:
return "MISC";
case END_OR_CONN_REASON_PT_MISSING:
@@ -276,6 +278,8 @@ tls_error_to_orconn_end_reason(int e)
case TOR_TLS_CLOSE:
case TOR_TLS_DONE:
return END_OR_CONN_REASON_DONE;
+ case TOR_TLS_ERROR_MISC:
+ return END_OR_CONN_REASON_TLS_ERROR;
default:
return END_OR_CONN_REASON_MISC;
}
diff --git a/src/core/or/reasons.h b/src/core/or/reasons.h
index c45a8bc38d..2e534aab73 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index f83d2365e4..75d2d479e7 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -66,6 +66,7 @@
#include "lib/crypt_ops/crypto_util.h"
#include "feature/dircommon/directory.h"
#include "feature/relay/dns.h"
+#include "feature/relay/circuitbuild_relay.h"
#include "feature/stats/geoip_stats.h"
#include "feature/hs/hs_cache.h"
#include "core/mainloop/mainloop.h"
@@ -866,7 +867,7 @@ connection_ap_process_end_not_open(
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
} else if (rh->length == 17 || rh->length == 21) {
tor_addr_from_ipv6_bytes(&addr,
- (char*)(cell->payload+RELAY_HEADER_SIZE+1));
+ (cell->payload+RELAY_HEADER_SIZE+1));
if (rh->length == 21)
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17));
}
@@ -1091,7 +1092,7 @@ connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
return -1;
if (get_uint8(payload + 4) != 6)
return -1;
- tor_addr_from_ipv6_bytes(addr_out, (char*)(payload + 5));
+ tor_addr_from_ipv6_bytes(addr_out, (payload + 5));
bytes = ntohl(get_uint32(payload + 21));
if (bytes <= INT32_MAX)
*ttl_out = (int) bytes;
@@ -1164,7 +1165,7 @@ resolved_cell_parse(const cell_t *cell, const relay_header_t *rh,
if (answer_len != 16)
goto err;
addr = tor_malloc_zero(sizeof(*addr));
- tor_addr_from_ipv6_bytes(&addr->addr, (const char*) cp);
+ tor_addr_from_ipv6_bytes(&addr->addr, cp);
cp += 16;
addr->ttl = ntohl(get_uint32(cp));
cp += 4;
@@ -3216,7 +3217,7 @@ decode_address_from_payload(tor_addr_t *addr_out, const uint8_t *payload,
case RESOLVED_TYPE_IPV6:
if (payload[1] != 16)
return NULL;
- tor_addr_from_ipv6_bytes(addr_out, (char*)(payload+2));
+ tor_addr_from_ipv6_bytes(addr_out, (payload+2));
break;
default:
tor_addr_make_unspec(addr_out);
diff --git a/src/core/or/relay.h b/src/core/or/relay.h
index 99f7553013..31bed0e01b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -107,7 +107,7 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ,
STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
tor_addr_t *addr_out, int *ttl_out);
/** An address-and-ttl tuple as yielded by resolved_cell_parse */
-typedef struct address_ttl_s {
+typedef struct address_ttl_t {
tor_addr_t addr;
char *hostname;
int ttl;
diff --git a/src/core/or/relay_crypto_st.h b/src/core/or/relay_crypto_st.h
index 83bbd329a6..d92f486a90 100644
--- a/src/core/or/relay_crypto_st.h
+++ b/src/core/or/relay_crypto_st.h
@@ -1,13 +1,18 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file relay_crypto_st.h
+ * @brief Relay-cell encryption state structure.
+ **/
+
#ifndef RELAY_CRYPTO_ST_H
#define RELAY_CRYPTO_ST_H
-#define crypto_cipher_t aes_cnt_cipher
+#define crypto_cipher_t aes_cnt_cipher_t
struct crypto_cipher_t;
struct crypto_digest_t;
diff --git a/src/core/or/scheduler.c b/src/core/or/scheduler.c
index 0e3f0fe815..072d78128b 100644
--- a/src/core/or/scheduler.c
+++ b/src/core/or/scheduler.c
@@ -1,18 +1,17 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
#include "app/config/config.h"
#include "lib/evloop/compat_libevent.h"
-#define SCHEDULER_PRIVATE_
+#define SCHEDULER_PRIVATE
#define SCHEDULER_KIST_PRIVATE
#include "core/or/scheduler.h"
#include "core/mainloop/mainloop.h"
#include "lib/buf/buffers.h"
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#include "core/or/channeltls.h"
-#include "lib/evloop/compat_libevent.h"
#include "core/or/or_connection_st.h"
@@ -43,7 +42,7 @@
* circuit scheduler. It was supposed to prioritize circuits across many
* channels, but wasn't effective. It is preserved in scheduler_vanilla.c.
*
- * [0]: http://www.robgjansen.com/publications/kist-sec2014.pdf
+ * [0]: https://www.robgjansen.com/publications/kist-sec2014.pdf
*
* Then we actually got around to implementing KIST for real. We decided to
* modularize the scheduler so new ones can be implemented. You can find KIST
@@ -503,7 +502,12 @@ scheduler_free_all(void)
the_scheduler = NULL;
}
-/** Mark a channel as no longer ready to accept writes. */
+/** Mark a channel as no longer ready to accept writes.
+ *
+ * Possible state changes:
+ * - SCHED_CHAN_PENDING -> SCHED_CHAN_WAITING_TO_WRITE
+ * - SCHED_CHAN_WAITING_FOR_CELLS -> SCHED_CHAN_IDLE
+ */
MOCK_IMPL(void,
scheduler_channel_doesnt_want_writes,(channel_t *chan))
{
@@ -514,31 +518,32 @@ scheduler_channel_doesnt_want_writes,(channel_t *chan))
return;
}
- /* If it's already in pending, we can put it in waiting_to_write */
if (chan->scheduler_state == SCHED_CHAN_PENDING) {
/*
- * It's in channels_pending, so it shouldn't be in any of
- * the other lists. It can't write any more, so it goes to
- * channels_waiting_to_write.
+ * It has cells but no longer can write, so it becomes
+ * SCHED_CHAN_WAITING_TO_WRITE. It's in channels_pending, so we
+ * should remove it from the list.
*/
smartlist_pqueue_remove(channels_pending,
scheduler_compare_channels,
offsetof(channel_t, sched_heap_idx),
chan);
scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE);
- } else {
+ } else if (chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS) {
/*
- * It's not in pending, so it can't become waiting_to_write; it's
- * either not in any of the lists (nothing to do) or it's already in
- * waiting_for_cells (remove it, can't write any more).
+ * It does not have cells and no longer can write, so it becomes
+ * SCHED_CHAN_IDLE.
*/
- if (chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS) {
- scheduler_set_channel_state(chan, SCHED_CHAN_IDLE);
- }
+ scheduler_set_channel_state(chan, SCHED_CHAN_IDLE);
}
}
-/** Mark a channel as having waiting cells. */
+/** Mark a channel as having waiting cells.
+ *
+ * Possible state changes:
+ * - SCHED_CHAN_WAITING_FOR_CELLS -> SCHED_CHAN_PENDING
+ * - SCHED_CHAN_IDLE -> SCHED_CHAN_WAITING_TO_WRITE
+ */
MOCK_IMPL(void,
scheduler_channel_has_waiting_cells,(channel_t *chan))
{
@@ -549,12 +554,11 @@ scheduler_channel_has_waiting_cells,(channel_t *chan))
return;
}
- /* First, check if it's also writeable */
if (chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS) {
/*
- * It's in channels_waiting_for_cells, so it shouldn't be in any of
- * the other lists. It has waiting cells now, so it goes to
- * channels_pending.
+ * It is able to write and now has cells, so it becomes
+ * SCHED_CHAN_PENDING. It must be added to the channels_pending
+ * list.
*/
scheduler_set_channel_state(chan, SCHED_CHAN_PENDING);
if (!SCHED_BUG(chan->sched_heap_idx != -1, chan)) {
@@ -566,16 +570,12 @@ scheduler_channel_has_waiting_cells,(channel_t *chan))
/* If we made a channel pending, we potentially have scheduling work to
* do. */
the_scheduler->schedule();
- } else {
+ } else if (chan->scheduler_state == SCHED_CHAN_IDLE) {
/*
- * It's not in waiting_for_cells, so it can't become pending; it's
- * either not in any of the lists (we add it to waiting_to_write)
- * or it's already in waiting_to_write or pending (we do nothing)
+ * It is not able to write but now has cells, so it becomes
+ * SCHED_CHAN_WAITING_TO_WRITE.
*/
- if (!(chan->scheduler_state == SCHED_CHAN_WAITING_TO_WRITE ||
- chan->scheduler_state == SCHED_CHAN_PENDING)) {
- scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE);
- }
+ scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE);
}
}
@@ -663,8 +663,12 @@ scheduler_release_channel,(channel_t *chan))
scheduler_set_channel_state(chan, SCHED_CHAN_IDLE);
}
-/** Mark a channel as ready to accept writes */
-
+/** Mark a channel as ready to accept writes.
+ * Possible state changes:
+ *
+ * - SCHED_CHAN_WAITING_TO_WRITE -> SCHED_CHAN_PENDING
+ * - SCHED_CHAN_IDLE -> SCHED_CHAN_WAITING_FOR_CELLS
+ */
void
scheduler_channel_wants_writes(channel_t *chan)
{
@@ -675,10 +679,11 @@ scheduler_channel_wants_writes(channel_t *chan)
return;
}
- /* If it's already in waiting_to_write, we can put it in pending */
if (chan->scheduler_state == SCHED_CHAN_WAITING_TO_WRITE) {
/*
- * It can write now, so it goes to channels_pending.
+ * It has cells and can now write, so it becomes
+ * SCHED_CHAN_PENDING. It must be added to the channels_pending
+ * list.
*/
scheduler_set_channel_state(chan, SCHED_CHAN_PENDING);
if (!SCHED_BUG(chan->sched_heap_idx != -1, chan)) {
@@ -689,15 +694,12 @@ scheduler_channel_wants_writes(channel_t *chan)
}
/* We just made a channel pending, we have scheduling work to do. */
the_scheduler->schedule();
- } else {
+ } else if (chan->scheduler_state == SCHED_CHAN_IDLE) {
/*
- * It's not in SCHED_CHAN_WAITING_TO_WRITE, so it can't become pending;
- * it's either idle and goes to WAITING_FOR_CELLS, or it's a no-op.
+ * It does not have cells but can now write, so it becomes
+ * SCHED_CHAN_WAITING_FOR_CELLS.
*/
- if (!(chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS ||
- chan->scheduler_state == SCHED_CHAN_PENDING)) {
- scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_FOR_CELLS);
- }
+ scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_FOR_CELLS);
}
}
diff --git a/src/core/or/scheduler.h b/src/core/or/scheduler.h
index 843be2603c..82df2b0b0f 100644
--- a/src/core/or/scheduler.h
+++ b/src/core/or/scheduler.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* * Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -40,7 +40,7 @@ typedef enum {
* doesn't create any state for itself, thus it has nothing to free when Tor
* is shutting down), then set that function pointer to NULL.
*/
-typedef struct scheduler_s {
+typedef struct scheduler_t {
/* Scheduler type. This is used for logging when the scheduler is switched
* during runtime. */
scheduler_types_t type;
@@ -136,7 +136,9 @@ MOCK_DECL(void, scheduler_channel_has_waiting_cells, (channel_t *chan));
* These functions are only visible to the scheduling system, the current
* scheduler implementation, and tests.
*****************************************************************************/
-#ifdef SCHEDULER_PRIVATE_
+#ifdef SCHEDULER_PRIVATE
+
+#include "ext/ht.h"
/*********************************
* Defined in scheduler.c
@@ -173,8 +175,8 @@ void scheduler_touch_channel(channel_t *chan);
/* Socket table entry which holds information of a channel's socket and kernel
* TCP information. Only used by KIST. */
-typedef struct socket_table_ent_s {
- HT_ENTRY(socket_table_ent_s) node;
+typedef struct socket_table_ent_t {
+ HT_ENTRY(socket_table_ent_t) node;
const channel_t *chan;
/* Amount written this scheduling run */
uint64_t written;
@@ -187,7 +189,7 @@ typedef struct socket_table_ent_s {
uint32_t notsent;
} socket_table_ent_t;
-typedef HT_HEAD(outbuf_table_s, outbuf_table_ent_s) outbuf_table_t;
+typedef HT_HEAD(outbuf_table_s, outbuf_table_ent_t) outbuf_table_t;
MOCK_DECL(int, channel_should_write_to_kernel,
(outbuf_table_t *table, channel_t *chan));
@@ -212,7 +214,6 @@ extern int32_t sched_run_interval;
scheduler_t *get_vanilla_scheduler(void);
-#endif /* defined(SCHEDULER_PRIVATE_) */
+#endif /* defined(SCHEDULER_PRIVATE) */
#endif /* !defined(TOR_SCHEDULER_H) */
-
diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c
index 35b613cb8a..c73d768f88 100644
--- a/src/core/or/scheduler_kist.c
+++ b/src/core/or/scheduler_kist.c
@@ -1,6 +1,11 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file scheduler_kist.c
+ * @brief Implements the KIST cell scheduler.
+ **/
+
#define SCHEDULER_KIST_PRIVATE
#include "core/or/or.h"
@@ -8,10 +13,10 @@
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "feature/nodelist/networkstatus.h"
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#include "core/or/channel.h"
#include "core/or/channeltls.h"
-#define SCHEDULER_PRIVATE_
+#define SCHEDULER_PRIVATE
#include "core/or/scheduler.h"
#include "lib/math/fp.h"
@@ -46,22 +51,22 @@ socket_table_ent_eq(const socket_table_ent_t *a, const socket_table_ent_t *b)
return a->chan == b->chan;
}
-typedef HT_HEAD(socket_table_s, socket_table_ent_s) socket_table_t;
+typedef HT_HEAD(socket_table_s, socket_table_ent_t) socket_table_t;
static socket_table_t socket_table = HT_INITIALIZER();
-HT_PROTOTYPE(socket_table_s, socket_table_ent_s, node, socket_table_ent_hash,
- socket_table_ent_eq)
-HT_GENERATE2(socket_table_s, socket_table_ent_s, node, socket_table_ent_hash,
- socket_table_ent_eq, 0.6, tor_reallocarray, tor_free_)
+HT_PROTOTYPE(socket_table_s, socket_table_ent_t, node, socket_table_ent_hash,
+ socket_table_ent_eq);
+HT_GENERATE2(socket_table_s, socket_table_ent_t, node, socket_table_ent_hash,
+ socket_table_ent_eq, 0.6, tor_reallocarray, tor_free_);
/* outbuf_table hash table stuff. The outbuf_table keeps track of which
* channels have data sitting in their outbuf so the kist scheduler can force
* a write from outbuf to kernel periodically during a run and at the end of a
* run. */
-typedef struct outbuf_table_ent_s {
- HT_ENTRY(outbuf_table_ent_s) node;
+typedef struct outbuf_table_ent_t {
+ HT_ENTRY(outbuf_table_ent_t) node;
channel_t *chan;
} outbuf_table_ent_t;
@@ -77,10 +82,10 @@ outbuf_table_ent_eq(const outbuf_table_ent_t *a, const outbuf_table_ent_t *b)
return a->chan->global_identifier == b->chan->global_identifier;
}
-HT_PROTOTYPE(outbuf_table_s, outbuf_table_ent_s, node, outbuf_table_ent_hash,
- outbuf_table_ent_eq)
-HT_GENERATE2(outbuf_table_s, outbuf_table_ent_s, node, outbuf_table_ent_hash,
- outbuf_table_ent_eq, 0.6, tor_reallocarray, tor_free_)
+HT_PROTOTYPE(outbuf_table_s, outbuf_table_ent_t, node, outbuf_table_ent_hash,
+ outbuf_table_ent_eq);
+HT_GENERATE2(outbuf_table_s, outbuf_table_ent_t, node, outbuf_table_ent_hash,
+ outbuf_table_ent_eq, 0.6, tor_reallocarray, tor_free_);
/*****************************************************************************
* Other internal data
@@ -458,6 +463,13 @@ MOCK_IMPL(void, channel_write_to_kernel, (channel_t *chan))
log_debug(LD_SCHED, "Writing %lu bytes to kernel for chan %" PRIu64,
(unsigned long)channel_outbuf_length(chan),
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()'.
+ * This side-effect will only occur if the channel is currently in the
+ * 'SCHED_CHAN_WAITING_TO_WRITE' or 'SCHED_CHAN_IDLE' states, which KIST
+ * rarely uses, so it should be fine unless KIST begins using these states
+ * in the future. */
connection_handle_write(TO_CONN(BASE_CHAN_TO_TLS(chan)->conn), 0);
}
diff --git a/src/core/or/scheduler_vanilla.c b/src/core/or/scheduler_vanilla.c
index 33536ae04b..d862ff8710 100644
--- a/src/core/or/scheduler_vanilla.c
+++ b/src/core/or/scheduler_vanilla.c
@@ -1,11 +1,16 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file scheduler_vanilla.c
+ * @brief "Vanilla" (pre-KIST) cell scheduler code.
+ **/
+
#include "core/or/or.h"
#include "app/config/config.h"
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#include "core/or/channel.h"
-#define SCHEDULER_PRIVATE_
+#define SCHEDULER_PRIVATE
#include "core/or/scheduler.h"
/*****************************************************************************
@@ -172,4 +177,3 @@ get_vanilla_scheduler(void)
{
return &vanilla_scheduler;
}
-
diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c
index e61cf0c0f8..788f56088c 100644
--- a/src/core/or/sendme.c
+++ b/src/core/or/sendme.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019, The Tor Project, Inc. */
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/sendme.h b/src/core/or/sendme.h
index 9d757ee435..05d37ec3bb 100644
--- a/src/core/or/sendme.h
+++ b/src/core/or/sendme.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019, The Tor Project, Inc. */
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/server_port_cfg_st.h b/src/core/or/server_port_cfg_st.h
index 0738735c61..9a005eccdf 100644
--- a/src/core/or/server_port_cfg_st.h
+++ b/src/core/or/server_port_cfg_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file server_port_cfg_st.h
+ * @brief Cnfiguration structure for server ports.
+ **/
+
#ifndef SERVER_PORT_CFG_ST_H
#define SERVER_PORT_CFG_ST_H
@@ -17,4 +22,3 @@ struct server_port_cfg_t {
};
#endif /* !defined(SERVER_PORT_CFG_ST_H) */
-
diff --git a/src/core/or/socks_request_st.h b/src/core/or/socks_request_st.h
index 9fb941ff7e..4bcdb48b92 100644
--- a/src/core/or/socks_request_st.h
+++ b/src/core/or/socks_request_st.h
@@ -1,12 +1,19 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file socks_request_st.h
+ * @brief Client request structure.
+ **/
+
#ifndef SOCKS_REQUEST_ST_H
#define SOCKS_REQUEST_ST_H
+#include "lib/net/socks5_status.h"
+
#define MAX_SOCKS_REPLY_LEN 1024
#define SOCKS_NO_AUTH 0x00
@@ -58,6 +65,11 @@ struct socks_request_t {
* "username/password" authentication if both are offered. Used as input to
* parse_socks. */
unsigned int socks_prefer_no_auth : 1;
+ /** If set, we can send back the extended error code in the reply. */
+ unsigned int socks_use_extended_errors : 1;
+ /** If non zero, this contains the extended error code that should be used
+ * if the port was configured to use them. */
+ socks5_reply_status_t socks_extended_error_code;
/** Number of bytes in username; 0 if username is NULL */
size_t usernamelen;
diff --git a/src/core/or/status.c b/src/core/or/status.c
index 46494ca76c..ed8448883c 100644
--- a/src/core/or/status.c
+++ b/src/core/or/status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,6 +17,7 @@
#include "core/or/or.h"
#include "core/or/circuituse.h"
#include "app/config/config.h"
+#include "feature/dirclient/dirclient.h"
#include "core/or/status.h"
#include "feature/nodelist/nodelist.h"
#include "core/or/relay.h"
@@ -146,6 +147,8 @@ log_heartbeat(time_t now)
uptime, count_circuits(), bw_sent, bw_rcvd,
hibernating?" We are currently hibernating.":"");
+ dirclient_dump_total_dls();
+
if (server_mode(options) && accounting_is_enabled(options) && !hibernating) {
log_accounting(now, options);
}
diff --git a/src/core/or/status.h b/src/core/or/status.h
index 3467501ebb..639f8cdf51 100644
--- a/src/core/or/status.h
+++ b/src/core/or/status.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file status.h
+ * @brief Header for status.c
+ **/
+
#ifndef TOR_STATUS_H
#define TOR_STATUS_H
@@ -15,4 +20,3 @@ STATIC char *bytes_to_usage(uint64_t bytes);
#endif
#endif /* !defined(TOR_STATUS_H) */
-
diff --git a/src/core/or/tor_version_st.h b/src/core/or/tor_version_st.h
index c5bdcaf07b..46644c5eb8 100644
--- a/src/core/or/tor_version_st.h
+++ b/src/core/or/tor_version_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file tor_version_st.h
+ * @brief Parsed Tor version structure.
+ **/
+
#ifndef TOR_VERSION_ST_H
#define TOR_VERSION_ST_H
@@ -29,4 +34,3 @@ struct tor_version_t {
};
#endif /* !defined(TOR_VERSION_ST_H) */
-
diff --git a/src/core/or/var_cell_st.h b/src/core/or/var_cell_st.h
index 607c0d6c83..caf64c63a5 100644
--- a/src/core/or/var_cell_st.h
+++ b/src/core/or/var_cell_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file var_cell_st.h
+ * @brief Variable-length cell structure.
+ **/
+
#ifndef VAR_CELL_ST_H
#define VAR_CELL_ST_H
@@ -20,4 +25,3 @@ struct var_cell_t {
};
#endif /* !defined(VAR_CELL_ST_H) */
-
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index 2c32b529f7..31f1f5b997 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -296,7 +296,7 @@ tor_version_parse(const char *s, tor_version_t *out)
return -1;
hexlen = (int)(close_paren-cp);
memwipe(digest, 0, sizeof(digest));
- if ( hexlen == 0 || (hexlen % 2) == 1)
+ if (hexlen == 0 || (hexlen % 2) == 1)
return -1;
if (base16_decode(digest, hexlen/2, cp, hexlen) != hexlen/2)
return -1;
diff --git a/src/core/or/versions.h b/src/core/or/versions.h
index 9aa7a0db87..75dc17f9c7 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/.may_include b/src/core/proto/.may_include
index c1647a5cf9..a66c3f83a6 100644
--- a/src/core/proto/.may_include
+++ b/src/core/proto/.may_include
@@ -4,7 +4,11 @@ orconfig.h
lib/crypt_ops/*.h
lib/buf/*.h
+lib/malloc/*.h
+lib/string/*.h
+
+lib/net/address.h
trunnel/*.h
-core/proto/*.h \ No newline at end of file
+core/proto/*.h
diff --git a/src/core/proto/core_proto.md b/src/core/proto/core_proto.md
new file mode 100644
index 0000000000..ad43bc5846
--- /dev/null
+++ b/src/core/proto/core_proto.md
@@ -0,0 +1,6 @@
+@dir /core/proto
+@brief core/proto: Protocol encoding/decoding
+
+These functions should (but do not always) exist at a lower level than most
+of the rest of core.
+
diff --git a/src/core/proto/include.am b/src/core/proto/include.am
new file mode 100644
index 0000000000..726ef924cf
--- /dev/null
+++ b/src/core/proto/include.am
@@ -0,0 +1,18 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/core/proto/proto_cell.c \
+ src/core/proto/proto_control0.c \
+ src/core/proto/proto_ext_or.c \
+ src/core/proto/proto_haproxy.c \
+ src/core/proto/proto_http.c \
+ src/core/proto/proto_socks.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/core/proto/proto_cell.h \
+ src/core/proto/proto_control0.h \
+ src/core/proto/proto_ext_or.h \
+ src/core/proto/proto_haproxy.h \
+ src/core/proto/proto_http.h \
+ src/core/proto/proto_socks.h
diff --git a/src/core/proto/proto_cell.c b/src/core/proto/proto_cell.c
index 697fed29e1..5c1a2c24d7 100644
--- a/src/core/proto/proto_cell.c
+++ b/src/core/proto/proto_cell.c
@@ -1,9 +1,16 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_cell.c
+ * @brief Decodes Tor cells from buffers.
+ **/
+/* Right now it only handles variable-length cells, but eventually
+ * we should refactor other cell-reading code into here. */
+
#include "core/or/or.h"
#include "lib/buf/buffers.h"
#include "core/proto/proto_cell.h"
@@ -83,4 +90,3 @@ fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto)
*out = result;
return 1;
}
-
diff --git a/src/core/proto/proto_cell.h b/src/core/proto/proto_cell.h
index 4f3982ea43..0e9cfbfed3 100644
--- a/src/core/proto/proto_cell.h
+++ b/src/core/proto/proto_cell.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_cell.h
+ * @brief Header for proto_cell.c
+ **/
+
#ifndef TOR_PROTO_CELL_H
#define TOR_PROTO_CELL_H
@@ -14,4 +19,3 @@ int fetch_var_cell_from_buf(struct buf_t *buf, struct var_cell_t **out,
int linkproto);
#endif /* !defined(TOR_PROTO_CELL_H) */
-
diff --git a/src/core/proto/proto_control0.c b/src/core/proto/proto_control0.c
index d741f28f09..323b37c539 100644
--- a/src/core/proto/proto_control0.c
+++ b/src/core/proto/proto_control0.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_control0.c
+ * @brief Code to detect the obsolete v0 control protocol.
+ **/
+
#include "core/or/or.h"
#include "lib/buf/buffers.h"
#include "core/proto/proto_control0.h"
@@ -23,4 +28,3 @@ peek_buf_has_control0_command(buf_t *buf)
}
return 0;
}
-
diff --git a/src/core/proto/proto_control0.h b/src/core/proto/proto_control0.h
index 162e513a1b..561bf00d19 100644
--- a/src/core/proto/proto_control0.h
+++ b/src/core/proto/proto_control0.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_control0.h
+ * @brief Header for proto_control0.c
+ **/
+
#ifndef TOR_PROTO_CONTROL0_H
#define TOR_PROTO_CONTROL0_H
@@ -11,4 +16,3 @@ struct buf_t;
int peek_buf_has_control0_command(struct buf_t *buf);
#endif /* !defined(TOR_PROTO_CONTROL0_H) */
-
diff --git a/src/core/proto/proto_ext_or.c b/src/core/proto/proto_ext_or.c
index 4213bc14dd..23fc2393b7 100644
--- a/src/core/proto/proto_ext_or.c
+++ b/src/core/proto/proto_ext_or.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_ext_or.c
+ * @brief Parsing/encoding for the extended OR protocol.
+ **/
+
#include "core/or/or.h"
#include "lib/buf/buffers.h"
#include "feature/relay/ext_orport.h"
@@ -37,4 +42,3 @@ fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out)
buf_get_bytes(buf, (*out)->body, len);
return 1;
}
-
diff --git a/src/core/proto/proto_ext_or.h b/src/core/proto/proto_ext_or.h
index b2bc64af85..3408599fb7 100644
--- a/src/core/proto/proto_ext_or.h
+++ b/src/core/proto/proto_ext_or.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_ext_or.h
+ * @brief Header for proto_ext_or.c
+ **/
+
#ifndef TOR_PROTO_EXT_OR_H
#define TOR_PROTO_EXT_OR_H
@@ -19,4 +24,11 @@ struct ext_or_cmd_t {
int fetch_ext_or_command_from_buf(struct buf_t *buf,
struct ext_or_cmd_t **out);
+ext_or_cmd_t *ext_or_cmd_new(uint16_t len);
+
+#define ext_or_cmd_free(cmd) \
+ FREE_AND_NULL(ext_or_cmd_t, ext_or_cmd_free_, (cmd))
+
+void ext_or_cmd_free_(ext_or_cmd_t *cmd);
+
#endif /* !defined(TOR_PROTO_EXT_OR_H) */
diff --git a/src/core/proto/proto_haproxy.c b/src/core/proto/proto_haproxy.c
new file mode 100644
index 0000000000..9129fc55bf
--- /dev/null
+++ b/src/core/proto/proto_haproxy.c
@@ -0,0 +1,45 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define PROTO_HAPROXY_PRIVATE
+#include "lib/malloc/malloc.h"
+#include "lib/net/address.h"
+#include "lib/string/printf.h"
+#include "core/proto/proto_haproxy.h"
+
+/** Return a newly allocated PROXY header null-terminated string. Returns NULL
+ * if addr_port->addr is incompatible with the proxy protocol.
+ */
+char *
+haproxy_format_proxy_header_line(const tor_addr_port_t *addr_port)
+{
+ tor_assert(addr_port);
+
+ sa_family_t family = tor_addr_family(&addr_port->addr);
+ const char *family_string = NULL;
+ const char *src_addr_string = NULL;
+
+ switch (family) {
+ case AF_INET:
+ family_string = "TCP4";
+ src_addr_string = "0.0.0.0";
+ break;
+ case AF_INET6:
+ family_string = "TCP6";
+ src_addr_string = "::";
+ break;
+ default:
+ /* Unknown family. */
+ return NULL;
+ }
+
+ char *buf;
+ char addrbuf[TOR_ADDR_BUF_LEN];
+
+ tor_addr_to_str(addrbuf, &addr_port->addr, sizeof(addrbuf), 0);
+
+ tor_asprintf(&buf, "PROXY %s %s %s 0 %d\r\n", family_string, src_addr_string,
+ addrbuf, addr_port->port);
+
+ return buf;
+}
diff --git a/src/core/proto/proto_haproxy.h b/src/core/proto/proto_haproxy.h
new file mode 100644
index 0000000000..63c164e1a1
--- /dev/null
+++ b/src/core/proto/proto_haproxy.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_PROTO_HAPROXY_H
+#define TOR_PROTO_HAPROXY_H
+
+struct tor_addr_port_t;
+
+char *haproxy_format_proxy_header_line(
+ const struct tor_addr_port_t *addr_port);
+
+#endif /* !defined(TOR_PROTO_HAPROXY_H) */
diff --git a/src/core/proto/proto_http.c b/src/core/proto/proto_http.c
index 88c59ef561..ef4b897fcc 100644
--- a/src/core/proto/proto_http.c
+++ b/src/core/proto/proto_http.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_http.c
+ * @brief Parse a subset of the HTTP protocol.
+ **/
+
#define PROTO_HTTP_PRIVATE
#include "core/or/or.h"
#include "lib/buf/buffers.h"
@@ -168,4 +173,3 @@ buf_http_find_content_length(const char *headers, size_t headerlen,
return ok ? 1 : -1;
}
-
diff --git a/src/core/proto/proto_http.h b/src/core/proto/proto_http.h
index cd70050205..e0c5135346 100644
--- a/src/core/proto/proto_http.h
+++ b/src/core/proto/proto_http.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_http.h
+ * @brief Header for proto_http.c
+ **/
+
#ifndef TOR_PROTO_HTTP_H
#define TOR_PROTO_HTTP_H
@@ -21,4 +26,3 @@ STATIC int buf_http_find_content_length(const char *headers, size_t headerlen,
#endif
#endif /* !defined(TOR_PROTO_HTTP_H) */
-
diff --git a/src/core/proto/proto_socks.c b/src/core/proto/proto_socks.c
index c06e6b1a41..198195c0ae 100644
--- a/src/core/proto/proto_socks.c
+++ b/src/core/proto/proto_socks.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_socks.c
+ * @brief Implementations for SOCKS4 and SOCKS5 protocols.
+ **/
+
#include "core/or/or.h"
#include "feature/client/addressmap.h"
#include "lib/buf/buffers.h"
@@ -105,7 +110,7 @@ socks_request_free_(socks_request_t *req)
/**
* Parse a single SOCKS4 request from buffer <b>raw_data</b> of length
* <b>datalen</b> and update relevant fields of <b>req</b>. If SOCKS4a
- * request is detected, set <b>*is_socks4a<b> to true. Set <b>*drain_out</b>
+ * request is detected, set <b>*is_socks4a</b> to true. Set <b>*drain_out</b>
* to number of bytes we parsed so far.
*
* Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
@@ -582,9 +587,8 @@ parse_socks5_client_request(const uint8_t *raw_data, socks_request_t *req,
strlcpy(req->address, hostname, sizeof(req->address));
} break;
case 4: {
- const char *ipv6 =
- (const char *)socks5_client_request_getarray_dest_addr_ipv6(
- trunnel_req);
+ const uint8_t *ipv6 =
+ socks5_client_request_getarray_dest_addr_ipv6(trunnel_req);
tor_addr_from_ipv6_bytes(&destaddr, ipv6);
tor_addr_to_str(req->address, &destaddr, sizeof(req->address), 1);
@@ -615,6 +619,7 @@ process_socks5_client_request(socks_request_t *req,
int safe_socks)
{
socks_result_t res = SOCKS_RESULT_DONE;
+ tor_addr_t tmpaddr;
if (req->command != SOCKS_COMMAND_CONNECT &&
req->command != SOCKS_COMMAND_RESOLVE &&
@@ -625,11 +630,10 @@ process_socks5_client_request(socks_request_t *req,
}
if (req->command == SOCKS_COMMAND_RESOLVE_PTR &&
- !string_is_valid_ipv4_address(req->address) &&
- !string_is_valid_ipv6_address(req->address)) {
+ tor_addr_parse(&tmpaddr, req->address) < 0) {
socks_request_set_socks5_error(req, SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
- "hostname type. Rejecting.");
+ "a malformed address. Rejecting.");
res = SOCKS_RESULT_INVALID;
goto end;
diff --git a/src/core/proto/proto_socks.h b/src/core/proto/proto_socks.h
index 2a387bf848..f3af0d988e 100644
--- a/src/core/proto/proto_socks.h
+++ b/src/core/proto/proto_socks.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file proto_socks.h
+ * @brief Header for proto_socks.c
+ **/
+
#ifndef TOR_PROTO_SOCKS_H
#define TOR_PROTO_SOCKS_H
diff --git a/src/core/stA1RajU b/src/core/stA1RajU
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/core/stA1RajU
diff --git a/src/core/stiysZND b/src/core/stiysZND
new file mode 100644
index 0000000000..faa365b769
--- /dev/null
+++ b/src/core/stiysZND
Binary files differ
diff --git a/src/ext/ed25519/ref10/base.py b/src/ext/ed25519/ref10/base.py
index 84accc8580..3d477c5c39 100644
--- a/src/ext/ed25519/ref10/base.py
+++ b/src/ext/ed25519/ref10/base.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
b = 256
q = 2**255 - 19
l = 2**252 + 27742317777372353535851937790883648493
@@ -51,15 +56,15 @@ def radix255(x):
Bi = B
for i in range(32):
- print "{"
+ print("{")
Bij = Bi
for j in range(8):
- print " {"
- print " {",radix255(Bij[1]+Bij[0]),"},"
- print " {",radix255(Bij[1]-Bij[0]),"},"
- print " {",radix255(2*d*Bij[0]*Bij[1]),"},"
+ print(" {")
+ print(" {",radix255(Bij[1]+Bij[0]),"},")
+ print(" {",radix255(Bij[1]-Bij[0]),"},")
+ print(" {",radix255(2*d*Bij[0]*Bij[1]),"},")
Bij = edwards(Bij,Bi)
- print " },"
- print "},"
+ print(" },")
+ print("},")
for k in range(8):
Bi = edwards(Bi,Bi)
diff --git a/src/ext/ed25519/ref10/base2.py b/src/ext/ed25519/ref10/base2.py
index 5e4e8739d0..3f8e3d25d2 100644
--- a/src/ext/ed25519/ref10/base2.py
+++ b/src/ext/ed25519/ref10/base2.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
b = 256
q = 2**255 - 19
l = 2**252 + 27742317777372353535851937790883648493
@@ -52,9 +57,9 @@ def radix255(x):
Bi = B
for i in range(8):
- print " {"
- print " {",radix255(Bi[1]+Bi[0]),"},"
- print " {",radix255(Bi[1]-Bi[0]),"},"
- print " {",radix255(2*d*Bi[0]*Bi[1]),"},"
- print " },"
+ print(" {")
+ print(" {",radix255(Bi[1]+Bi[0]),"},")
+ print(" {",radix255(Bi[1]-Bi[0]),"},")
+ print(" {",radix255(2*d*Bi[0]*Bi[1]),"},")
+ print(" },")
Bi = edwards(B,edwards(B,Bi))
diff --git a/src/ext/ed25519/ref10/d.py b/src/ext/ed25519/ref10/d.py
index 8995bb86a3..5b875de666 100644
--- a/src/ext/ed25519/ref10/d.py
+++ b/src/ext/ed25519/ref10/d.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
q = 2**255 - 19
def expmod(b,e,m):
@@ -25,4 +30,4 @@ def radix255(x):
return result
d = -121665 * inv(121666)
-print radix255(d)
+print(radix255(d))
diff --git a/src/ext/ed25519/ref10/d2.py b/src/ext/ed25519/ref10/d2.py
index 79841758be..f59a1bc62a 100644
--- a/src/ext/ed25519/ref10/d2.py
+++ b/src/ext/ed25519/ref10/d2.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
q = 2**255 - 19
def expmod(b,e,m):
@@ -25,4 +30,4 @@ def radix255(x):
return result
d = -121665 * inv(121666)
-print radix255(d*2)
+print(radix255(d*2))
diff --git a/src/ext/ed25519/ref10/sqrtm1.py b/src/ext/ed25519/ref10/sqrtm1.py
index 9a47fbc12a..df9f26ee1d 100644
--- a/src/ext/ed25519/ref10/sqrtm1.py
+++ b/src/ext/ed25519/ref10/sqrtm1.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
q = 2**255 - 19
def expmod(b,e,m):
@@ -25,4 +30,4 @@ def radix255(x):
return result
I = expmod(2,(q-1)/4,q)
-print radix255(I)
+print(radix255(I))
diff --git a/src/ext/ht.h b/src/ext/ht.h
index 54e5eb7cba..4bfce36903 100644
--- a/src/ext/ht.h
+++ b/src/ext/ht.h
@@ -226,11 +226,16 @@ ht_string_hash(const char *s)
(x) = HT_NEXT(name, head, x))
#ifndef HT_NDEBUG
-#define HT_ASSERT_(x) tor_assert(x)
+#include "lib/err/torerr.h"
+#define HT_ASSERT_(x) raw_assert(x)
#else
#define HT_ASSERT_(x) (void)0
#endif
+/* Macro put at the end of the end of a macro definition so that it
+ * consumes the following semicolon at file scope. Used only inside ht.h. */
+#define HT_EAT_SEMICOLON__ struct ht_semicolon_eater
+
#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \
int name##_HT_GROW(struct name *ht, unsigned min_capacity); \
void name##_HT_CLEAR(struct name *ht); \
@@ -370,7 +375,8 @@ ht_string_hash(const char *s)
/* Return the next element in 'head' after 'elm', under the arbitrary \
* order used by HT_START. If there are no more elements, return \
* NULL. If 'elm' is to be removed from the table, you must call \
- * this function for the next value before you remove it. \
+ * this function for the next value before you remove it, or use \
+ * HT_NEXT_RMV instead. \
*/ \
ATTR_UNUSED static inline struct type ** \
name##_HT_NEXT(struct name *head, struct type **elm) \
@@ -392,6 +398,8 @@ ht_string_hash(const char *s)
return NULL; \
} \
} \
+ /* As HT_NEXT, but also remove the current element 'elm' from the \
+ * table. */ \
ATTR_UNUSED static inline struct type ** \
name##_HT_NEXT_RMV(struct name *head, struct type **elm) \
{ \
@@ -409,7 +417,8 @@ ht_string_hash(const char *s)
} \
return NULL; \
} \
- }
+ } \
+ HT_EAT_SEMICOLON__
#define HT_GENERATE2(name, type, field, hashfn, eqfn, load, reallocarrayfn, \
freefn) \
@@ -534,7 +543,8 @@ ht_string_hash(const char *s)
if (n != head->hth_n_entries) \
return 6; \
return 0; \
- }
+ } \
+ HT_EAT_SEMICOLON__
#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \
reallocfn, freefn) \
@@ -617,4 +627,3 @@ ht_string_hash(const char *s)
*/
#endif
-
diff --git a/src/ext/siphash.h b/src/ext/siphash.h
index 730e49937d..0207a959ff 100644
--- a/src/ext/siphash.h
+++ b/src/ext/siphash.h
@@ -1,6 +1,8 @@
#ifndef SIPHASH_H
#define SIPHASH_H
+#include <stdint.h>
+
struct sipkey {
uint64_t k0;
uint64_t k1;
diff --git a/src/ext/timeouts/timeout.h b/src/ext/timeouts/timeout.h
index 1ed309fd08..f1028bfc80 100644
--- a/src/ext/timeouts/timeout.h
+++ b/src/ext/timeouts/timeout.h
@@ -89,10 +89,10 @@ typedef uint64_t timeout_t;
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef TIMEOUT_CB_OVERRIDE
-struct timeout_cb {
+struct timeout_cb_t {
void (*fn)(void);
void *arg;
-}; /* struct timeout_cb */
+}; /* struct timeout_cb_t */
#endif
/*
@@ -125,7 +125,7 @@ struct timeout {
/* entry member for struct timeout_list lists */
#ifndef TIMEOUT_DISABLE_CALLBACKS
- struct timeout_cb callback;
+ struct timeout_cb_t callback;
/* optional callback information */
#endif
diff --git a/src/ext/tinytest_macros.h b/src/ext/tinytest_macros.h
index c3728d1fdd..6fc2cea2da 100644
--- a/src/ext/tinytest_macros.h
+++ b/src/ext/tinytest_macros.h
@@ -99,11 +99,11 @@
/* Assert b, but do not stop the test if b fails. Log msg on failure. */
#define tt_want_msg(b, msg) \
- tt_want_(b, msg, );
+ tt_want_(b, msg, )
/* Assert b and stop the test if b fails. Log msg on failure. */
#define tt_assert_msg(b, msg) \
- tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
+ tt_want_(b, msg, TT_EXIT_TEST_FUNCTION)
/* Assert b, but do not stop the test if b fails. */
#define tt_want(b) tt_want_msg( (b), "want("#b")")
diff --git a/src/feature/api/.may_include b/src/feature/api/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/api/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/api/feature_api.md b/src/feature/api/feature_api.md
new file mode 100644
index 0000000000..3065c000aa
--- /dev/null
+++ b/src/feature/api/feature_api.md
@@ -0,0 +1,2 @@
+@dir /feature/api
+@brief feature/api: In-process interface to starting/stopping Tor.
diff --git a/src/feature/api/include.am b/src/feature/api/include.am
new file mode 100644
index 0000000000..8d490458d4
--- /dev/null
+++ b/src/feature/api/include.am
@@ -0,0 +1,11 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/api/tor_api.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/api/tor_api_internal.h
+
+# This may someday want to be an installed file?
+noinst_HEADERS += src/feature/api/tor_api.h
diff --git a/src/feature/api/tor_api.c b/src/feature/api/tor_api.c
index e270c51ac9..531793301e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/api/tor_api.h b/src/feature/api/tor_api.h
index cb84853a52..e9993bb0d5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 60e0f3aa59..d52b2caf44 100644
--- a/src/feature/api/tor_api_internal.h
+++ b/src/feature/api/tor_api_internal.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file tor_api_internal.h
+ * @brief Internal declarations for in-process Tor API.
+ **/
+
#ifndef TOR_API_INTERNAL_H
#define TOR_API_INTERNAL_H
diff --git a/src/feature/client/.may_include b/src/feature/client/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/client/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/client/addressmap.c b/src/feature/client/addressmap.c
index c5a27ce8c6..9ad2d7f934 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,7 +23,6 @@
#include "app/config/config.h"
#include "core/or/connection_edge.h"
#include "feature/control/control_events.h"
-#include "feature/relay/dns.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerset.h"
@@ -689,7 +688,7 @@ client_dns_set_addressmap_impl(entry_connection_t *for_conn,
if (ttl<0)
ttl = DEFAULT_DNS_TTL;
else
- ttl = dns_clip_ttl(ttl);
+ ttl = clip_dns_ttl(ttl);
if (exitname) {
/* XXXX fails to ever get attempts to get an exit address of
@@ -903,7 +902,7 @@ get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
}
if (ipv6)
- tor_addr_from_ipv6_bytes(addr_out, (char*) bytes);
+ tor_addr_from_ipv6_bytes(addr_out, bytes);
else
tor_addr_from_ipv4n(addr_out, get_uint32(bytes));
diff --git a/src/feature/client/addressmap.h b/src/feature/client/addressmap.h
index 9179aef1d0..7f1024e09a 100644
--- a/src/feature/client/addressmap.h
+++ b/src/feature/client/addressmap.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file addressmap.h
+ * @brief Header for addressmap.c
+ **/
+
#ifndef TOR_ADDRESSMAP_H
#define TOR_ADDRESSMAP_H
@@ -62,4 +67,3 @@ STATIC void get_random_virtual_addr(const virtual_addr_conf_t *conf,
#endif /* defined(ADDRESSMAP_PRIVATE) */
#endif /* !defined(TOR_ADDRESSMAP_H) */
-
diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c
index f517876609..66b04f3bc2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -844,8 +844,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
}
}
- if (options->ClientPreferIPv6ORPort == -1 ||
- options->ClientAutoIPv6ORPort == 0) {
+ if (options->ClientPreferIPv6ORPort == -1) {
/* Mark which address to use based on which bridge_t we got. */
node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 &&
!tor_addr_is_null(&node->ri->ipv6_addr));
diff --git a/src/feature/client/bridges.h b/src/feature/client/bridges.h
index 27b2750a45..174149cf97 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c
index 60a52664f1..74260171fe 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -826,6 +826,11 @@ pathbias_send_usable_probe(circuit_t *circ)
ocirc->pathbias_probe_nonce &= 0x00ffffff;
probe_nonce = tor_dup_ip(ocirc->pathbias_probe_nonce);
+ if (!probe_nonce) {
+ log_err(LD_BUG, "Failed to generate nonce");
+ return -1;
+ }
+
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:25", probe_nonce);
payload_len = (int)strlen(payload)+1;
diff --git a/src/feature/client/circpathbias.h b/src/feature/client/circpathbias.h
index a9a8d18df2..88cc982dd4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/dnsserv.c b/src/feature/client/dnsserv.c
index f9e436e88f..c1981ecde0 100644
--- a/src/feature/client/dnsserv.c
+++ b/src/feature/client/dnsserv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/dnsserv.h b/src/feature/client/dnsserv.h
index fff1ed2adb..4011cb4e02 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index 115d871843..223815e7b2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -47,8 +47,7 @@
* As a persistent ordered list whose elements are taken from the
* sampled set, we track a CONFIRMED GUARDS LIST. A guard becomes
* confirmed when we successfully build a circuit through it, and decide
- * to use that circuit. We order the guards on this list by the order
- * in which they became confirmed.
+ * to use that circuit.
*
* And as a final group, we have an ordered list of PRIMARY GUARDS,
* whose elements are taken from the filtered set. We prefer
@@ -59,7 +58,7 @@
*
* To build circuits, we take a primary guard if possible -- or a
* reachable filtered confirmed guard if no primary guard is possible --
- * or a random reachable filtered guard otherwise. If the guard is
+ * or the first (by sampled order) filtered guard otherwise. If the guard is
* primary, we can use the circuit immediately on success. Otherwise,
* the guard is now "pending" -- we won't use its circuit unless all
* of the circuits we're trying to build through better guards have
@@ -92,14 +91,18 @@
* [x] Whenever we remove a guard from the sample, remove it from the primary
* and confirmed lists.
*
- * [x] When we make a guard confirmed, update the primary list.
+ * [x] When we make a guard confirmed, update the primary list, and sort them
+ * by sampled order.
*
* [x] When we make a guard filtered or unfiltered, update the primary list.
*
* [x] When we are about to pick a guard, make sure that the primary list is
* full.
*
- * [x] Before calling sample_reachable_filtered_entry_guards(), make sure
+ * [x] When we update the confirmed list, or when we re-build the primary list
+ * and detect a change, we sort those lists by sampled_idx
+ *
+ * [x] Before calling first_reachable_filtered_entry_guard(), make sure
* that the filtered, primary, and confirmed flags are up-to-date.
*
* [x] Call entry_guard_consider_retry every time we are about to check
@@ -114,7 +117,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "app/config/statefile.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
@@ -172,6 +175,7 @@ static entry_guard_t *get_sampled_guard_by_bridge_addr(guard_selection_t *gs,
const tor_addr_port_t *addrport);
static int entry_guard_obeys_restriction(const entry_guard_t *guard,
const entry_guard_restriction_t *rst);
+static int compare_guards_by_sampled_idx(const void **a_, const void **b_);
/** Return 0 if we should apply guardfraction information found in the
* consensus. A specific consensus can be specified with the
@@ -890,6 +894,7 @@ entry_guard_add_to_sample_impl(guard_selection_t *gs,
tor_free(guard->sampled_by_version);
guard->sampled_by_version = tor_strdup(VERSION);
guard->currently_listed = 1;
+ guard->sampled_idx = gs->next_sampled_idx++;
guard->confirmed_idx = -1;
/* non-persistent fields */
@@ -901,6 +906,11 @@ entry_guard_add_to_sample_impl(guard_selection_t *gs,
guard->in_selection = gs;
entry_guard_set_filtered_flags(get_options(), gs, guard);
entry_guards_changed_for_guard_selection(gs);
+
+ /* Just added this guard to the sampled set and hence it might be used as a
+ * guard in the future: send GUARD NEW control event. */
+ control_event_guard(guard->nickname, guard->identity, "NEW");
+
return guard;
}
@@ -1038,7 +1048,7 @@ get_max_sample_size(guard_selection_t *gs,
* Return a smartlist of the all the guards that are not currently
* members of the sample (GUARDS - SAMPLED_GUARDS). The elements of
* this list are node_t pointers in the non-bridge case, and
- * bridge_info_t pointers in the bridge case. Set *<b>n_guards_out/b>
+ * bridge_info_t pointers in the bridge case. Set *<b>n_guards_out</b>
* to the number of guards that we found in GUARDS, including those
* that were already sampled.
*/
@@ -1383,7 +1393,7 @@ sampled_guards_prune_obsolete_entries(guard_selection_t *gs,
if (rmv) {
++n_changes;
- SMARTLIST_DEL_CURRENT(gs->sampled_entry_guards, guard);
+ SMARTLIST_DEL_CURRENT_KEEPORDER(gs->sampled_entry_guards, guard);
remove_guard_from_confirmed_and_primary_lists(gs, guard);
entry_guard_free(guard);
}
@@ -1707,7 +1717,7 @@ entry_guards_update_filtered_sets(guard_selection_t *gs)
}
/**
- * Return a random guard from the reachable filtered sample guards
+ * Return the first sampled guard from the reachable filtered sample guards
* in <b>gs</b>, subject to the exclusion rules listed in <b>flags</b>.
* Return NULL if no such guard can be found.
*
@@ -1718,7 +1728,7 @@ entry_guards_update_filtered_sets(guard_selection_t *gs)
* violate it.
**/
STATIC entry_guard_t *
-sample_reachable_filtered_entry_guards(guard_selection_t *gs,
+first_reachable_filtered_entry_guard(guard_selection_t *gs,
const entry_guard_restriction_t *rst,
unsigned flags)
{
@@ -1771,7 +1781,17 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
flags, smartlist_len(reachable_filtered_sample));
if (smartlist_len(reachable_filtered_sample)) {
- result = smartlist_choose(reachable_filtered_sample);
+ /**
+ * Get the first guard of the filtered set builds from
+ * sampled_entry_guards. Proposal 310 suggests this design to overcome
+ * performance and security issues linked to the previous selection
+ * method. The guard selected here should be filtered out if this function
+ * is called again in the same context. I.e., if we filter guards to add
+ * them into some list X, then the guards from list X will be filtered out
+ * when this function is called again. Hence it requires setting exclude
+ * flags in a appropriate way (depending of the context of the caller).
+ */
+ result = smartlist_get(reachable_filtered_sample, 0);
log_info(LD_GUARD, " (Selected %s.)",
result ? entry_guard_describe(result) : "<null>");
}
@@ -1780,10 +1800,6 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
return result;
}
-/**
- * Helper: compare two entry_guard_t by their confirmed_idx values.
- * Used to sort the confirmed list.
- */
static int
compare_guards_by_confirmed_idx(const void **a_, const void **b_)
{
@@ -1795,6 +1811,21 @@ compare_guards_by_confirmed_idx(const void **a_, const void **b_)
else
return 0;
}
+/**
+ * Helper: compare two entry_guard_t by their sampled_idx values.
+ * Used to sort the sampled list
+ */
+static int
+compare_guards_by_sampled_idx(const void **a_, const void **b_)
+{
+ const entry_guard_t *a = *a_, *b = *b_;
+ if (a->sampled_idx < b->sampled_idx)
+ return -1;
+ else if (a->sampled_idx > b->sampled_idx)
+ return 1;
+ else
+ return 0;
+}
/**
* Find the confirmed guards from among the sampled guards in <b>gs</b>,
@@ -1811,7 +1842,7 @@ entry_guards_update_confirmed(guard_selection_t *gs)
} SMARTLIST_FOREACH_END(guard);
smartlist_sort(gs->confirmed_entry_guards, compare_guards_by_confirmed_idx);
-
+ /** Needed to keep a dense array of confirmed_idx */
int any_changed = 0;
SMARTLIST_FOREACH_BEGIN(gs->confirmed_entry_guards, entry_guard_t *, guard) {
if (guard->confirmed_idx != guard_sl_idx) {
@@ -1821,6 +1852,8 @@ entry_guards_update_confirmed(guard_selection_t *gs)
} SMARTLIST_FOREACH_END(guard);
gs->next_confirmed_idx = smartlist_len(gs->confirmed_entry_guards);
+ // We need the confirmed list to always be give guards in sampled order
+ smartlist_sort(gs->confirmed_entry_guards, compare_guards_by_sampled_idx);
if (any_changed) {
entry_guards_changed_for_guard_selection(gs);
@@ -1849,6 +1882,9 @@ make_guard_confirmed(guard_selection_t *gs, entry_guard_t *guard)
guard->confirmed_idx = gs->next_confirmed_idx++;
smartlist_add(gs->confirmed_entry_guards, guard);
+ /** The confirmation ordering might not be the sample ording. We need to
+ * reorder */
+ smartlist_sort(gs->confirmed_entry_guards, compare_guards_by_sampled_idx);
// This confirmed guard might kick something else out of the primary
// guards.
@@ -1912,7 +1948,7 @@ entry_guards_update_primary(guard_selection_t *gs)
/* Finally, fill out the list with sampled guards. */
while (smartlist_len(new_primary_guards) < N_PRIMARY_GUARDS) {
- entry_guard_t *guard = sample_reachable_filtered_entry_guards(gs, NULL,
+ entry_guard_t *guard = first_reachable_filtered_entry_guard(gs, NULL,
SAMPLE_EXCLUDE_CONFIRMED|
SAMPLE_EXCLUDE_PRIMARY|
SAMPLE_NO_UPDATE_PRIMARY);
@@ -1943,6 +1979,7 @@ entry_guards_update_primary(guard_selection_t *gs)
g->confirmed_idx >= 0 ? " (confirmed)" : "",
g->is_filtered_guard ? "" : " (excluded by filter)");
} SMARTLIST_FOREACH_END(g);
+ smartlist_sort(new_primary_guards, compare_guards_by_sampled_idx);
}
smartlist_free(old_primary_guards);
@@ -1974,10 +2011,12 @@ get_retry_schedule(time_t failing_since, time_t now,
const struct {
time_t maximum; int primary_delay; int nonprimary_delay;
} delays[] = {
+ // clang-format off
{ SIX_HOURS, 10*60, 1*60*60 },
{ FOUR_DAYS, 90*60, 4*60*60 },
{ SEVEN_DAYS, 4*60*60, 18*60*60 },
{ TIME_MAX, 9*60*60, 36*60*60 }
+ // clang-format on
};
unsigned i;
@@ -2053,10 +2092,15 @@ select_primary_guard_for_circuit(guard_selection_t *gs,
SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) {
entry_guard_consider_retry(guard);
- if (! entry_guard_obeys_restriction(guard, rst))
+ if (!entry_guard_obeys_restriction(guard, rst)) {
+ log_info(LD_GUARD, "Entry guard %s doesn't obey restriction, we test the"
+ " next one", entry_guard_describe(guard));
continue;
+ }
if (guard->is_reachable != GUARD_REACHABLE_NO) {
if (need_descriptor && !guard_has_descriptor(guard)) {
+ log_info(LD_GUARD, "Guard %s does not have a descriptor",
+ entry_guard_describe(guard));
continue;
}
*state_out = GUARD_CIRC_STATE_USABLE_ON_COMPLETION;
@@ -2069,9 +2113,11 @@ select_primary_guard_for_circuit(guard_selection_t *gs,
if (smartlist_len(usable_primary_guards)) {
chosen_guard = smartlist_choose(usable_primary_guards);
+ log_info(LD_GUARD,
+ "Selected primary guard %s for circuit from a list size of %d.",
+ entry_guard_describe(chosen_guard),
+ smartlist_len(usable_primary_guards));
smartlist_free(usable_primary_guards);
- log_info(LD_GUARD, "Selected primary guard %s for circuit.",
- entry_guard_describe(chosen_guard));
}
smartlist_free(usable_primary_guards);
@@ -2116,10 +2162,10 @@ select_confirmed_guard_for_circuit(guard_selection_t *gs,
}
/**
- * For use with a circuit, pick a confirmed usable filtered guard
- * at random. Update the <b>last_tried_to_connect</b> time and the
- * <b>is_pending</b> fields of the guard as appropriate. Set <b>state_out</b>
- * to the new guard-state of the circuit.
+ * For use with a circuit, pick a usable filtered guard. Update the
+ * <b>last_tried_to_connect</b> time and the <b>is_pending</b> fields of the
+ * guard as appropriate. Set <b>state_out</b> to the new guard-state of the
+ * circuit.
*/
static entry_guard_t *
select_filtered_guard_for_circuit(guard_selection_t *gs,
@@ -2132,7 +2178,7 @@ select_filtered_guard_for_circuit(guard_selection_t *gs,
unsigned flags = 0;
if (need_descriptor)
flags |= SAMPLE_EXCLUDE_NO_DESCRIPTOR;
- chosen_guard = sample_reachable_filtered_entry_guards(gs,
+ chosen_guard = first_reachable_filtered_entry_guard(gs,
rst,
SAMPLE_EXCLUDE_CONFIRMED |
SAMPLE_EXCLUDE_PRIMARY |
@@ -2146,7 +2192,7 @@ select_filtered_guard_for_circuit(guard_selection_t *gs,
chosen_guard->last_tried_to_connect = approx_time();
*state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD;
log_info(LD_GUARD, "No primary or confirmed guards available. Selected "
- "random guard %s for circuit. Will try other guards before "
+ "guard %s for circuit. Will try other guards before "
"using this circuit.",
entry_guard_describe(chosen_guard));
return chosen_guard;
@@ -2187,8 +2233,8 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
if (chosen_guard)
return chosen_guard;
- /* "Otherwise, if there is no such entry, select a member at
- random from {USABLE_FILTERED_GUARDS}." */
+ /* "Otherwise, if there is no such entry, select a member
+ * {USABLE_FILTERED_GUARDS} following the sample ordering" */
chosen_guard = select_filtered_guard_for_circuit(gs, usage, rst, state_out);
if (chosen_guard == NULL) {
@@ -2218,6 +2264,9 @@ entry_guards_note_guard_failure(guard_selection_t *gs,
if (guard->failing_since == 0)
guard->failing_since = approx_time();
+ /* This guard not reachable: send GUARD DOWN event */
+ control_event_guard(guard->nickname, guard->identity, "DOWN");
+
log_info(LD_GUARD, "Recorded failure for %s%sguard %s",
guard->is_primary?"primary ":"",
guard->confirmed_idx>=0?"confirmed ":"",
@@ -2243,6 +2292,11 @@ entry_guards_note_guard_success(guard_selection_t *gs,
const time_t last_time_on_internet = gs->last_time_on_internet;
gs->last_time_on_internet = approx_time();
+ /* 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");
+ }
+
guard->is_reachable = GUARD_REACHABLE_YES;
guard->failing_since = 0;
guard->is_pending = 0;
@@ -2771,10 +2825,12 @@ entry_guards_update_all(guard_selection_t *gs)
/**
* Return a newly allocated string for encoding the persistent parts of
- * <b>guard</b> to the state file.
+ * <b>guard</b> to the state file. <b>dense_sampled_idx</b> refers to the
+ * sampled_idx made dense for this <b>guard</b>. Encoding all guards should
+ * lead to a dense array of sampled_idx in the state file.
*/
STATIC char *
-entry_guard_encode_for_state(entry_guard_t *guard)
+entry_guard_encode_for_state(entry_guard_t *guard, int dense_sampled_idx)
{
/*
* The meta-format we use is K=V K=V K=V... where K can be any
@@ -2803,7 +2859,8 @@ entry_guard_encode_for_state(entry_guard_t *guard)
format_iso_time_nospace(tbuf, guard->sampled_on_date);
smartlist_add_asprintf(result, "sampled_on=%s", tbuf);
-
+ // Replacing the sampled_idx by dense array
+ smartlist_add_asprintf(result, "sampled_idx=%d", dense_sampled_idx);
if (guard->sampled_by_version) {
smartlist_add_asprintf(result, "sampled_by=%s",
guard->sampled_by_version);
@@ -2859,6 +2916,78 @@ entry_guard_encode_for_state(entry_guard_t *guard)
}
/**
+ * Extract key=val from the state string <b>s</b> and duplicate the value to
+ * some string target declared in entry_guard_parse_from_state
+ */
+static void
+parse_from_state_set_vals(const char *s, smartlist_t *entries, smartlist_t
+ *extra, strmap_t *vals)
+{
+ smartlist_split_string(entries, s, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+
+ SMARTLIST_FOREACH_BEGIN(entries, char *, entry) {
+ const char *eq = strchr(entry, '=');
+ if (!eq) {
+ smartlist_add(extra, entry);
+ continue;
+ }
+ char *key = tor_strndup(entry, eq-entry);
+ char **target = strmap_get(vals, key);
+ if (target == NULL || *target != NULL) {
+ /* unrecognized or already set */
+ smartlist_add(extra, entry);
+ tor_free(key);
+ continue;
+ }
+
+ *target = tor_strdup(eq+1);
+ tor_free(key);
+ tor_free(entry);
+ } SMARTLIST_FOREACH_END(entry);
+}
+
+/**
+ * Handle part of the parsing state file logic, focused on time related things
+ */
+static void
+parse_from_state_handle_time(entry_guard_t *guard, char *sampled_on, char
+ *unlisted_since, char *confirmed_on)
+{
+#define HANDLE_TIME(field) do { \
+ if (field) { \
+ int r = parse_iso_time_nospace(field, &field ## _time); \
+ if (r < 0) { \
+ log_warn(LD_CIRC, "Unable to parse %s %s from guard", \
+ #field, escaped(field)); \
+ field##_time = -1; \
+ } \
+ } \
+ } while (0)
+
+ time_t sampled_on_time = 0;
+ time_t unlisted_since_time = 0;
+ time_t confirmed_on_time = 0;
+
+ HANDLE_TIME(sampled_on);
+ HANDLE_TIME(unlisted_since);
+ HANDLE_TIME(confirmed_on);
+
+ if (sampled_on_time <= 0)
+ sampled_on_time = approx_time();
+ if (unlisted_since_time < 0)
+ unlisted_since_time = 0;
+ if (confirmed_on_time < 0)
+ confirmed_on_time = 0;
+
+ #undef HANDLE_TIME
+
+ guard->sampled_on_date = sampled_on_time;
+ guard->unlisted_since_date = unlisted_since_time;
+ guard->confirmed_on_date = confirmed_on_time;
+}
+
+/**
* Given a string generated by entry_guard_encode_for_state(), parse it
* (if possible) and return an entry_guard_t object for it. Return NULL
* on complete failure.
@@ -2874,6 +3003,7 @@ entry_guard_parse_from_state(const char *s)
char *rsa_id = NULL;
char *nickname = NULL;
char *sampled_on = NULL;
+ char *sampled_idx = NULL;
char *sampled_by = NULL;
char *unlisted_since = NULL;
char *listed = NULL;
@@ -2890,6 +3020,7 @@ entry_guard_parse_from_state(const char *s)
char *pb_collapsed_circuits = NULL;
char *pb_unusable_circuits = NULL;
char *pb_timeouts = NULL;
+ int invalid_sampled_idx = get_max_sample_size_absolute();
/* Split up the entries. Put the ones we know about in strings and the
* rest in "extra". */
@@ -2903,6 +3034,7 @@ entry_guard_parse_from_state(const char *s)
FIELD(rsa_id);
FIELD(nickname);
FIELD(sampled_on);
+ FIELD(sampled_idx);
FIELD(sampled_by);
FIELD(unlisted_since);
FIELD(listed);
@@ -2918,29 +3050,8 @@ entry_guard_parse_from_state(const char *s)
FIELD(pb_unusable_circuits);
FIELD(pb_timeouts);
#undef FIELD
-
- smartlist_split_string(entries, s, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
-
- SMARTLIST_FOREACH_BEGIN(entries, char *, entry) {
- const char *eq = strchr(entry, '=');
- if (!eq) {
- smartlist_add(extra, entry);
- continue;
- }
- char *key = tor_strndup(entry, eq-entry);
- char **target = strmap_get(vals, key);
- if (target == NULL || *target != NULL) {
- /* unrecognized or already set */
- smartlist_add(extra, entry);
- tor_free(key);
- continue;
- }
-
- *target = tor_strdup(eq+1);
- tor_free(key);
- tor_free(entry);
- } SMARTLIST_FOREACH_END(entry);
+ /* Extract from s the key=val that we recognize, put the others in extra*/
+ parse_from_state_set_vals(s, entries, extra, vals);
smartlist_free(entries);
strmap_free(vals, NULL);
@@ -2988,43 +3099,12 @@ entry_guard_parse_from_state(const char *s)
}
/* Process the various time fields. */
-
-#define HANDLE_TIME(field) do { \
- if (field) { \
- int r = parse_iso_time_nospace(field, &field ## _time); \
- if (r < 0) { \
- log_warn(LD_CIRC, "Unable to parse %s %s from guard", \
- #field, escaped(field)); \
- field##_time = -1; \
- } \
- } \
- } while (0)
-
- time_t sampled_on_time = 0;
- time_t unlisted_since_time = 0;
- time_t confirmed_on_time = 0;
-
- HANDLE_TIME(sampled_on);
- HANDLE_TIME(unlisted_since);
- HANDLE_TIME(confirmed_on);
-
- if (sampled_on_time <= 0)
- sampled_on_time = approx_time();
- if (unlisted_since_time < 0)
- unlisted_since_time = 0;
- if (confirmed_on_time < 0)
- confirmed_on_time = 0;
-
- #undef HANDLE_TIME
-
- guard->sampled_on_date = sampled_on_time;
- guard->unlisted_since_date = unlisted_since_time;
- guard->confirmed_on_date = confirmed_on_time;
+ parse_from_state_handle_time(guard, sampled_on, unlisted_since,
+ confirmed_on);
/* Take sampled_by_version verbatim. */
guard->sampled_by_version = sampled_by;
sampled_by = NULL; /* prevent free */
-
/* Listed is a boolean */
if (listed && strcmp(listed, "0"))
guard->currently_listed = 1;
@@ -3042,6 +3122,29 @@ entry_guard_parse_from_state(const char *s)
}
}
+ if (sampled_idx) {
+ int ok = 1;
+ long idx = tor_parse_long(sampled_idx, 10, 0, INT_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_GUARD, "Guard has invalid sampled_idx %s",
+ escaped(sampled_idx));
+ /* set it to a idx higher than the max sample size */
+ guard->sampled_idx = invalid_sampled_idx++;
+ } else {
+ guard->sampled_idx = (int)idx;
+ }
+ } else if (confirmed_idx) {
+ /* This state has been written by an older Tor version which did not have
+ * sample ordering */
+
+ guard->sampled_idx = guard->confirmed_idx;
+ } else {
+ log_warn(LD_GUARD, "The state file seems to be into a status that could"
+ " yield to weird entry node selection: we're missing both a"
+ " sampled_idx and a confirmed_idx.");
+ guard->sampled_idx = invalid_sampled_idx++;
+ }
+
/* Anything we didn't recognize gets crammed together */
if (smartlist_len(extra) > 0) {
guard->extra_state_fields = smartlist_join_strings(extra, " ", 0, NULL);
@@ -3096,6 +3199,7 @@ entry_guard_parse_from_state(const char *s)
tor_free(listed);
tor_free(confirmed_on);
tor_free(confirmed_idx);
+ tor_free(sampled_idx);
tor_free(bridge_addr);
tor_free(pb_use_attempts);
tor_free(pb_use_successes);
@@ -3125,13 +3229,15 @@ entry_guards_update_guards_in_state(or_state_t *state)
config_line_t **nextline = &lines;
SMARTLIST_FOREACH_BEGIN(guard_contexts, guard_selection_t *, gs) {
+ int i = 0;
SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
if (guard->is_persistent == 0)
continue;
*nextline = tor_malloc_zero(sizeof(config_line_t));
(*nextline)->key = tor_strdup("Guard");
- (*nextline)->value = entry_guard_encode_for_state(guard);
+ (*nextline)->value = entry_guard_encode_for_state(guard, i);
nextline = &(*nextline)->next;
+ i++;
} SMARTLIST_FOREACH_END(guard);
} SMARTLIST_FOREACH_END(gs);
@@ -3184,6 +3290,14 @@ entry_guards_load_guards_from_state(or_state_t *state, int set)
tor_assert(gs);
smartlist_add(gs->sampled_entry_guards, guard);
guard->in_selection = gs;
+ /* Recompute the next_sampled_id from the state. We do not assume that
+ * sampled guards appear in the correct order within the file, and we
+ * need to know what would be the next sampled idx to give to any
+ * new sampled guard (i.e., max of guard->sampled_idx + 1)*/
+ if (gs->next_sampled_idx <= guard->sampled_idx) {
+ gs->next_sampled_idx = guard->sampled_idx + 1;
+ }
+
} else {
entry_guard_free(guard);
}
@@ -3191,6 +3305,10 @@ entry_guards_load_guards_from_state(or_state_t *state, int set)
if (set) {
SMARTLIST_FOREACH_BEGIN(guard_contexts, guard_selection_t *, gs) {
+ /** Guards should be in sample order within the file, but it is maybe
+ * better NOT to assume that. Let's order them before updating lists
+ */
+ smartlist_sort(gs->sampled_entry_guards, compare_guards_by_sampled_idx);
entry_guards_update_all(gs);
} SMARTLIST_FOREACH_END(gs);
}
diff --git a/src/feature/client/entrynodes.h b/src/feature/client/entrynodes.h
index 4e5eb4e960..4b236dc80c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,7 +15,7 @@
#include "lib/container/handles.h"
/* Forward declare for guard_selection_t; entrynodes.c has the real struct */
-typedef struct guard_selection_s guard_selection_t;
+typedef struct guard_selection_t guard_selection_t;
/* Forward declare for entry_guard_t; the real declaration is private. */
typedef struct entry_guard_t entry_guard_t;
@@ -28,7 +28,7 @@ typedef struct circuit_guard_state_t circuit_guard_state_t;
private. */
typedef struct entry_guard_restriction_t entry_guard_restriction_t;
-/* Information about a guard's pathbias status.
+/** Information about a guard's pathbias status.
* These fields are used in circpathbias.c to try to detect entry
* nodes that are failing circuits at a suspicious frequency.
*/
@@ -117,6 +117,13 @@ struct entry_guard_t {
* confirmed guard. */
time_t confirmed_on_date; /* 0 if not confirmed */
/**
+ * In what order was this guard sampled? Guards with
+ * lower indices appear earlier on the sampled list, the confirmed list and
+ * the primary list as a result of Prop 310
+ */
+ int sampled_idx;
+
+ /**
* In what order was this guard confirmed? Guards with lower indices
* appear earlier on the confirmed list. If the confirmed list is compacted,
* this field corresponds to the index of this guard on the confirmed list.
@@ -210,7 +217,7 @@ typedef enum guard_selection_type_t {
* See the module documentation for entrynodes.c for more information
* about guard selection algorithms.
*/
-struct guard_selection_s {
+struct guard_selection_t {
/**
* The name for this guard-selection object. (Must not contain spaces).
*/
@@ -242,8 +249,9 @@ struct guard_selection_s {
* Ordered list (from highest to lowest priority) of guards that we
* have successfully contacted and decided to use. Every member of
* this list is a member of sampled_entry_guards. Every member should
- * have confirmed_on_date set, and have confirmed_idx greater than
- * any earlier member of the list.
+ * have confirmed_on_date set.
+ * The ordering of the list should be by sampled idx. The reasoning behind
+ * it is linked to Proposal 310.
*
* This list is persistent. It is a subset of the elements in
* sampled_entry_guards, and its pointers point to elements of
@@ -271,6 +279,12 @@ struct guard_selection_s {
* confirmed_entry_guards receive? */
int next_confirmed_idx;
+ /** What sampled_idx value should the next-added member of
+ * sampled_entry_guards receive? This should follow the size of the sampled
+ * list until sampled relays get pruned for some reason
+ */
+ int next_sampled_idx;
+
};
struct entry_guard_handle_t;
@@ -515,7 +529,8 @@ MOCK_DECL(STATIC circuit_guard_state_t *,
STATIC entry_guard_t *entry_guard_add_to_sample(guard_selection_t *gs,
const node_t *node);
STATIC entry_guard_t *entry_guards_expand_sample(guard_selection_t *gs);
-STATIC char *entry_guard_encode_for_state(entry_guard_t *guard);
+STATIC char *entry_guard_encode_for_state(entry_guard_t *guard, int
+ dense_sampled_index);
STATIC entry_guard_t *entry_guard_parse_from_state(const char *s);
#define entry_guard_free(e) \
FREE_AND_NULL(entry_guard_t, entry_guard_free_, (e))
@@ -523,7 +538,7 @@ STATIC void entry_guard_free_(entry_guard_t *e);
STATIC void entry_guards_update_filtered_sets(guard_selection_t *gs);
STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
/**
- * @name Flags for sample_reachable_filtered_entry_guards()
+ * @name Flags for first_reachable_filtered_entry_guard()
*/
/**@{*/
#define SAMPLE_EXCLUDE_CONFIRMED (1u<<0)
@@ -532,7 +547,7 @@ STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
#define SAMPLE_NO_UPDATE_PRIMARY (1u<<3)
#define SAMPLE_EXCLUDE_NO_DESCRIPTOR (1u<<4)
/**@}*/
-STATIC entry_guard_t *sample_reachable_filtered_entry_guards(
+STATIC entry_guard_t *first_reachable_filtered_entry_guard(
guard_selection_t *gs,
const entry_guard_restriction_t *rst,
unsigned flags);
diff --git a/src/feature/client/feature_client.md b/src/feature/client/feature_client.md
new file mode 100644
index 0000000000..dd4bf78ec8
--- /dev/null
+++ b/src/feature/client/feature_client.md
@@ -0,0 +1,5 @@
+@dir /feature/client
+@brief feature/client: Client-specific code
+
+(There is also a bunch of client-specific code in other modules.)
+
diff --git a/src/feature/client/include.am b/src/feature/client/include.am
new file mode 100644
index 0000000000..53c9f047d4
--- /dev/null
+++ b/src/feature/client/include.am
@@ -0,0 +1,20 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/client/addressmap.c \
+ src/feature/client/bridges.c \
+ src/feature/client/circpathbias.c \
+ src/feature/client/dnsserv.c \
+ src/feature/client/entrynodes.c \
+ src/feature/client/proxymode.c \
+ src/feature/client/transports.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/client/addressmap.h \
+ src/feature/client/bridges.h \
+ src/feature/client/circpathbias.h \
+ src/feature/client/dnsserv.h \
+ src/feature/client/entrynodes.h \
+ src/feature/client/proxymode.h \
+ src/feature/client/transports.h
diff --git a/src/feature/client/proxymode.c b/src/feature/client/proxymode.c
new file mode 100644
index 0000000000..aa269ec7fb
--- /dev/null
+++ b/src/feature/client/proxymode.c
@@ -0,0 +1,32 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file proxymode.c
+ * @brief Determine whether we are trying to be a proxy.
+ **/
+
+#include "core/or/or.h"
+
+#include "app/config/config.h"
+#include "core/mainloop/connection.h"
+#include "core/or/port_cfg_st.h"
+#include "feature/client/proxymode.h"
+
+/** Return true iff we are trying to proxy client connections. */
+int
+proxy_mode(const or_options_t *options)
+{
+ (void)options;
+ SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
+ if (p->type == CONN_TYPE_AP_LISTENER ||
+ p->type == CONN_TYPE_AP_TRANS_LISTENER ||
+ p->type == CONN_TYPE_AP_DNS_LISTENER ||
+ p->type == CONN_TYPE_AP_NATD_LISTENER)
+ return 1;
+ } SMARTLIST_FOREACH_END(p);
+ return 0;
+}
diff --git a/src/feature/client/proxymode.h b/src/feature/client/proxymode.h
new file mode 100644
index 0000000000..30be08ff78
--- /dev/null
+++ b/src/feature/client/proxymode.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file proxymode.h
+ * \brief Header file for proxymode.c.
+ **/
+
+#ifndef TOR_PROXYMODE_H
+#define TOR_PROXYMODE_H
+
+int proxy_mode(const or_options_t *options);
+
+#endif /* !defined(TOR_PROXYMODE_H) */
diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c
index 3f731ac7d4..2bdc0ae151 100644
--- a/src/feature/client/transports.c
+++ b/src/feature/client/transports.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2019, The Tor Project, Inc. */
+/* Copyright (c) 2011-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -97,6 +97,9 @@
#include "core/or/circuitbuild.h"
#include "feature/client/transports.h"
#include "feature/relay/router.h"
+#include "feature/relay/relay_find_addr.h"
+/* 31851: split the server transport code out of the client module */
+#include "feature/relay/transport_config.h"
#include "app/config/statefile.h"
#include "core/or/connection_or.h"
#include "feature/relay/ext_orport.h"
@@ -733,6 +736,9 @@ get_pt_proxy_uri(void)
const or_options_t *options = get_options();
char *uri = NULL;
+ /* XXX: Currently TCPProxy is not supported in TOR_PT_PROXY because
+ * there isn't a standard URI scheme for some proxy protocols, such as
+ * haproxy. */
if (options->Socks4Proxy || options->Socks5Proxy || options->HTTPSProxy) {
char addr[TOR_ADDR_BUF_LEN+1];
@@ -1279,7 +1285,7 @@ get_transport_options_for_server_proxy(const managed_proxy_t *mp)
string. */
SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, const char *, transport) {
smartlist_t *options_tmp_sl = NULL;
- options_tmp_sl = get_options_for_server_transport(transport);
+ options_tmp_sl = pt_get_options_for_server_transport(transport);
if (!options_tmp_sl)
continue;
@@ -1415,8 +1421,10 @@ create_managed_proxy_environment(const managed_proxy_t *mp)
smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=%s",
ext_or_addrport_tmp);
}
- smartlist_add_asprintf(envs, "TOR_PT_AUTH_COOKIE_FILE=%s",
- cookie_file_loc);
+ if (cookie_file_loc) {
+ smartlist_add_asprintf(envs, "TOR_PT_AUTH_COOKIE_FILE=%s",
+ cookie_file_loc);
+ }
tor_free(ext_or_addrport_tmp);
tor_free(cookie_file_loc);
@@ -1853,7 +1861,9 @@ managed_proxy_stderr_callback(process_t *process,
if (BUG(mp == NULL))
return;
- log_warn(LD_PT, "Managed proxy at '%s' reported: %s", mp->argv[0], line);
+ log_info(LD_PT,
+ "Managed proxy at '%s' reported via standard error: %s",
+ mp->argv[0], line);
}
/** Callback function that is called when our PT process terminates. The
diff --git a/src/feature/client/transports.h b/src/feature/client/transports.h
index 900dd9288e..1ed942c175 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/.may_include b/src/feature/control/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/control/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/control/btrack.c b/src/feature/control/btrack.c
index 3ce97dc855..405630ecd4 100644
--- a/src/feature/control/btrack.c
+++ b/src/feature/control/btrack.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -56,8 +56,9 @@ btrack_add_pubsub(pubsub_connector_t *connector)
const subsys_fns_t sys_btrack = {
.name = "btrack",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
- .level = -30,
+ .level = 55,
.initialize = btrack_init,
.shutdown = btrack_fini,
.add_pubsub = btrack_add_pubsub,
diff --git a/src/feature/control/btrack_circuit.c b/src/feature/control/btrack_circuit.c
index 2980c77ddc..be51b51046 100644
--- a/src/feature/control/btrack_circuit.c
+++ b/src/feature/control/btrack_circuit.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, 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 b326c22ccf..75699450c3 100644
--- a/src/feature/control/btrack_circuit.h
+++ b/src/feature/control/btrack_circuit.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, 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 922b542a0c..104c8af230 100644
--- a/src/feature/control/btrack_orconn.c
+++ b/src/feature/control/btrack_orconn.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, 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 07b1b755f3..8b3d8be37d 100644
--- a/src/feature/control/btrack_orconn.h
+++ b/src/feature/control/btrack_orconn.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, 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 a00eb042d5..d11be59280 100644
--- a/src/feature/control/btrack_orconn_cevent.c
+++ b/src/feature/control/btrack_orconn_cevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -45,6 +45,7 @@ using_proxy(const bt_orconn_t *bto)
case PROXY_CONNECT:
case PROXY_SOCKS4:
case PROXY_SOCKS5:
+ case PROXY_HAPROXY:
return true;
default:
return false;
diff --git a/src/feature/control/btrack_orconn_cevent.h b/src/feature/control/btrack_orconn_cevent.h
index afec55581e..8b2207721e 100644
--- a/src/feature/control/btrack_orconn_cevent.h
+++ b/src/feature/control/btrack_orconn_cevent.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, 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 e64bd3f0fe..a60dffb8c4 100644
--- a/src/feature/control/btrack_orconn_maps.c
+++ b/src/feature/control/btrack_orconn_maps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -47,17 +47,18 @@ bto_chan_eq_(bt_orconn_t *a, bt_orconn_t *b)
}
HT_HEAD(bto_gid_ht, bt_orconn_t);
-HT_PROTOTYPE(bto_gid_ht, bt_orconn_t, node, bto_gid_hash_, bto_gid_eq_)
+HT_PROTOTYPE(bto_gid_ht, bt_orconn_t, node, bto_gid_hash_, bto_gid_eq_);
HT_GENERATE2(bto_gid_ht, bt_orconn_t, node,
bto_gid_hash_, bto_gid_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
static struct bto_gid_ht *bto_gid_map;
HT_HEAD(bto_chan_ht, bt_orconn_t);
-HT_PROTOTYPE(bto_chan_ht, bt_orconn_t, chan_node, bto_chan_hash_, bto_chan_eq_)
+HT_PROTOTYPE(bto_chan_ht, bt_orconn_t, chan_node, bto_chan_hash_,
+ bto_chan_eq_);
HT_GENERATE2(bto_chan_ht, bt_orconn_t, chan_node,
bto_chan_hash_, bto_chan_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
static struct bto_chan_ht *bto_chan_map;
/** Clear the GID hash map, freeing any bt_orconn_t objects that become
diff --git a/src/feature/control/btrack_orconn_maps.h b/src/feature/control/btrack_orconn_maps.h
index c2043fa153..c83b22b1e8 100644
--- a/src/feature/control/btrack_orconn_maps.h
+++ b/src/feature/control/btrack_orconn_maps.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, 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 3f831d0640..5a157b7b54 100644
--- a/src/feature/control/btrack_sys.h
+++ b/src/feature/control/btrack_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control.c b/src/feature/control/control.c
index ece5616907..ee1026359d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control.h b/src/feature/control/control.h
index 8d3595d2ed..7e72b2736b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 a574d07b33..b60623ab5c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 246e18ccbc..d4c1dd78a7 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 098e24682e..fee7612ba2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -171,6 +171,12 @@ control_event_bootstrap_core(int loglevel, bootstrap_status_t status,
control_event_client_status(LOG_NOTICE, "%s", buf);
}
+int
+control_get_bootstrap_percent(void)
+{
+ return bootstrap_percent;
+}
+
/** Called when Tor has made progress at bootstrapping its directory
* information and initial circuits.
*
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index 68d05abb73..d9a38011de 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,7 +13,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "app/main/main.h"
#include "core/mainloop/connection.h"
#include "core/or/circuitbuild.h"
@@ -26,6 +26,7 @@
#include "feature/control/control.h"
#include "feature/control/control_auth.h"
#include "feature/control/control_cmd.h"
+#include "feature/control/control_hs.h"
#include "feature/control/control_events.h"
#include "feature/control/control_getinfo.h"
#include "feature/control/control_proto.h"
@@ -288,26 +289,23 @@ handle_control_getconf(control_connection_t *conn,
const smartlist_t *questions = args->args;
smartlist_t *answers = smartlist_new();
smartlist_t *unrecognized = smartlist_new();
- char *msg = NULL;
- size_t msg_len;
const or_options_t *options = get_options();
- int i, len;
SMARTLIST_FOREACH_BEGIN(questions, const char *, q) {
if (!option_is_recognized(q)) {
- smartlist_add(unrecognized, (char*) q);
+ control_reply_add_printf(unrecognized, 552,
+ "Unrecognized configuration key \"%s\"", q);
} else {
config_line_t *answer = option_get_assignment(options,q);
if (!answer) {
const char *name = option_get_canonical_name(q);
- smartlist_add_asprintf(answers, "250-%s\r\n", name);
+ control_reply_add_one_kv(answers, 250, KV_OMIT_VALS, name, "");
}
while (answer) {
config_line_t *next;
- smartlist_add_asprintf(answers, "250-%s=%s\r\n",
- answer->key, answer->value);
-
+ control_reply_add_one_kv(answers, 250, KV_RAW, answer->key,
+ answer->value);
next = answer->next;
tor_free(answer->key);
tor_free(answer->value);
@@ -317,30 +315,16 @@ handle_control_getconf(control_connection_t *conn,
}
} SMARTLIST_FOREACH_END(q);
- if ((len = smartlist_len(unrecognized))) {
- for (i=0; i < len-1; ++i)
- control_printf_midreply(conn, 552,
- "Unrecognized configuration key \"%s\"",
- (char*)smartlist_get(unrecognized, i));
- control_printf_endreply(conn, 552,
- "Unrecognized configuration key \"%s\"",
- (char*)smartlist_get(unrecognized, len-1));
- } else if ((len = smartlist_len(answers))) {
- char *tmp = smartlist_get(answers, len-1);
- tor_assert(strlen(tmp)>4);
- tmp[3] = ' ';
- msg = smartlist_join_strings(answers, "", 0, &msg_len);
- connection_buf_add(msg, msg_len, TO_CONN(conn));
+ if (smartlist_len(unrecognized)) {
+ control_write_reply_lines(conn, unrecognized);
+ } else if (smartlist_len(answers)) {
+ control_write_reply_lines(conn, answers);
} else {
send_control_done(conn);
}
- SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
- smartlist_free(answers);
- smartlist_free(unrecognized);
-
- tor_free(msg);
-
+ control_reply_free(answers);
+ control_reply_free(unrecognized);
return 0;
}
@@ -590,7 +574,7 @@ control_setconf_helper(control_connection_t *conn,
const unsigned flags =
CAL_CLEAR_FIRST | (use_defaults ? CAL_USE_DEFAULTS : 0);
- // We need a copy here, since confparse.c wants to canonicalize cases.
+ // We need a copy here, since confmgt.c wants to canonicalize cases.
config_line_t *lines = config_lines_dup(args->kwargs);
opt_err = options_trial_assign(lines, flags, &errstring);
@@ -1256,6 +1240,66 @@ static const control_cmd_syntax_t protocolinfo_syntax = {
.max_args = UINT_MAX
};
+/** Return a comma-separated list of authentication methods for
+ handle_control_protocolinfo(). Caller must free this string. */
+static char *
+get_authmethods(const or_options_t *options)
+{
+ int cookies = options->CookieAuthentication;
+ char *methods;
+ int passwd = (options->HashedControlPassword != NULL ||
+ options->HashedControlSessionPassword != NULL);
+ smartlist_t *mlist = smartlist_new();
+
+ if (cookies) {
+ smartlist_add(mlist, (char*)"COOKIE");
+ smartlist_add(mlist, (char*)"SAFECOOKIE");
+ }
+ if (passwd)
+ smartlist_add(mlist, (char*)"HASHEDPASSWORD");
+ if (!cookies && !passwd)
+ smartlist_add(mlist, (char*)"NULL");
+ methods = smartlist_join_strings(mlist, ",", 0, NULL);
+ smartlist_free(mlist);
+
+ return methods;
+}
+
+/** Return escaped cookie filename. Caller must free this string.
+ Return NULL if cookie authentication is disabled. */
+static char *
+get_esc_cfile(const or_options_t *options)
+{
+ char *cfile = NULL, *abs_cfile = NULL, *esc_cfile = NULL;
+
+ if (!options->CookieAuthentication)
+ return NULL;
+
+ cfile = get_controller_cookie_file_name();
+ abs_cfile = make_path_absolute(cfile);
+ esc_cfile = esc_for_log(abs_cfile);
+ tor_free(cfile);
+ tor_free(abs_cfile);
+ return esc_cfile;
+}
+
+/** Compose the auth methods line of a PROTOCOLINFO reply. */
+static void
+add_authmethods(smartlist_t *reply)
+{
+ const or_options_t *options = get_options();
+ char *methods = get_authmethods(options);
+ char *esc_cfile = get_esc_cfile(options);
+
+ control_reply_add_str(reply, 250, "AUTH");
+ control_reply_append_kv(reply, "METHODS", methods);
+ if (esc_cfile)
+ control_reply_append_kv(reply, "COOKIEFILE", esc_cfile);
+
+ tor_free(methods);
+ tor_free(esc_cfile);
+}
+
/** Called when we get a PROTOCOLINFO command: send back a reply. */
static int
handle_control_protocolinfo(control_connection_t *conn,
@@ -1263,6 +1307,7 @@ handle_control_protocolinfo(control_connection_t *conn,
{
const char *bad_arg = NULL;
const smartlist_t *args = cmd_args->args;
+ smartlist_t *reply = NULL;
conn->have_sent_protocolinfo = 1;
@@ -1280,45 +1325,17 @@ handle_control_protocolinfo(control_connection_t *conn,
/* Don't tolerate bad arguments when not authenticated. */
if (!STATE_IS_OPEN(TO_CONN(conn)->state))
connection_mark_for_close(TO_CONN(conn));
- goto done;
- } else {
- const or_options_t *options = get_options();
- int cookies = options->CookieAuthentication;
- char *cfile = get_controller_cookie_file_name();
- char *abs_cfile;
- char *esc_cfile;
- char *methods;
- abs_cfile = make_path_absolute(cfile);
- esc_cfile = esc_for_log(abs_cfile);
- {
- int passwd = (options->HashedControlPassword != NULL ||
- options->HashedControlSessionPassword != NULL);
- smartlist_t *mlist = smartlist_new();
- if (cookies) {
- smartlist_add(mlist, (char*)"COOKIE");
- smartlist_add(mlist, (char*)"SAFECOOKIE");
- }
- if (passwd)
- smartlist_add(mlist, (char*)"HASHEDPASSWORD");
- if (!cookies && !passwd)
- smartlist_add(mlist, (char*)"NULL");
- methods = smartlist_join_strings(mlist, ",", 0, NULL);
- smartlist_free(mlist);
- }
-
- control_write_midreply(conn, 250, "PROTOCOLINFO 1");
- control_printf_midreply(conn, 250, "AUTH METHODS=%s%s%s", methods,
- cookies?" COOKIEFILE=":"",
- cookies?esc_cfile:"");
- control_printf_midreply(conn, 250, "VERSION Tor=%s", escaped(VERSION));
- send_control_done(conn);
-
- tor_free(methods);
- tor_free(cfile);
- tor_free(abs_cfile);
- tor_free(esc_cfile);
+ return 0;
}
- done:
+ reply = smartlist_new();
+ control_reply_add_str(reply, 250, "PROTOCOLINFO 1");
+ add_authmethods(reply);
+ control_reply_add_str(reply, 250, "VERSION");
+ control_reply_append_kv(reply, "Tor", escaped(VERSION));
+ control_reply_add_done(reply);
+
+ control_write_reply_lines(conn, reply);
+ control_reply_free(reply);
return 0;
}
@@ -1970,6 +1987,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
decoded_key->v2 = pk;
*hs_version = HS_VERSION_TWO;
} else if (!strcasecmp(key_type_ed25519_v3, key_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));
if (base64_decode((char *) sk->seckey, sizeof(sk->seckey), key_blob,
@@ -2248,12 +2266,13 @@ typedef struct control_cmd_def_t {
*/
#define CMD_FL_WIPE (1u<<0)
+#ifndef COCCI
/** Macro: declare a command with a one-line argument, a given set of flags,
* and a syntax definition.
**/
#define ONE_LINE(name, flags) \
{ \
- #name, \
+ (#name), \
handle_control_ ##name, \
flags, \
&name##_syntax, \
@@ -2264,7 +2283,7 @@ typedef struct control_cmd_def_t {
* flags.
**/
#define MULTLINE(name, flags) \
- { "+"#name, \
+ { ("+"#name), \
handle_control_ ##name, \
flags, \
&name##_syntax \
@@ -2280,6 +2299,7 @@ typedef struct control_cmd_def_t {
0, \
&obsolete_syntax, \
}
+#endif /* !defined(COCCI) */
/**
* An array defining all the recognized controller commands.
@@ -2315,6 +2335,9 @@ static const control_cmd_def_t CONTROL_COMMANDS[] =
MULTLINE(hspost, 0),
ONE_LINE(add_onion, CMD_FL_WIPE),
ONE_LINE(del_onion, CMD_FL_WIPE),
+ ONE_LINE(onion_client_auth_add, CMD_FL_WIPE),
+ ONE_LINE(onion_client_auth_remove, 0),
+ ONE_LINE(onion_client_auth_view, 0),
};
/**
diff --git a/src/feature/control/control_cmd.h b/src/feature/control/control_cmd.h
index 4b6d54abe7..0ff0f0755f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_cmd_args_st.h b/src/feature/control/control_cmd_args_st.h
index 8d7a4f55b3..e7d064c6fe 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 c9164f03b3..9e410324e0 100644
--- a/src/feature/control/control_connection_st.h
+++ b/src/feature/control/control_connection_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file control_connection_st.h
+ * @brief Controller connection structure.
+ **/
+
#ifndef CONTROL_CONNECTION_ST_H
#define CONTROL_CONNECTION_ST_H
diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c
index 8cf6d6de0b..916ccea875 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -38,6 +38,7 @@
#include "core/or/origin_circuit_st.h"
#include "lib/evloop/compat_libevent.h"
+#include "lib/encoding/confline.h"
static void flush_queued_events_cb(mainloop_event_t *event, void *arg);
static void control_get_bytes_rw_last_sec(uint64_t *r, uint64_t *w);
@@ -317,7 +318,7 @@ control_per_second_events(void)
/** Represents an event that's queued to be sent to one or more
* controllers. */
-typedef struct queued_event_s {
+typedef struct queued_event_t {
uint16_t event;
char *msg;
} queued_event_t;
@@ -833,13 +834,19 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp,
circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn));
if (circ && CIRCUIT_IS_ORIGIN(circ))
origin_circ = TO_ORIGIN_CIRCUIT(circ);
- send_control_event(EVENT_STREAM_STATUS,
- "650 STREAM %"PRIu64" %s %lu %s%s%s%s\r\n",
+
+ {
+ char *conndesc = entry_connection_describe_status_for_controller(conn);
+ const char *sp = strlen(conndesc) ? " " : "";
+ send_control_event(EVENT_STREAM_STATUS,
+ "650 STREAM %"PRIu64" %s %lu %s%s%s%s%s%s\r\n",
(ENTRY_TO_CONN(conn)->global_identifier),
status,
origin_circ?
(unsigned long)origin_circ->global_identifier : 0ul,
- buf, reason_buf, addrport_buf, purpose);
+ buf, reason_buf, addrport_buf, purpose, sp, conndesc);
+ tor_free(conndesc);
+ }
/* XXX need to specify its intended exit, etc? */
@@ -1211,7 +1218,7 @@ control_event_circuit_cell_stats(void)
static int next_measurement_idx = 0;
/* number of entries set in n_measurements */
static int n_measurements = 0;
-static struct cached_bw_event_s {
+static struct cached_bw_event_t {
uint32_t n_read;
uint32_t n_written;
} cached_bw_events[N_BW_EVENTS_TO_CACHE];
@@ -1250,7 +1257,7 @@ get_bw_samples(void)
for (i = 0; i < n_measurements; ++i) {
tor_assert(0 <= idx && idx < N_BW_EVENTS_TO_CACHE);
- const struct cached_bw_event_s *bwe = &cached_bw_events[idx];
+ const struct cached_bw_event_t *bwe = &cached_bw_events[idx];
smartlist_add_asprintf(elements, "%u,%u",
(unsigned)bwe->n_read,
@@ -1641,13 +1648,17 @@ control_event_status(int type, int severity, const char *format, va_list args)
log_warn(LD_BUG, "Format string too long.");
return -1;
}
- tor_vasprintf(&user_buf, format, args);
+ if (tor_vasprintf(&user_buf, format, args)<0) {
+ log_warn(LD_BUG, "Failed to create user buffer.");
+ return -1;
+ }
send_control_event(type, "%s %s\r\n", format_buf, user_buf);
tor_free(user_buf);
return 0;
}
+#ifndef COCCI
#define CONTROL_EVENT_STATUS_BODY(event, sev) \
int r; \
do { \
@@ -1659,6 +1670,7 @@ control_event_status(int type, int severity, const char *format, va_list args)
r = control_event_status((event), (sev), format, ap); \
va_end(ap); \
} while (0)
+#endif /* !defined(COCCI) */
/** Format and send an EVENT_STATUS_GENERAL event whose main text is obtained
* by formatting the arguments using the printf-style <b>format</b>. */
@@ -1747,27 +1759,24 @@ control_event_guard(const char *nickname, const char *digest,
}
/** Called when a configuration option changes. This is generally triggered
- * by SETCONF requests and RELOAD/SIGHUP signals. The <b>elements</b> is
- * a smartlist_t containing (key, value, ...) pairs in sequence.
- * <b>value</b> can be NULL. */
-int
-control_event_conf_changed(const smartlist_t *elements)
+ * by SETCONF requests and RELOAD/SIGHUP signals. The <b>changes</b> are
+ * a linked list of configuration key-values.
+ * <b>changes</b> can be NULL, meaning "no changes".
+ */
+void
+control_event_conf_changed(const config_line_t *changes)
{
- int i;
char *result;
smartlist_t *lines;
- if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) ||
- smartlist_len(elements) == 0) {
- return 0;
+ if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) || !changes) {
+ return;
}
lines = smartlist_new();
- for (i = 0; i < smartlist_len(elements); i += 2) {
- char *k = smartlist_get(elements, i);
- char *v = smartlist_get(elements, i+1);
- if (v == NULL) {
- smartlist_add_asprintf(lines, "650-%s", k);
+ for (const config_line_t *line = changes; line; line = line->next) {
+ if (line->value == NULL) {
+ smartlist_add_asprintf(lines, "650-%s", line->key);
} else {
- smartlist_add_asprintf(lines, "650-%s=%s", k, v);
+ smartlist_add_asprintf(lines, "650-%s=%s", line->key, line->value);
}
}
result = smartlist_join_strings(lines, "\r\n", 0, NULL);
@@ -1776,7 +1785,6 @@ control_event_conf_changed(const smartlist_t *elements)
tor_free(result);
SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
smartlist_free(lines);
- return 0;
}
/** We just generated a new summary of which countries we've seen clients
diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h
index 34986fdb89..4a5492b510 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,7 +12,11 @@
#ifndef TOR_CONTROL_EVENTS_H
#define TOR_CONTROL_EVENTS_H
+#include "lib/cc/ctassert.h"
#include "core/or/ocirc_event.h"
+#include "core/or/orconn_event.h"
+
+struct config_line_t;
/** Used to indicate the type of a CIRC_MINOR event passed to the controller.
* The various types are defined in control-spec.txt . */
@@ -21,8 +25,6 @@ typedef enum circuit_status_minor_event_t {
CIRC_MINOR_EVENT_CANNIBALIZED,
} circuit_status_minor_event_t;
-#include "core/or/orconn_event.h"
-
/** Used to indicate the type of a stream event passed to the controller.
* The various types are defined in control-spec.txt */
typedef enum stream_status_event_t {
@@ -157,12 +159,13 @@ int control_event_server_error(const char *format, ...)
int control_event_guard(const char *nickname, const char *digest,
const char *status);
-int control_event_conf_changed(const smartlist_t *elements);
+void control_event_conf_changed(const struct config_line_t *changes);
int control_event_buildtimeout_set(buildtimeout_set_event_t type,
const char *args);
int control_event_signal(uintptr_t signal);
void control_event_bootstrap(bootstrap_status_t status, int progress);
+int control_get_bootstrap_percent(void);
MOCK_DECL(void, control_event_bootstrap_prob_or,(const char *warn,
int reason,
or_connection_t *or_conn));
@@ -286,10 +289,7 @@ typedef uint64_t event_mask_t;
/* If EVENT_MAX_ ever hits 0x0040, we need to make the mask into a
* different structure, as it can only handle a maximum left shift of 1<<63. */
-
-#if EVENT_MAX_ >= EVENT_CAPACITY_
-#error control_connection_t.event_mask has an event greater than its capacity
-#endif
+CTASSERT(EVENT_MAX_ < EVENT_CAPACITY_);
#define EVENT_MASK_(e) (((uint64_t)1)<<(e))
diff --git a/src/feature/control/control_fmt.c b/src/feature/control/control_fmt.c
index e0e77eb2d0..d76e6ad8dd 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -165,6 +165,99 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
return rv;
}
+/** Allocate and return a description of <b>conn</b>'s current status. */
+char *
+entry_connection_describe_status_for_controller(const entry_connection_t *conn)
+{
+ char *rv;
+ smartlist_t *descparts = smartlist_new();
+
+ if (conn->socks_request != NULL) {
+ // Show username and/or password if available; used by IsolateSOCKSAuth.
+ if (conn->socks_request->usernamelen > 0) {
+ char* username_escaped = esc_for_log_len(conn->socks_request->username,
+ (size_t) conn->socks_request->usernamelen);
+ smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s",
+ username_escaped);
+ tor_free(username_escaped);
+ }
+ if (conn->socks_request->passwordlen > 0) {
+ char* password_escaped = esc_for_log_len(conn->socks_request->password,
+ (size_t) conn->socks_request->passwordlen);
+ smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s",
+ password_escaped);
+ tor_free(password_escaped);
+ }
+
+ const char *client_protocol;
+ // Show the client protocol; used by IsolateClientProtocol.
+ switch (conn->socks_request->listener_type)
+ {
+ case CONN_TYPE_AP_LISTENER:
+ switch (conn->socks_request->socks_version)
+ {
+ case 4: client_protocol = "SOCKS4"; break;
+ case 5: client_protocol = "SOCKS5"; break;
+ default: client_protocol = "UNKNOWN";
+ }
+ break;
+ case CONN_TYPE_AP_TRANS_LISTENER: client_protocol = "TRANS"; break;
+ case CONN_TYPE_AP_NATD_LISTENER: client_protocol = "NATD"; break;
+ case CONN_TYPE_AP_DNS_LISTENER: client_protocol = "DNS"; break;
+ case CONN_TYPE_AP_HTTP_CONNECT_LISTENER:
+ client_protocol = "HTTPCONNECT"; break;
+ default: client_protocol = "UNKNOWN";
+ }
+ smartlist_add_asprintf(descparts, "CLIENT_PROTOCOL=%s",
+ client_protocol);
+ }
+
+ // Show newnym epoch; used for stream isolation when NEWNYM is used.
+ smartlist_add_asprintf(descparts, "NYM_EPOCH=%u",
+ conn->nym_epoch);
+
+ // Show session group; used for stream isolation of multiple listener ports.
+ smartlist_add_asprintf(descparts, "SESSION_GROUP=%d",
+ conn->entry_cfg.session_group);
+
+ // Show isolation flags.
+ smartlist_t *isoflaglist = smartlist_new();
+ char *isoflaglist_joined;
+ if (conn->entry_cfg.isolation_flags & ISO_DESTPORT) {
+ smartlist_add(isoflaglist, (void *)"DESTPORT");
+ }
+ if (conn->entry_cfg.isolation_flags & ISO_DESTADDR) {
+ smartlist_add(isoflaglist, (void *)"DESTADDR");
+ }
+ if (conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) {
+ smartlist_add(isoflaglist, (void *)"SOCKS_USERNAME");
+ smartlist_add(isoflaglist, (void *)"SOCKS_PASSWORD");
+ }
+ if (conn->entry_cfg.isolation_flags & ISO_CLIENTPROTO) {
+ smartlist_add(isoflaglist, (void *)"CLIENT_PROTOCOL");
+ }
+ if (conn->entry_cfg.isolation_flags & ISO_CLIENTADDR) {
+ smartlist_add(isoflaglist, (void *)"CLIENTADDR");
+ }
+ if (conn->entry_cfg.isolation_flags & ISO_SESSIONGRP) {
+ smartlist_add(isoflaglist, (void *)"SESSION_GROUP");
+ }
+ if (conn->entry_cfg.isolation_flags & ISO_NYM_EPOCH) {
+ smartlist_add(isoflaglist, (void *)"NYM_EPOCH");
+ }
+ isoflaglist_joined = smartlist_join_strings(isoflaglist, ",", 0, NULL);
+ smartlist_add_asprintf(descparts, "ISO_FIELDS=%s", isoflaglist_joined);
+ tor_free(isoflaglist_joined);
+ smartlist_free(isoflaglist);
+
+ rv = smartlist_join_strings(descparts, " ", 0, NULL);
+
+ SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
+ smartlist_free(descparts);
+
+ return rv;
+}
+
/** Return a longname the node whose identity is <b>id_digest</b>. If
* node_get_by_id() returns NULL, base 16 encoding of <b>id_digest</b> is
* returned instead.
diff --git a/src/feature/control/control_fmt.h b/src/feature/control/control_fmt.h
index 6446e37079..f3357cfc4e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,6 +17,8 @@ int write_stream_target_to_buf(entry_connection_t *conn, char *buf,
void orconn_target_get_name(char *buf, size_t len,
or_connection_t *conn);
char *circuit_describe_status_for_controller(origin_circuit_t *circ);
+char *entry_connection_describe_status_for_controller(const
+ entry_connection_t *conn);
MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest));
diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c
index 3e31bb9e8f..0823acbe07 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -34,6 +34,7 @@
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
#include "feature/dirclient/dlstatus.h"
+#include "feature/dircommon/directory.h"
#include "feature/hibernate/hibernate.h"
#include "feature/hs/hs_cache.h"
#include "feature/hs_common/shared_random_client.h"
@@ -43,6 +44,7 @@
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerlist.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
@@ -50,6 +52,7 @@
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
#include "lib/version/torversion.h"
+#include "lib/encoding/kvline.h"
#include "core/or/entry_connection_st.h"
#include "core/or/or_connection_st.h"
@@ -134,6 +137,7 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
return -1;
}
*answer = tor_dup_ip(addr);
+ tor_assert_nonfatal(*answer);
} else if (!strcmp(question, "traffic/read")) {
tor_asprintf(answer, "%"PRIu64, (get_bytes_read()));
} else if (!strcmp(question, "traffic/written")) {
@@ -325,6 +329,121 @@ getinfo_helper_current_time(control_connection_t *control_conn,
return 0;
}
+/** GETINFO helper for dumping different consensus flavors
+ * returns: 0 on success -1 on error. */
+STATIC int
+getinfo_helper_current_consensus(consensus_flavor_t flavor,
+ char** answer,
+ const char** errmsg)
+{
+ const char *flavor_name = networkstatus_get_flavor_name(flavor);
+ if (BUG(!strcmp(flavor_name, "??"))) {
+ *errmsg = "Internal error: unrecognized flavor name.";
+ return -1;
+ }
+ if (we_want_to_fetch_flavor(get_options(), flavor)) {
+ /** Check from the cache */
+ const cached_dir_t *consensus = dirserv_get_consensus(flavor_name);
+ if (consensus) {
+ *answer = tor_strdup(consensus->dir);
+ }
+ }
+ if (!*answer) { /* try loading it from disk */
+
+ tor_mmap_t *mapped = networkstatus_map_cached_consensus(flavor_name);
+ if (mapped) {
+ *answer = tor_memdup_nulterm(mapped->data, mapped->size);
+ tor_munmap_file(mapped);
+ }
+ if (!*answer) { /* generate an error */
+ *errmsg = "Could not open cached consensus. "
+ "Make sure FetchUselessDescriptors is set to 1.";
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/** Helper for getinfo_helper_dir.
+ *
+ * Add a signed_descriptor_t to <b>descs_out</b> for each router matching
+ * <b>key</b>. The key should be either
+ * - "/tor/server/authority" for our own routerinfo;
+ * - "/tor/server/all" for all the routerinfos we have, concatenated;
+ * - "/tor/server/fp/FP" where FP is a plus-separated sequence of
+ * hex identity digests; or
+ * - "/tor/server/d/D" where D is a plus-separated sequence
+ * of server descriptor digests, in hex.
+ *
+ * Return 0 if we found some matching descriptors, or -1 if we do not
+ * have any descriptors, no matching descriptors, or if we did not
+ * recognize the key (URL).
+ * If -1 is returned *<b>msg</b> will be set to an appropriate error
+ * message.
+ */
+static int
+controller_get_routerdescs(smartlist_t *descs_out, const char *key,
+ const char **msg)
+{
+ *msg = NULL;
+
+ if (!strcmp(key, "/tor/server/all")) {
+ routerlist_t *rl = router_get_routerlist();
+ SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
+ smartlist_add(descs_out, &(r->cache_info)));
+ } else if (!strcmp(key, "/tor/server/authority")) {
+ const routerinfo_t *ri = router_get_my_routerinfo();
+ if (ri)
+ smartlist_add(descs_out, (void*) &(ri->cache_info));
+ } else if (!strcmpstart(key, "/tor/server/d/")) {
+ smartlist_t *digests = smartlist_new();
+ key += strlen("/tor/server/d/");
+ dir_split_resource_into_fingerprints(key, digests, NULL,
+ DSR_HEX|DSR_SORT_UNIQ);
+ SMARTLIST_FOREACH(digests, const char *, d,
+ {
+ signed_descriptor_t *sd = router_get_by_descriptor_digest(d);
+ if (sd)
+ smartlist_add(descs_out,sd);
+ });
+ SMARTLIST_FOREACH(digests, char *, d, tor_free(d));
+ smartlist_free(digests);
+ } else if (!strcmpstart(key, "/tor/server/fp/")) {
+ smartlist_t *digests = smartlist_new();
+ time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH;
+ key += strlen("/tor/server/fp/");
+ dir_split_resource_into_fingerprints(key, digests, NULL,
+ DSR_HEX|DSR_SORT_UNIQ);
+ SMARTLIST_FOREACH_BEGIN(digests, const char *, d) {
+ if (router_digest_is_me(d)) {
+ /* calling router_get_my_routerinfo() to make sure it exists */
+ const routerinfo_t *ri = router_get_my_routerinfo();
+ if (ri)
+ smartlist_add(descs_out, (void*) &(ri->cache_info));
+ } else {
+ const routerinfo_t *ri = router_get_by_id_digest(d);
+ /* Don't actually serve a descriptor that everyone will think is
+ * expired. This is an (ugly) workaround to keep buggy 0.1.1.10
+ * Tors from downloading descriptors that they will throw away.
+ */
+ if (ri && ri->cache_info.published_on > cutoff)
+ smartlist_add(descs_out, (void*) &(ri->cache_info));
+ }
+ } SMARTLIST_FOREACH_END(d);
+ SMARTLIST_FOREACH(digests, char *, d, tor_free(d));
+ smartlist_free(digests);
+ } else {
+ *msg = "Key not recognized";
+ return -1;
+ }
+
+ if (!smartlist_len(descs_out)) {
+ *msg = "Servers unavailable";
+ return -1;
+ }
+ return 0;
+}
+
/** Implementation helper for GETINFO: knows the answers for questions about
* directory information. */
STATIC int
@@ -554,7 +673,7 @@ getinfo_helper_dir(control_connection_t *control_conn,
int res;
char *cp;
tor_asprintf(&url, "/tor/%s", question+4);
- res = dirserv_get_routerdescs(descs, url, &msg);
+ res = controller_get_routerdescs(descs, url, &msg);
if (res) {
log_warn(LD_CONTROL, "getinfo '%s': %s", question, msg);
smartlist_free(descs);
@@ -576,23 +695,18 @@ getinfo_helper_dir(control_connection_t *control_conn,
smartlist_free(descs);
} else if (!strcmpstart(question, "dir/status/")) {
*answer = tor_strdup("");
- } else if (!strcmp(question, "dir/status-vote/current/consensus")) { /* v3 */
- if (we_want_to_fetch_flavor(get_options(), FLAV_NS)) {
- const cached_dir_t *consensus = dirserv_get_consensus("ns");
- if (consensus)
- *answer = tor_strdup(consensus->dir);
+ } else if (!strcmp(question, "dir/status-vote/current/consensus")) {
+ int consensus_result = getinfo_helper_current_consensus(FLAV_NS,
+ answer, errmsg);
+ if (consensus_result < 0) {
+ return -1;
}
- if (!*answer) { /* try loading it from disk */
- tor_mmap_t *mapped = networkstatus_map_cached_consensus("ns");
- if (mapped) {
- *answer = tor_memdup_nulterm(mapped->data, mapped->size);
- tor_munmap_file(mapped);
- }
- if (!*answer) { /* generate an error */
- *errmsg = "Could not open cached consensus. "
- "Make sure FetchUselessDescriptors is set to 1.";
- return -1;
- }
+ } else if (!strcmp(question,
+ "dir/status-vote/current/consensus-microdesc")) {
+ int consensus_result = getinfo_helper_current_consensus(FLAV_MICRODESC,
+ answer, errmsg);
+ if (consensus_result < 0) {
+ return -1;
}
} else if (!strcmp(question, "network-status")) { /* v1 */
static int network_status_warned = 0;
@@ -1219,8 +1333,22 @@ getinfo_helper_events(control_connection_t *control_conn,
}
routerinfo_t *r;
extrainfo_t *e;
- if (router_build_fresh_descriptor(&r, &e) < 0) {
- *errmsg = "Error generating descriptor";
+ int result;
+ if ((result = router_build_fresh_descriptor(&r, &e)) < 0) {
+ switch (result) {
+ case TOR_ROUTERINFO_ERROR_NO_EXT_ADDR:
+ *errmsg = "Cannot get relay address while generating descriptor";
+ break;
+ case TOR_ROUTERINFO_ERROR_DIGEST_FAILED:
+ *errmsg = "Key digest failed";
+ break;
+ case TOR_ROUTERINFO_ERROR_CANNOT_GENERATE:
+ *errmsg = "Cannot generate router descriptor";
+ break;
+ default:
+ *errmsg = "Error generating descriptor";
+ break;
+ }
return -1;
}
size_t size = r->cache_info.signed_descriptor_len + 1;
@@ -1513,6 +1641,8 @@ static const getinfo_item_t getinfo_items[] = {
"v2 networkstatus docs as retrieved from a DirPort."),
ITEM("dir/status-vote/current/consensus", dir,
"v3 Networkstatus consensus as retrieved from a DirPort."),
+ ITEM("dir/status-vote/current/consensus-microdesc", dir,
+ "v3 Microdescriptor consensus as retrieved from a DirPort."),
ITEM("exit-policy/default", policies,
"The default value appended to the configured exit policy."),
ITEM("exit-policy/reject-private/default", policies,
@@ -1600,7 +1730,6 @@ handle_control_getinfo(control_connection_t *conn,
smartlist_t *answers = smartlist_new();
smartlist_t *unrecognized = smartlist_new();
char *ans = NULL;
- int i;
SMARTLIST_FOREACH_BEGIN(questions, const char *, q) {
const char *errmsg = NULL;
@@ -1612,43 +1741,33 @@ handle_control_getinfo(control_connection_t *conn,
goto done;
}
if (!ans) {
- if (errmsg) /* use provided error message */
- smartlist_add_strdup(unrecognized, errmsg);
- else /* use default error message */
- smartlist_add_asprintf(unrecognized, "Unrecognized key \"%s\"", q);
+ if (errmsg) {
+ /* use provided error message */
+ control_reply_add_str(unrecognized, 552, errmsg);
+ } else {
+ /* use default error message */
+ control_reply_add_printf(unrecognized, 552,
+ "Unrecognized key \"%s\"", q);
+ }
} else {
- smartlist_add_strdup(answers, q);
- smartlist_add(answers, ans);
+ control_reply_add_one_kv(answers, 250, KV_RAW, q, ans);
+ tor_free(ans);
}
} SMARTLIST_FOREACH_END(q);
- if (smartlist_len(unrecognized)) {
- /* control-spec section 2.3, mid-reply '-' or end of reply ' ' */
- for (i=0; i < smartlist_len(unrecognized)-1; ++i)
- control_write_midreply(conn, 552,
- (char *)smartlist_get(unrecognized, i));
+ control_reply_add_done(answers);
- control_write_endreply(conn, 552, (char *)smartlist_get(unrecognized, i));
+ if (smartlist_len(unrecognized)) {
+ control_write_reply_lines(conn, unrecognized);
+ /* If there were any unrecognized queries, don't write real answers */
goto done;
}
- for (i = 0; i < smartlist_len(answers); i += 2) {
- char *k = smartlist_get(answers, i);
- char *v = smartlist_get(answers, i+1);
- if (!strchr(v, '\n') && !strchr(v, '\r')) {
- control_printf_midreply(conn, 250, "%s=%s", k, v);
- } else {
- control_printf_datareply(conn, 250, "%s=", k);
- control_write_data(conn, v);
- }
- }
- send_control_done(conn);
+ control_write_reply_lines(conn, answers);
done:
- SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
- smartlist_free(answers);
- SMARTLIST_FOREACH(unrecognized, char *, cp, tor_free(cp));
- smartlist_free(unrecognized);
+ control_reply_free(answers);
+ control_reply_free(unrecognized);
return 0;
}
diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h
index 52978686d8..0ada49258e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -48,6 +48,10 @@ STATIC int getinfo_helper_downloads(
control_connection_t *control_conn,
const char *question, char **answer,
const char **errmsg);
+STATIC int getinfo_helper_current_consensus(
+ consensus_flavor_t flavor,
+ char **answer,
+ const char **errmsg);
STATIC int getinfo_helper_dir(
control_connection_t *control_conn,
const char *question, char **answer,
diff --git a/src/feature/control/control_hs.c b/src/feature/control/control_hs.c
new file mode 100644
index 0000000000..c8de03b318
--- /dev/null
+++ b/src/feature/control/control_hs.c
@@ -0,0 +1,343 @@
+/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file control_hs.c
+ *
+ * \brief Implement commands for Tor's control-socket interface that are
+ * related to onion services.
+ **/
+
+#include "core/or/or.h"
+#include "feature/control/control_cmd.h"
+#include "feature/control/control_hs.h"
+#include "feature/control/control_proto.h"
+#include "feature/hs/hs_client.h"
+#include "lib/encoding/confline.h"
+
+#include "feature/control/control_cmd_args_st.h"
+
+/** Parse the 'KeyType ":" PrivateKey' from <b>client_privkey_str</b> and store
+ * it into <b>privkey</b>. Use <b>conn</b> to output any errors if needed.
+ *
+ * Return 0 if all went well, -1 otherwise. */
+static int
+parse_private_key_from_control_port(const char *client_privkey_str,
+ curve25519_secret_key_t *privkey,
+ control_connection_t *conn)
+{
+ int retval = -1;
+ smartlist_t *key_args = smartlist_new();
+
+ tor_assert(privkey);
+
+ smartlist_split_string(key_args, client_privkey_str, ":",
+ SPLIT_IGNORE_BLANK, 0);
+ if (smartlist_len(key_args) != 2) {
+ control_printf_endreply(conn, 512, "Invalid key type/blob");
+ goto err;
+ }
+
+ const char *key_type = smartlist_get(key_args, 0);
+ const char *key_blob = smartlist_get(key_args, 1);
+
+ if (strcasecmp(key_type, "x25519")) {
+ control_printf_endreply(conn, 552,
+ "Unrecognized key type \"%s\"", key_type);
+ goto err;
+ }
+
+ if (base64_decode((char*)privkey->secret_key, sizeof(privkey->secret_key),
+ key_blob,
+ strlen(key_blob)) != sizeof(privkey->secret_key)) {
+ control_printf_endreply(conn, 512, "Failed to decode x25519 private key");
+ goto err;
+ }
+
+ if (fast_mem_is_zero((const char*)privkey->secret_key,
+ sizeof(privkey->secret_key))) {
+ control_printf_endreply(conn, 553,
+ "Invalid private key \"%s\"", key_blob);
+ goto err;
+ }
+
+ retval = 0;
+
+ err:
+ SMARTLIST_FOREACH(key_args, char *, c, tor_free(c));
+ smartlist_free(key_args);
+ return retval;
+}
+
+/** Syntax details for ONION_CLIENT_AUTH_ADD */
+const control_cmd_syntax_t onion_client_auth_add_syntax = {
+ .max_args = 2,
+ .accept_keywords = true,
+};
+
+/** Called when we get an ONION_CLIENT_AUTH_ADD command; parse the body, and
+ * register the new client-side client auth credentials:
+ * "ONION_CLIENT_AUTH_ADD" SP HSAddress
+ * SP KeyType ":" PrivateKeyBlob
+ * [SP "Type=" TYPE] CRLF
+ */
+int
+handle_control_onion_client_auth_add(control_connection_t *conn,
+ const control_cmd_args_t *args)
+{
+ int retval = -1;
+ smartlist_t *flags = smartlist_new();
+ hs_client_service_authorization_t *creds = NULL;
+
+ tor_assert(args);
+
+ int argc = smartlist_len(args->args);
+ /* We need at least 'HSAddress' and 'PrivateKeyBlob' */
+ if (argc < 2) {
+ control_printf_endreply(conn, 512,
+ "Incomplete ONION_CLIENT_AUTH_ADD command");
+ goto err;
+ }
+
+ creds = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+
+ const char *hsaddress = smartlist_get(args->args, 0);
+ if (!hs_address_is_valid(hsaddress)) {
+ control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",hsaddress);
+ goto err;
+ }
+ strlcpy(creds->onion_address, hsaddress, sizeof(creds->onion_address));
+
+ /* Parse the client private key */
+ const char *client_privkey = smartlist_get(args->args, 1);
+ if (parse_private_key_from_control_port(client_privkey,
+ &creds->enc_seckey, conn) < 0) {
+ goto err;
+ }
+
+ /* Now let's parse the remaining arguments (variable size) */
+ for (const config_line_t *line = args->kwargs; line; line = line->next) {
+ if (!strcasecmpstart(line->key, "Flags")) {
+ smartlist_split_string(flags, line->value, ",", SPLIT_IGNORE_BLANK, 0);
+ if (smartlist_len(flags) < 1) {
+ control_write_endreply(conn, 512, "Invalid 'Flags' argument");
+ goto err;
+ }
+ SMARTLIST_FOREACH_BEGIN(flags, const char *, flag) {
+ if (!strcasecmp(flag, "Permanent")) {
+ creds->flags |= CLIENT_AUTH_FLAG_IS_PERMANENT;
+ } else {
+ control_printf_endreply(conn, 512, "Invalid 'Flags' argument: %s",
+ escaped(flag));
+ goto err;
+ }
+ } SMARTLIST_FOREACH_END(flag);
+ }
+ }
+
+ hs_client_register_auth_status_t register_status;
+ /* Register the credential (register func takes ownership of cred.) */
+ register_status = hs_client_register_auth_credentials(creds);
+ switch (register_status) {
+ case REGISTER_FAIL_BAD_ADDRESS:
+ /* It's a bug because the service addr has already been validated above */
+ control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"", hsaddress);
+ break;
+ case REGISTER_FAIL_PERMANENT_STORAGE:
+ control_printf_endreply(conn, 553, "Unable to store creds for \"%s\"",
+ hsaddress);
+ break;
+ case REGISTER_SUCCESS_ALREADY_EXISTS:
+ control_printf_endreply(conn, 251,"Client for onion existed and replaced");
+ break;
+ case REGISTER_SUCCESS_AND_DECRYPTED:
+ control_printf_endreply(conn, 252,"Registered client and decrypted desc");
+ break;
+ case REGISTER_SUCCESS:
+ control_printf_endreply(conn, 250, "OK");
+ break;
+ default:
+ tor_assert_nonfatal_unreached();
+ }
+
+ retval = 0;
+ goto done;
+
+ err:
+ client_service_authorization_free(creds);
+
+ done:
+ SMARTLIST_FOREACH(flags, char *, s, tor_free(s));
+ smartlist_free(flags);
+ return retval;
+}
+
+/** Syntax details for ONION_CLIENT_AUTH_REMOVE */
+const control_cmd_syntax_t onion_client_auth_remove_syntax = {
+ .max_args = 1,
+ .accept_keywords = true,
+};
+
+/** Called when we get an ONION_CLIENT_AUTH_REMOVE command; parse the body, and
+ * register the new client-side client auth credentials.
+ * "ONION_CLIENT_AUTH_REMOVE" SP HSAddress
+ */
+int
+handle_control_onion_client_auth_remove(control_connection_t *conn,
+ const control_cmd_args_t *args)
+{
+ int retval = -1;
+
+ tor_assert(args);
+
+ int argc = smartlist_len(args->args);
+ if (argc < 1) {
+ control_printf_endreply(conn, 512,
+ "Incomplete ONION_CLIENT_AUTH_REMOVE command");
+ goto err;
+ }
+
+ const char *hsaddress = smartlist_get(args->args, 0);
+ if (!hs_address_is_valid(hsaddress)) {
+ control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",hsaddress);
+ goto err;
+ }
+
+ hs_client_removal_auth_status_t removal_status;
+ removal_status = hs_client_remove_auth_credentials(hsaddress);
+ switch (removal_status) {
+ case REMOVAL_BAD_ADDRESS:
+ /* It's a bug because the service addr has already been validated above */
+ control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",hsaddress);
+ break;
+ case REMOVAL_SUCCESS_NOT_FOUND:
+ control_printf_endreply(conn, 251, "No credentials for \"%s\"",hsaddress);
+ break;
+ case REMOVAL_SUCCESS:
+ control_printf_endreply(conn, 250, "OK");
+ break;
+ default:
+ tor_assert_nonfatal_unreached();
+ }
+
+ retval = 0;
+
+ err:
+ return retval;
+}
+
+/** Helper: Return a newly allocated string with the encoding of client
+ * authorization credentials */
+static char *
+encode_client_auth_cred_for_control_port(
+ hs_client_service_authorization_t *cred)
+{
+ smartlist_t *control_line = smartlist_new();
+ char x25519_b64[128];
+ char *msg_str = NULL;
+
+ tor_assert(cred);
+
+ if (base64_encode(x25519_b64, sizeof(x25519_b64),
+ (char *)cred->enc_seckey.secret_key,
+ sizeof(cred->enc_seckey.secret_key), 0) < 0) {
+ tor_assert_nonfatal_unreached();
+ goto err;
+ }
+
+ smartlist_add_asprintf(control_line, "CLIENT %s x25519:%s",
+ cred->onion_address, x25519_b64);
+
+ if (cred->flags) { /* flags are also optional */
+ if (cred->flags & CLIENT_AUTH_FLAG_IS_PERMANENT) {
+ smartlist_add_asprintf(control_line, " Flags=Permanent");
+ }
+ }
+
+ /* Join all the components into a single string */
+ msg_str = smartlist_join_strings(control_line, "", 0, NULL);
+
+ err:
+ SMARTLIST_FOREACH(control_line, char *, cp, tor_free(cp));
+ smartlist_free(control_line);
+
+ return msg_str;
+}
+
+/** Syntax details for ONION_CLIENT_AUTH_VIEW */
+const control_cmd_syntax_t onion_client_auth_view_syntax = {
+ .max_args = 1,
+ .accept_keywords = true,
+};
+
+/** Called when we get an ONION_CLIENT_AUTH_VIEW command; parse the body, and
+ * register the new client-side client auth credentials.
+ * "ONION_CLIENT_AUTH_VIEW" [SP HSAddress] CRLF
+ */
+int
+handle_control_onion_client_auth_view(control_connection_t *conn,
+ const control_cmd_args_t *args)
+{
+ int retval = -1;
+ const char *hsaddress = NULL;
+ /* We are gonna put all the credential strings into a smartlist, and sort it
+ before printing, so that we can get a guaranteed order of printing. */
+ smartlist_t *creds_str_list = smartlist_new();
+
+ tor_assert(args);
+
+ int argc = smartlist_len(args->args);
+ if (argc >= 1) {
+ hsaddress = smartlist_get(args->args, 0);
+ if (!hs_address_is_valid(hsaddress)) {
+ control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",
+ hsaddress);
+ goto err;
+ }
+ }
+
+ if (hsaddress) {
+ control_printf_midreply(conn, 250, "ONION_CLIENT_AUTH_VIEW %s", hsaddress);
+ } else {
+ control_printf_midreply(conn, 250, "ONION_CLIENT_AUTH_VIEW");
+ }
+
+ /* Create an iterator out of the digest256map */
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ digest256map_iter_t *itr = digest256map_iter_init(client_auths);
+ while (!digest256map_iter_done(itr)) {
+ const uint8_t *service_pubkey;
+ void *valp;
+ digest256map_iter_get(itr, &service_pubkey, &valp);
+ tor_assert(valp);
+ hs_client_service_authorization_t *cred = valp;
+
+ /* If a specific HS address was requested, only print creds for that one */
+ if (hsaddress && strcmp(cred->onion_address, hsaddress)) {
+ itr = digest256map_iter_next(client_auths, itr);
+ continue;
+ }
+
+ char *encoding_str = encode_client_auth_cred_for_control_port(cred);
+ tor_assert_nonfatal(encoding_str);
+ smartlist_add(creds_str_list, encoding_str);
+
+ itr = digest256map_iter_next(client_auths, itr);
+ }
+
+ /* We got everything: Now sort the strings and print them */
+ smartlist_sort_strings(creds_str_list);
+ SMARTLIST_FOREACH_BEGIN(creds_str_list, char *, c) {
+ control_printf_midreply(conn, 250, "%s", c);
+ } SMARTLIST_FOREACH_END(c);
+
+ send_control_done(conn);
+
+ retval = 0;
+
+ err:
+ SMARTLIST_FOREACH(creds_str_list, char *, cp, tor_free(cp));
+ smartlist_free(creds_str_list);
+ return retval;
+}
diff --git a/src/feature/control/control_hs.h b/src/feature/control/control_hs.h
new file mode 100644
index 0000000000..8a0cd6818d
--- /dev/null
+++ b/src/feature/control/control_hs.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file control_hs.c
+ *
+ * \brief Header file for control_hs.c.
+ **/
+
+#ifndef TOR_CONTROL_HS_H
+#define TOR_CONTROL_HS_H
+
+struct control_connection_t;
+struct control_cmd_syntax_t;
+struct control_cmd_args_t;
+
+extern const struct control_cmd_syntax_t onion_client_auth_add_syntax;
+extern const struct control_cmd_syntax_t onion_client_auth_remove_syntax;
+extern const struct control_cmd_syntax_t onion_client_auth_view_syntax;
+
+int
+handle_control_onion_client_auth_add(struct control_connection_t *conn,
+ const struct control_cmd_args_t *args);
+
+int
+handle_control_onion_client_auth_remove(struct control_connection_t *conn,
+ const struct control_cmd_args_t *args);
+
+int
+handle_control_onion_client_auth_view(struct control_connection_t *conn,
+ const struct control_cmd_args_t *args);
+
+#endif /* !defined(TOR_CONTROL_HS_H) */
diff --git a/src/feature/control/control_proto.c b/src/feature/control/control_proto.c
index 5dec87491d..98715ad9d5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,6 +22,8 @@
#include "core/or/origin_circuit_st.h"
#include "core/or/socks_request_st.h"
#include "feature/control/control_connection_st.h"
+#include "lib/container/smartlist.h"
+#include "lib/encoding/kvline.h"
/** Append a NUL-terminated string <b>s</b> to the end of
* <b>conn</b>-\>outbuf.
@@ -275,3 +277,158 @@ control_write_data(control_connection_t *conn, const char *data)
connection_buf_add(esc, esc_len, TO_CONN(conn));
tor_free(esc);
}
+
+/** Write a single reply line to @a conn.
+ *
+ * @param conn control connection
+ * @param line control reply line to write
+ * @param lastone true if this is the last reply line of a multi-line reply
+ */
+void
+control_write_reply_line(control_connection_t *conn,
+ const control_reply_line_t *line, bool lastone)
+{
+ const config_line_t *kvline = line->kvline;
+ char *s = NULL;
+
+ if (strpbrk(kvline->value, "\r\n") != NULL) {
+ /* If a key-value pair needs to be encoded as CmdData, it can be
+ the only key-value pair in that reply line */
+ tor_assert(kvline->next == NULL);
+ control_printf_datareply(conn, line->code, "%s=", kvline->key);
+ control_write_data(conn, kvline->value);
+ return;
+ }
+ s = kvline_encode(kvline, line->flags);
+ if (lastone) {
+ control_write_endreply(conn, line->code, s);
+ } else {
+ control_write_midreply(conn, line->code, s);
+ }
+ tor_free(s);
+}
+
+/** Write a set of reply lines to @a conn.
+ *
+ * @param conn control connection
+ * @param lines smartlist of pointers to control_reply_line_t to write
+ */
+void
+control_write_reply_lines(control_connection_t *conn, smartlist_t *lines)
+{
+ bool lastone = false;
+
+ SMARTLIST_FOREACH_BEGIN(lines, control_reply_line_t *, line) {
+ if (line_sl_idx >= line_sl_len - 1)
+ lastone = true;
+ control_write_reply_line(conn, line, lastone);
+ } SMARTLIST_FOREACH_END(line);
+}
+
+/** Add a single key-value pair as a new reply line to a control reply
+ * line list.
+ *
+ * @param reply smartlist of pointers to control_reply_line_t
+ * @param code numeric control reply code
+ * @param flags kvline encoding flags
+ * @param key key
+ * @param val value
+ */
+void
+control_reply_add_one_kv(smartlist_t *reply, int code, int flags,
+ const char *key, const char *val)
+{
+ control_reply_line_t *line = tor_malloc_zero(sizeof(*line));
+
+ line->code = code;
+ line->flags = flags;
+ config_line_append(&line->kvline, key, val);
+ smartlist_add(reply, line);
+}
+
+/** Append a single key-value pair to last reply line in a control
+ * reply line list.
+ *
+ * @param reply smartlist of pointers to control_reply_line_t
+ * @param key key
+ * @param val value
+ */
+void
+control_reply_append_kv(smartlist_t *reply, const char *key, const char *val)
+{
+ int len = smartlist_len(reply);
+ control_reply_line_t *line;
+
+ tor_assert(len > 0);
+
+ line = smartlist_get(reply, len - 1);
+ config_line_append(&line->kvline, key, val);
+}
+
+/** Add new reply line consisting of the string @a s
+ *
+ * @param reply smartlist of pointers to control_reply_line_t
+ * @param code numeric control reply code
+ * @param s string containing the rest of the reply line
+ */
+void
+control_reply_add_str(smartlist_t *reply, int code, const char *s)
+{
+ control_reply_add_one_kv(reply, code, KV_OMIT_KEYS|KV_RAW, "", s);
+}
+
+/** Format a new reply line
+ *
+ * @param reply smartlist of pointers to control_reply_line_t
+ * @param code numeric control reply code
+ * @param fmt format string
+ */
+void
+control_reply_add_printf(smartlist_t *reply, int code, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf = NULL;
+
+ va_start(ap, fmt);
+ (void)tor_vasprintf(&buf, fmt, ap);
+ va_end(ap);
+ control_reply_add_str(reply, code, buf);
+ tor_free(buf);
+}
+
+/** Add a "250 OK" line to a set of control reply lines */
+void
+control_reply_add_done(smartlist_t *reply)
+{
+ control_reply_add_str(reply, 250, "OK");
+}
+
+/** Free a control_reply_line_t. Don't call this directly; use the
+ * control_reply_line_free() macro instead. */
+void
+control_reply_line_free_(control_reply_line_t *line)
+{
+ if (!line)
+ return;
+ config_free_lines(line->kvline);
+ tor_free_(line);
+}
+
+/** Clear a smartlist of control_reply_line_t. Doesn't free the
+ * smartlist, but does free each individual line. */
+void
+control_reply_clear(smartlist_t *reply)
+{
+ SMARTLIST_FOREACH(reply, control_reply_line_t *, line,
+ control_reply_line_free(line));
+ smartlist_clear(reply);
+}
+
+/** Free a smartlist of control_reply_line_t. Don't call this
+ * directly; use the control_reply_free() macro instead. */
+void
+control_reply_free_(smartlist_t *reply)
+{
+ control_reply_clear(reply);
+ smartlist_free_(reply);
+}
diff --git a/src/feature/control/control_proto.h b/src/feature/control/control_proto.h
index 3182f3d415..4c32b820d1 100644
--- a/src/feature/control/control_proto.h
+++ b/src/feature/control/control_proto.h
@@ -1,17 +1,62 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file control_proto.h
* \brief Header file for control_proto.c.
+ *
+ * See @ref replylines for details about the key-value abstraction for
+ * generating reply lines.
**/
#ifndef TOR_CONTROL_PROTO_H
#define TOR_CONTROL_PROTO_H
+#include "lib/encoding/confline.h"
+
+/**
+ * @defgroup replylines Control reply lines
+ * @brief Key-value structures for control reply lines
+ *
+ * Control reply lines are config_line_t key-value structures with
+ * some additional information to help formatting, such as the numeric
+ * result code specified in the control protocol and flags affecting
+ * the way kvline_encode() formats the @a kvline.
+ *
+ * Generally, modules implementing control commands will work with
+ * smartlists of these structures, using functions like
+ * control_reply_add_str() for adding a reply line consisting of a
+ * single string, or control_reply_add_one_kv() and
+ * control_reply_append_kv() for composing a line containing one or
+ * more key-value pairs.
+ *
+ * @{
+ */
+/** @brief A reply line for the control protocol.
+ *
+ * This wraps config_line_t with some additional information that's
+ * useful when generating control reply lines.
+ */
+typedef struct control_reply_line_t {
+ int code; /**< numeric code */
+ int flags; /**< kvline encoding flags */
+ config_line_t *kvline; /**< kvline */
+} control_reply_line_t;
+
+void control_reply_line_free_(control_reply_line_t *line);
+/**
+ * @brief Free and null a control_reply_line_t
+ *
+ * @param line pointer to control_reply_line_t to free
+ */
+#define control_reply_line_free(line) \
+ FREE_AND_NULL(control_reply_line_t, \
+ control_reply_line_free_, (line))
+/** @} */
+
void connection_write_str_to_buf(const char *s, control_connection_t *conn);
void connection_printf_to_buf(control_connection_t *conn,
const char *format, ...)
@@ -45,4 +90,31 @@ void control_printf_datareply(control_connection_t *conn, int code,
CHECK_PRINTF(3, 4);
void control_write_data(control_connection_t *conn, const char *data);
+/** @addtogroup replylines
+ * @{
+ */
+void control_write_reply_line(control_connection_t *conn,
+ const control_reply_line_t *line, bool lastone);
+void control_write_reply_lines(control_connection_t *conn, smartlist_t *lines);
+
+void control_reply_add_one_kv(smartlist_t *reply, int code, int flags,
+ const char *key, const char *val);
+void control_reply_append_kv(smartlist_t *reply, const char *key,
+ const char *val);
+void control_reply_add_str(smartlist_t *reply, int code, const char *s);
+void control_reply_add_printf(smartlist_t *reply, int code,
+ const char *fmt, ...)
+ CHECK_PRINTF(3, 4);
+void control_reply_add_done(smartlist_t *reply);
+
+void control_reply_clear(smartlist_t *reply);
+void control_reply_free_(smartlist_t *reply);
+
+/** @brief Free and null a smartlist of control_reply_line_t.
+ *
+ * @param r pointer to smartlist_t of control_reply_line_t to free */
+#define control_reply_free(r) \
+ FREE_AND_NULL(smartlist_t, control_reply_free_, (r))
+/** @} */
+
#endif /* !defined(TOR_CONTROL_PROTO_H) */
diff --git a/src/feature/control/feature_control.md b/src/feature/control/feature_control.md
new file mode 100644
index 0000000000..9f1681ea91
--- /dev/null
+++ b/src/feature/control/feature_control.md
@@ -0,0 +1,8 @@
+@dir /feature/control
+@brief feature/control: Controller API.
+
+The Controller API is a text-based protocol that another program (or another
+thread, if you're running Tor in-process) can use to configure and control
+Tor while it is running. The current protocol is documented in
+[control-spec.txt](https://gitweb.torproject.org/torspec.git/tree/control-spec.txt).
+
diff --git a/src/feature/control/fmt_serverstatus.c b/src/feature/control/fmt_serverstatus.c
index 33c5ba1336..ed9ad95ce2 100644
--- a/src/feature/control/fmt_serverstatus.c
+++ b/src/feature/control/fmt_serverstatus.c
@@ -1,8 +1,13 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file fmt_serverstatus.c
+ * @brief Format relay info for a controller.
+ **/
+
#include "core/or/or.h"
#include "feature/control/fmt_serverstatus.h"
diff --git a/src/feature/control/fmt_serverstatus.h b/src/feature/control/fmt_serverstatus.h
index d9190cb7e1..9dd9fe125c 100644
--- a/src/feature/control/fmt_serverstatus.h
+++ b/src/feature/control/fmt_serverstatus.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-2020, 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 d188725fa3..33019207e6 100644
--- a/src/feature/control/getinfo_geoip.c
+++ b/src/feature/control/getinfo_geoip.c
@@ -1,3 +1,12 @@
+/* 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 getinfo_geoip.c
+ * @brief GEOIP-related contoller GETINFO commands.
+ **/
#include "core/or/or.h"
#include "core/mainloop/connection.h"
diff --git a/src/feature/control/getinfo_geoip.h b/src/feature/control/getinfo_geoip.h
index 94759d0d18..5bc4b08414 100644
--- a/src/feature/control/getinfo_geoip.h
+++ b/src/feature/control/getinfo_geoip.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file getinfo_geoip.h
+ * @brief Header for getinfo_geoip.c
+ **/
+
#ifndef TOR_GETINFO_GEOIP_H
#define TOR_GETINFO_GEOIP_H
diff --git a/src/feature/control/include.am b/src/feature/control/include.am
new file mode 100644
index 0000000000..07094f23bb
--- /dev/null
+++ b/src/feature/control/include.am
@@ -0,0 +1,39 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/control/btrack.c \
+ src/feature/control/btrack_circuit.c \
+ src/feature/control/btrack_orconn.c \
+ src/feature/control/btrack_orconn_cevent.c \
+ src/feature/control/btrack_orconn_maps.c \
+ src/feature/control/control.c \
+ src/feature/control/control_auth.c \
+ src/feature/control/control_bootstrap.c \
+ src/feature/control/control_cmd.c \
+ src/feature/control/control_hs.c \
+ src/feature/control/control_events.c \
+ src/feature/control/control_fmt.c \
+ src/feature/control/control_getinfo.c \
+ src/feature/control/control_proto.c \
+ src/feature/control/fmt_serverstatus.c \
+ src/feature/control/getinfo_geoip.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/control/btrack_circuit.h \
+ src/feature/control/btrack_orconn.h \
+ src/feature/control/btrack_orconn_cevent.h \
+ src/feature/control/btrack_orconn_maps.h \
+ src/feature/control/btrack_sys.h \
+ src/feature/control/control.h \
+ src/feature/control/control_auth.h \
+ src/feature/control/control_cmd.h \
+ src/feature/control/control_hs.h \
+ src/feature/control/control_cmd_args_st.h \
+ src/feature/control/control_connection_st.h \
+ src/feature/control/control_events.h \
+ src/feature/control/control_fmt.h \
+ src/feature/control/control_getinfo.h \
+ src/feature/control/control_proto.h \
+ src/feature/control/fmt_serverstatus.h \
+ src/feature/control/getinfo_geoip.h
diff --git a/src/feature/dirauth/.may_include b/src/feature/dirauth/.may_include
new file mode 100644
index 0000000000..a9bb274699
--- /dev/null
+++ b/src/feature/dirauth/.may_include
@@ -0,0 +1,2 @@
+*.h
+feature/dirauth/*.inc
diff --git a/src/feature/dirauth/authmode.c b/src/feature/dirauth/authmode.c
index 29fcc6d1a9..0fde7bc679 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,6 +26,15 @@ authdir_mode(const or_options_t *options)
{
return options->AuthoritativeDir != 0;
}
+
+/* Return true iff we believe ourselves to be a v3 authoritative directory
+ * server. */
+int
+authdir_mode_v3(const or_options_t *options)
+{
+ return authdir_mode(options) && options->V3AuthoritativeDir != 0;
+}
+
/** Return true iff we are an authoritative directory server that is
* authoritative about receiving and serving descriptors of type
* <b>purpose</b> on its dirport.
diff --git a/src/feature/dirauth/authmode.h b/src/feature/dirauth/authmode.h
index bfd5f4dc04..6e6ba7f8ae 100644
--- a/src/feature/dirauth/authmode.h
+++ b/src/feature/dirauth/authmode.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,19 +14,13 @@
#ifdef HAVE_MODULE_DIRAUTH
int authdir_mode(const or_options_t *options);
+int authdir_mode_v3(const or_options_t *options);
int authdir_mode_handles_descs(const or_options_t *options, int purpose);
int authdir_mode_publishes_statuses(const or_options_t *options);
int authdir_mode_tests_reachability(const or_options_t *options);
int authdir_mode_bridge(const or_options_t *options);
-/* Return true iff we believe ourselves to be a v3 authoritative directory
- * server. */
-static inline int
-authdir_mode_v3(const or_options_t *options)
-{
- return authdir_mode(options) && options->V3AuthoritativeDir != 0;
-}
-
+/* Is the dirauth module enabled? */
#define have_module_dirauth() (1)
#else /* !defined(HAVE_MODULE_DIRAUTH) */
diff --git a/src/feature/dirauth/bridgeauth.c b/src/feature/dirauth/bridgeauth.c
index 4aaefc7a6d..b7bf3e4e04 100644
--- a/src/feature/dirauth/bridgeauth.c
+++ b/src/feature/dirauth/bridgeauth.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file bridgeauth.c
+ * @brief Bridge authority code
+ **/
+
#include "core/or/or.h"
#include "feature/dirauth/bridgeauth.h"
#include "feature/dirauth/voteflags.h"
diff --git a/src/feature/dirauth/bridgeauth.h b/src/feature/dirauth/bridgeauth.h
index 4905e9c3ee..382d1cfcb8 100644
--- a/src/feature/dirauth/bridgeauth.h
+++ b/src/feature/dirauth/bridgeauth.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file bridgeauth.h
+ * @brief Header for bridgeauth.c
+ **/
+
#ifndef TOR_DIRAUTH_BRIDGEAUTH_H
#define TOR_DIRAUTH_BRIDGEAUTH_H
diff --git a/src/feature/dirauth/bwauth.c b/src/feature/dirauth/bwauth.c
index e60c8b86bd..ff0c78f018 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,10 +13,12 @@
#include "feature/dirauth/bwauth.h"
#include "app/config/config.h"
+#include "feature/dirauth/dirauth_sys.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/routerlist.h"
#include "feature/dirparse/ns_parse.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/vote_routerstatus_st.h"
@@ -56,7 +58,7 @@ dirserv_get_last_n_measured_bws(void)
}
/** Measured bandwidth cache entry */
-typedef struct mbw_cache_entry_s {
+typedef struct mbw_cache_entry_t {
long mbw_kb;
time_t as_of;
} mbw_cache_entry_t;
@@ -182,7 +184,7 @@ dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri)
/* Check if we have a measured bandwidth, and check the threshold if not */
if (!(dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest,
&mbw_kb, NULL))) {
- threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
+ threshold = dirauth_get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
if (routers_with_measured_bw > threshold) {
/* Return zero for unmeasured bandwidth if we are above threshold */
bw_kb = 0;
diff --git a/src/feature/dirauth/bwauth.h b/src/feature/dirauth/bwauth.h
index 81c8affbd7..849c58e2fc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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
new file mode 100644
index 0000000000..a0b6de7eca
--- /dev/null
+++ b/src/feature/dirauth/dirauth_config.c
@@ -0,0 +1,471 @@
+/* Copyright (c) 2001 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 dirauth_config.c
+ * @brief Code to interpret the user's configuration of Tor's directory
+ * authority module.
+ **/
+
+#include "orconfig.h"
+#include "feature/dirauth/dirauth_config.h"
+
+#include "lib/encoding/confline.h"
+#include "lib/confmgt/confmgt.h"
+#include "lib/conf/confdecl.h"
+
+/* Required for dirinfo_type_t in or_options_t */
+#include "core/or/or.h"
+#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
+
+#include "feature/dirauth/voting_schedule.h"
+#include "feature/stats/rephist.h"
+
+#include "feature/dirauth/authmode.h"
+#include "feature/dirauth/bwauth.h"
+#include "feature/dirauth/dirauth_periodic.h"
+#include "feature/dirauth/dirauth_sys.h"
+#include "feature/dirauth/dirvote.h"
+#include "feature/dirauth/guardfraction.h"
+#include "feature/dirauth/dirauth_options_st.h"
+
+/* Copied from config.c, we will refactor later in 29211. */
+#define REJECT(arg) \
+ STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
+#if defined(__GNUC__) && __GNUC__ <= 3
+#define COMPLAIN(args...) \
+ STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END
+#else
+#define COMPLAIN(args, ...) \
+ STMT_BEGIN log_warn(LD_CONFIG, args, ##__VA_ARGS__); STMT_END
+#endif /* defined(__GNUC__) && __GNUC__ <= 3 */
+
+#define YES_IF_CHANGED_INT(opt) \
+ if (!CFG_EQ_INT(old_options, new_options, opt)) return 1;
+
+/** Return true iff we are configured to reject request under load for non
+ * relay connections. */
+bool
+dirauth_should_reject_requests_under_load(void)
+{
+ return !!dirauth_get_options()->AuthDirRejectRequestsUnderLoad;
+}
+
+/**
+ * Legacy validation/normalization function for the dirauth mode options in
+ * options. Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_dirauth_mode(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (!authdir_mode(options))
+ return 0;
+
+ /* confirm that our address isn't broken, so we can complain now */
+ uint32_t tmp;
+ if (resolve_my_address(LOG_WARN, options, &tmp, NULL, NULL) < 0)
+ REJECT("Failed to resolve/guess local address. See logs for details.");
+
+ if (!options->ContactInfo && !options->TestingTorNetwork)
+ REJECT("Authoritative directory servers must set ContactInfo");
+
+ if (options->UseEntryGuards) {
+ log_info(LD_CONFIG, "Authoritative directory servers can't set "
+ "UseEntryGuards. Disabling.");
+ options->UseEntryGuards = 0;
+ }
+ if (!options->DownloadExtraInfo && authdir_mode_v3(options)) {
+ log_info(LD_CONFIG, "Authoritative directories always try to download "
+ "extra-info documents. Setting DownloadExtraInfo.");
+ options->DownloadExtraInfo = 1;
+ }
+ if (!(options->BridgeAuthoritativeDir ||
+ options->V3AuthoritativeDir))
+ REJECT("AuthoritativeDir is set, but none of "
+ "(Bridge/V3)AuthoritativeDir is set.");
+
+ /* If we have a v3bandwidthsfile and it's broken, complain on startup */
+ if (options->V3BandwidthsFile && !old_options) {
+ dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL,
+ NULL);
+ }
+ /* same for guardfraction file */
+ if (options->GuardfractionFile && !old_options) {
+ dirserv_read_guardfraction_file(options->GuardfractionFile, NULL);
+ }
+
+ if (!options->DirPort_set)
+ REJECT("Running as authoritative directory, but no DirPort set.");
+
+ if (!options->ORPort_set)
+ REJECT("Running as authoritative directory, but no ORPort set.");
+
+ if (options->ClientOnly)
+ REJECT("Running as authoritative directory, but ClientOnly also set.");
+
+ return 0;
+}
+
+/**
+ * Legacy validation/normalization function for the dirauth schedule options
+ * in options. Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_dirauth_schedule(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (!authdir_mode_v3(options))
+ return 0;
+
+ if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
+ options->V3AuthVotingInterval/2) {
+ REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
+ "V3AuthVotingInterval");
+ }
+
+ if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) {
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS_TESTING) {
+ REJECT("V3AuthVoteDelay is way too low.");
+ } else {
+ COMPLAIN("V3AuthVoteDelay is very low. "
+ "This may lead to failure to vote for a consensus.");
+ }
+ } else {
+ REJECT("V3AuthVoteDelay is way too low.");
+ }
+ }
+
+ if (options->V3AuthDistDelay < MIN_DIST_SECONDS) {
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthDistDelay < MIN_DIST_SECONDS_TESTING) {
+ REJECT("V3AuthDistDelay is way too low.");
+ } else {
+ COMPLAIN("V3AuthDistDelay is very low. "
+ "This may lead to missing votes in a consensus.");
+ }
+ } else {
+ REJECT("V3AuthDistDelay is way too low.");
+ }
+ }
+
+ if (options->V3AuthNIntervalsValid < 2)
+ REJECT("V3AuthNIntervalsValid must be at least 2.");
+
+ if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) {
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL_TESTING) {
+ /* Unreachable, covered by earlier checks */
+ REJECT("V3AuthVotingInterval is insanely low."); /* LCOV_EXCL_LINE */
+ } else {
+ COMPLAIN("V3AuthVotingInterval is very low. "
+ "This may lead to failure to synchronise for a consensus.");
+ }
+ } else {
+ REJECT("V3AuthVotingInterval is insanely low.");
+ }
+ } else if (options->V3AuthVotingInterval > 24*60*60) {
+ REJECT("V3AuthVotingInterval is insanely high.");
+ } else if (((24*60*60) % options->V3AuthVotingInterval) != 0) {
+ COMPLAIN("V3AuthVotingInterval does not divide evenly into 24 hours.");
+ }
+
+ return 0;
+}
+
+/**
+ * Legacy validation/normalization function for the dirauth testing options
+ * in options. Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_dirauth_testing(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (!authdir_mode(options))
+ return 0;
+
+ if (!authdir_mode_v3(options))
+ return 0;
+
+ if (options->TestingV3AuthInitialVotingInterval
+ < MIN_VOTE_INTERVAL_TESTING_INITIAL) {
+ REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
+ } else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) {
+ REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into "
+ "30 minutes.");
+ }
+
+ if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS_TESTING) {
+ REJECT("TestingV3AuthInitialVoteDelay is way too low.");
+ }
+
+ if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS_TESTING) {
+ REJECT("TestingV3AuthInitialDistDelay is way too low.");
+ }
+
+ if (options->TestingV3AuthInitialVoteDelay +
+ options->TestingV3AuthInitialDistDelay >=
+ options->TestingV3AuthInitialVotingInterval) {
+ REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay "
+ "must be less than TestingV3AuthInitialVotingInterval");
+ }
+
+ if (options->TestingV3AuthVotingStartOffset >
+ MIN(options->TestingV3AuthInitialVotingInterval,
+ options->V3AuthVotingInterval)) {
+ REJECT("TestingV3AuthVotingStartOffset is higher than the voting "
+ "interval.");
+ } else if (options->TestingV3AuthVotingStartOffset < 0) {
+ REJECT("TestingV3AuthVotingStartOffset must be non-negative.");
+ }
+
+ return 0;
+}
+
+/**
+ * Return true if changing the configuration from <b>old</b> to <b>new</b>
+ * affects the timing of the voting subsystem
+ */
+static int
+options_transition_affects_dirauth_timing(const or_options_t *old_options,
+ const or_options_t *new_options)
+{
+ tor_assert(old_options);
+ tor_assert(new_options);
+
+ if (authdir_mode_v3(old_options) != authdir_mode_v3(new_options))
+ return 1;
+ if (! authdir_mode_v3(new_options))
+ return 0;
+
+ YES_IF_CHANGED_INT(V3AuthVotingInterval);
+ YES_IF_CHANGED_INT(V3AuthVoteDelay);
+ YES_IF_CHANGED_INT(V3AuthDistDelay);
+ YES_IF_CHANGED_INT(TestingV3AuthInitialVotingInterval);
+ YES_IF_CHANGED_INT(TestingV3AuthInitialVoteDelay);
+ YES_IF_CHANGED_INT(TestingV3AuthInitialDistDelay);
+ YES_IF_CHANGED_INT(TestingV3AuthVotingStartOffset);
+
+ return 0;
+}
+
+/** Fetch the active option list, and take dirauth actions based on it. All of
+ * the things we do should survive being done repeatedly. If present,
+ * <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_dirauth(const or_options_t *old_options)
+{
+ const or_options_t *options = get_options();
+
+ /* We may need to reschedule some dirauth stuff if our status changed. */
+ if (old_options) {
+ if (options_transition_affects_dirauth_timing(old_options, options)) {
+ dirauth_sched_recalculate_timing(options, time(NULL));
+ reschedule_dirvote(options);
+ }
+ }
+
+ return 0;
+}
+
+/** Fetch the active option list, and take dirauth mtbf actions based on it.
+ * All of the things we do should survive being done repeatedly. If present,
+ * <b>old_options</b> contains the previous value of the options.
+ *
+ * Must be called immediately after a successful or_state_load().
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_dirauth_mtbf(const or_options_t *old_options)
+{
+ (void)old_options;
+
+ const or_options_t *options = get_options();
+ int running_tor = options->command == CMD_RUN_TOR;
+
+ if (!authdir_mode(options))
+ return 0;
+
+ /* Load dirauth state */
+ if (running_tor) {
+ rep_hist_load_mtbf_data(time(NULL));
+ }
+
+ return 0;
+}
+
+/** Fetch the active option list, and take dirauth statistics actions based
+ * on it. All of the things we do should survive being done repeatedly. If
+ * present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Sets <b>*print_notice_out</b> if we enabled stats, and need to print
+ * a stats log using options_act_relay_stats_msg().
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_dirauth_stats(const or_options_t *old_options,
+ bool *print_notice_out)
+{
+ if (BUG(!print_notice_out))
+ return -1;
+
+ const or_options_t *options = get_options();
+
+ if (authdir_mode_bridge(options)) {
+ time_t now = time(NULL);
+ int print_notice = 0;
+
+ if (!old_options || !authdir_mode_bridge(old_options)) {
+ rep_hist_desc_stats_init(now);
+ print_notice = 1;
+ }
+ if (print_notice)
+ *print_notice_out = 1;
+ }
+
+ /* If we used to have statistics enabled but we just disabled them,
+ stop gathering them. */
+ if (old_options && authdir_mode_bridge(old_options) &&
+ !authdir_mode_bridge(options))
+ rep_hist_desc_stats_term();
+
+ return 0;
+}
+
+/**
+ * Make any necessary modifications to a dirauth_options_t that occur
+ * before validation. On success return 0; on failure return -1 and
+ * set *<b>msg_out</b> to a newly allocated error string.
+ **/
+static int
+dirauth_options_pre_normalize(void *arg, char **msg_out)
+{
+ dirauth_options_t *options = arg;
+ (void)msg_out;
+
+ if (!options->RecommendedClientVersions)
+ options->RecommendedClientVersions =
+ config_lines_dup(options->RecommendedVersions);
+ if (!options->RecommendedServerVersions)
+ options->RecommendedServerVersions =
+ config_lines_dup(options->RecommendedVersions);
+
+ if (config_ensure_bandwidth_cap(&options->AuthDirFastGuarantee,
+ "AuthDirFastGuarantee", msg_out) < 0)
+ return -1;
+ if (config_ensure_bandwidth_cap(&options->AuthDirGuardBWGuarantee,
+ "AuthDirGuardBWGuarantee", msg_out) < 0)
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Check whether a dirauth_options_t is correct.
+ *
+ * On success return 0; on failure return -1 and set *<b>msg_out</b> to a
+ * newly allocated error string.
+ **/
+static int
+dirauth_options_validate(const void *arg, char **msg)
+{
+ const dirauth_options_t *options = arg;
+
+ if (options->VersioningAuthoritativeDirectory &&
+ (!options->RecommendedClientVersions ||
+ !options->RecommendedServerVersions)) {
+ REJECT("Versioning authoritative dir servers must set "
+ "Recommended*Versions.");
+ }
+
+ char *t;
+ /* Call these functions to produce warnings only. */
+ t = format_recommended_version_list(options->RecommendedClientVersions, 1);
+ tor_free(t);
+ t = format_recommended_version_list(options->RecommendedServerVersions, 1);
+ tor_free(t);
+
+ if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) {
+ COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high.");
+ }
+
+ return 0;
+}
+
+/* Declare the options field table for dirauth_options */
+#define CONF_CONTEXT TABLE
+#include "feature/dirauth/dirauth_options.inc"
+#undef CONF_CONTEXT
+
+/** Magic number for dirauth_options_t. */
+#define DIRAUTH_OPTIONS_MAGIC 0x41757448
+
+/**
+ * Declare the configuration options for the dirauth module.
+ **/
+const config_format_t dirauth_options_fmt = {
+ .size = sizeof(dirauth_options_t),
+ .magic = { "dirauth_options_t",
+ DIRAUTH_OPTIONS_MAGIC,
+ offsetof(dirauth_options_t, magic) },
+ .vars = dirauth_options_t_vars,
+
+ .pre_normalize_fn = dirauth_options_pre_normalize,
+ .validate_fn = dirauth_options_validate
+};
diff --git a/src/feature/dirauth/dirauth_config.h b/src/feature/dirauth/dirauth_config.h
new file mode 100644
index 0000000000..9042ff8779
--- /dev/null
+++ b/src/feature/dirauth/dirauth_config.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2001 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 dirauth_config.h
+ * @brief Header for feature/dirauth/dirauth_config.c
+ **/
+
+#ifndef TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H
+#define TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H
+
+struct or_options_t;
+
+#ifdef HAVE_MODULE_DIRAUTH
+
+#include "lib/cc/torint.h"
+
+int options_validate_dirauth_mode(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_validate_dirauth_schedule(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_validate_dirauth_testing(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_act_dirauth(const struct or_options_t *old_options);
+int options_act_dirauth_mtbf(const struct or_options_t *old_options);
+int options_act_dirauth_stats(const struct or_options_t *old_options,
+ bool *print_notice_out);
+
+bool dirauth_should_reject_requests_under_load(void);
+
+extern const struct config_format_t dirauth_options_fmt;
+
+#else /* !defined(HAVE_MODULE_DIRAUTH) */
+
+/** When tor is compiled with the dirauth module disabled, it can't be
+ * configured as a directory authority.
+ *
+ * Returns -1 and sets msg to a newly allocated string, if AuthoritativeDir
+ * is set in options. Otherwise returns 0. */
+static inline int
+options_validate_dirauth_mode(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ /* Only check the primary option for now, #29211 will disable more
+ * options. */
+ if (options->AuthoritativeDir) {
+ /* REJECT() this configuration */
+ *msg = tor_strdup("This tor was built with dirauth mode disabled. "
+ "It can not be configured with AuthoritativeDir 1.");
+ return -1;
+ }
+
+ return 0;
+}
+
+#define options_validate_dirauth_schedule(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+#define options_validate_dirauth_testing(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+
+#define options_act_dirauth(old_options) \
+ (((void)(old_options)),0)
+#define options_act_dirauth_mtbf(old_options) \
+ (((void)(old_options)),0)
+
+static inline int
+options_act_dirauth_stats(const struct or_options_t *old_options,
+ bool *print_notice_out)
+{
+ (void)old_options;
+ *print_notice_out = 0;
+ return 0;
+}
+
+#define dirauth_should_reject_requests_under_load() (false)
+
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
+
+#endif /* !defined(TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H) */
diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc
new file mode 100644
index 0000000000..21f4996c39
--- /dev/null
+++ b/src/feature/dirauth/dirauth_options.inc
@@ -0,0 +1,105 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dirauth_options.inc
+ * @brief Declare configuration options for the crypto_ops module.
+ **/
+
+/** Holds configuration about our directory authority options. */
+BEGIN_CONF_STRUCT(dirauth_options_t)
+
+/** If non-zero, always vote the Fast flag for any relay advertising
+ * this amount of capacity or more. */
+CONF_VAR(AuthDirFastGuarantee, MEMUNIT, 0, "100 KB")
+
+/** If non-zero, this advertised capacity or more is always sufficient
+ * to satisfy the bandwidth requirement for the Guard flag. */
+CONF_VAR(AuthDirGuardBWGuarantee, MEMUNIT, 0, "2 MB")
+
+/** Boolean: are we on IPv6? */
+CONF_VAR(AuthDirHasIPv6Connectivity, BOOL, 0, "0")
+
+/** True iff we should list bad exits, and vote for all other exits as
+ * good. */
+CONF_VAR(AuthDirListBadExits, BOOL, 0, "0")
+
+/** Do not permit more than this number of servers per IP address. */
+CONF_VAR(AuthDirMaxServersPerAddr, POSINT, 0, "2")
+
+/** Boolean: Do we enforce key-pinning? */
+CONF_VAR(AuthDirPinKeys, BOOL, 0, "1")
+
+/** Bool (default: 1): Switch for the shared random protocol. Only
+ * relevant to a directory authority. If off, the authority won't
+ * participate in the protocol. If on (default), a flag is added to the
+ * vote indicating participation. */
+CONF_VAR(AuthDirSharedRandomness, BOOL, 0, "1")
+
+/** Bool (default: 1): When testing routerinfos as a directory authority,
+ * do we enforce Ed25519 identity match? */
+/* NOTE: remove this option someday. */
+CONF_VAR(AuthDirTestEd25519LinkKeys, BOOL, 0, "1")
+
+/** Authority only: key=value pairs that we add to our networkstatus
+ * consensus vote on the 'params' line. */
+CONF_VAR(ConsensusParams, STRING, 0, NULL)
+
+/** Authority only: minimum number of measured bandwidths we must see
+ * before we only believe measured bandwidths to assign flags. */
+CONF_VAR(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, 0, "500")
+
+/** As directory authority, accept hidden service directories after what
+ * time? */
+CONF_VAR(MinUptimeHidServDirectoryV2, INTERVAL, 0, "96 hours")
+
+/** Which versions of tor should we tell users to run? */
+CONF_VAR(RecommendedVersions, LINELIST, 0, NULL)
+
+/** Which versions of tor should we tell users to run on clients? */
+CONF_VAR(RecommendedClientVersions, LINELIST, 0, NULL)
+
+/** Which versions of tor should we tell users to run on relays? */
+CONF_VAR(RecommendedServerVersions, LINELIST, 0, NULL)
+
+/** 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. */
+CONF_VAR(TestingAuthDirTimeToLearnReachability, INTERVAL, 0, "30 minutes")
+
+ /** Relays in a testing network which should be voted Exit
+ * regardless of exit policy. */
+CONF_VAR(TestingDirAuthVoteExit, ROUTERSET, 0, NULL)
+CONF_VAR(TestingDirAuthVoteExitIsStrict, BOOL, 0, "0")
+
+/** Relays in a testing network which should be voted Guard
+ * regardless of uptime and bandwidth. */
+CONF_VAR(TestingDirAuthVoteGuard, ROUTERSET, 0, NULL)
+CONF_VAR(TestingDirAuthVoteGuardIsStrict, BOOL, 0, "0")
+
+/** Relays in a testing network which should be voted HSDir
+ * regardless of uptime and DirPort. */
+CONF_VAR(TestingDirAuthVoteHSDir, ROUTERSET, 0, NULL)
+CONF_VAR(TestingDirAuthVoteHSDirIsStrict, BOOL, 0, "0")
+
+/** Minimum value for the Exit flag threshold on testing networks. */
+CONF_VAR(TestingMinExitFlagThreshold, MEMUNIT, 0, "0")
+
+/** Minimum value for the Fast flag threshold on testing networks. */
+CONF_VAR(TestingMinFastFlagThreshold, MEMUNIT, 0, "0")
+
+/** Boolean: is this an authoritative directory that's willing to recommend
+ * versions? */
+CONF_VAR(VersioningAuthoritativeDirectory, BOOL, 0, "0")
+
+/** Boolean: Under bandwidth pressure, if set to 1, the authority will always
+ * answer directory requests from relays but will start sending 503 error code
+ * for the other connections. If set to 0, all connections are considered the
+ * same and the authority will try to answer them all regardless of bandwidth
+ * pressure or not. */
+CONF_VAR(AuthDirRejectRequestsUnderLoad, BOOL, 0, "1")
+
+END_CONF_STRUCT(dirauth_options_t)
diff --git a/src/feature/dirauth/dirauth_options_st.h b/src/feature/dirauth/dirauth_options_st.h
new file mode 100644
index 0000000000..02a498c054
--- /dev/null
+++ b/src/feature/dirauth/dirauth_options_st.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dirauth_options_st.h
+ * @brief Structure dirauth_options_t to hold directory authority options.
+ **/
+
+#ifndef TOR_FEATURE_DIRAUTH_DIRAUTH_OPTIONS_ST_H
+#define TOR_FEATURE_DIRAUTH_DIRAUTH_OPTIONS_ST_H
+
+#include "lib/conf/confdecl.h"
+#include "feature/nodelist/routerset.h"
+
+#define CONF_CONTEXT STRUCT
+#include "feature/dirauth/dirauth_options.inc"
+#undef CONF_CONTEXT
+
+typedef struct dirauth_options_t dirauth_options_t;
+
+#endif /* !defined(TOR_FEATURE_DIRAUTH_DIRAUTH_OPTIONS_ST_H) */
diff --git a/src/feature/dirauth/dirauth_periodic.c b/src/feature/dirauth/dirauth_periodic.c
index 02727d61b4..19e51c5a05 100644
--- a/src/feature/dirauth/dirauth_periodic.c
+++ b/src/feature/dirauth/dirauth_periodic.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dirauth_periodic.c
+ * @brief Peridoic events for directory authorities.
+ **/
+
#include "core/or/or.h"
#include "app/config/or_options_st.h"
@@ -18,11 +23,13 @@
#include "core/mainloop/periodic.h"
+#ifndef COCCI
#define DECLARE_EVENT(name, roles, flags) \
static periodic_event_item_t name ## _event = \
PERIODIC_EVENT(name, \
PERIODIC_EVENT_ROLE_##roles, \
flags)
+#endif /* !defined(COCCI) */
#define FL(name) (PERIODIC_EVENT_FLAG_##name)
diff --git a/src/feature/dirauth/dirauth_periodic.h b/src/feature/dirauth/dirauth_periodic.h
index 866fbd35de..ccdda92a77 100644
--- a/src/feature/dirauth/dirauth_periodic.h
+++ b/src/feature/dirauth/dirauth_periodic.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dirauth_periodic.h
+ * @brief Header for dirauth_periodic.c
+ **/
+
#ifndef DIRVOTE_PERIODIC_H
#define DIRVOTE_PERIODIC_H
diff --git a/src/feature/dirauth/dirauth_stub.c b/src/feature/dirauth/dirauth_stub.c
new file mode 100644
index 0000000000..9f48ce14fd
--- /dev/null
+++ b/src/feature/dirauth/dirauth_stub.c
@@ -0,0 +1,34 @@
+/* Copyright (c) 2001 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 dirauth_stub.c
+ * @brief Stub declarations for use when dirauth module is disabled.
+ **/
+
+#include "orconfig.h"
+#include "feature/dirauth/dirauth_sys.h"
+#include "lib/conf/conftypes.h"
+#include "lib/conf/confdecl.h"
+#include "lib/subsys/subsys.h"
+
+/* Declare the options field table for dirauth_options */
+#define CONF_CONTEXT STUB_TABLE
+#include "feature/dirauth/dirauth_options.inc"
+#undef CONF_CONTEXT
+
+static const config_format_t dirauth_options_stub_fmt = {
+ .vars = dirauth_options_t_vars,
+};
+
+const struct subsys_fns_t sys_dirauth = {
+ .name = "dirauth",
+ SUBSYS_DECLARE_LOCATION(),
+ .supported = false,
+ .level = DIRAUTH_SUBSYS_LEVEL,
+
+ .options_format = &dirauth_options_stub_fmt
+};
diff --git a/src/feature/dirauth/dirauth_sys.c b/src/feature/dirauth/dirauth_sys.c
index e38d391300..07c5743877 100644
--- a/src/feature/dirauth/dirauth_sys.c
+++ b/src/feature/dirauth/dirauth_sys.c
@@ -1,20 +1,31 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dirauth_sys.c
+ * @brief Directory authority subsystem declarations
+ **/
+
#include "core/or/or.h"
+#define DIRAUTH_SYS_PRIVATE
#include "feature/dirauth/bwauth.h"
#include "feature/dirauth/dirauth_sys.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/dirauth_periodic.h"
#include "feature/dirauth/keypin.h"
#include "feature/dirauth/process_descs.h"
+#include "feature/dirauth/dirauth_config.h"
+
+#include "feature/dirauth/dirauth_options_st.h"
#include "lib/subsys/subsys.h"
+static const dirauth_options_t *global_dirauth_options;
+
static int
subsys_dirauth_initialize(void)
{
@@ -29,12 +40,32 @@ subsys_dirauth_shutdown(void)
dirvote_free_all();
dirserv_clear_measured_bw_cache();
keypin_close_journal();
+ global_dirauth_options = NULL;
+}
+
+const dirauth_options_t *
+dirauth_get_options(void)
+{
+ tor_assert(global_dirauth_options);
+ return global_dirauth_options;
+}
+
+STATIC int
+dirauth_set_options(void *arg)
+{
+ dirauth_options_t *opts = arg;
+ global_dirauth_options = opts;
+ return 0;
}
const struct subsys_fns_t sys_dirauth = {
.name = "dirauth",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
- .level = 70,
+ .level = DIRAUTH_SUBSYS_LEVEL,
.initialize = subsys_dirauth_initialize,
.shutdown = subsys_dirauth_shutdown,
+
+ .options_format = &dirauth_options_fmt,
+ .set_options = dirauth_set_options,
};
diff --git a/src/feature/dirauth/dirauth_sys.h b/src/feature/dirauth/dirauth_sys.h
index 4e9b6a2ab4..c512b91b33 100644
--- a/src/feature/dirauth/dirauth_sys.h
+++ b/src/feature/dirauth/dirauth_sys.h
@@ -1,12 +1,32 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dirauth_sys.h
+ * @brief Header for dirauth_sys.c
+ **/
+
#ifndef DIRAUTH_SYS_H
#define DIRAUTH_SYS_H
+struct dirauth_options_t;
+const struct dirauth_options_t *dirauth_get_options(void);
+
extern const struct subsys_fns_t sys_dirauth;
+/**
+ * Subsystem level for the directory-authority system.
+ *
+ * Defined here so that it can be shared between the real and stub
+ * definitions.
+ **/
+#define DIRAUTH_SUBSYS_LEVEL 70
+
+#ifdef DIRAUTH_SYS_PRIVATE
+STATIC int dirauth_set_options(void *arg);
+#endif
+
#endif /* !defined(DIRAUTH_SYS_H) */
diff --git a/src/feature/dirauth/dircollate.c b/src/feature/dirauth/dircollate.c
index 7992e3a85f..2657f53853 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -32,8 +32,8 @@ static void dircollator_collate_by_ed25519(dircollator_t *dc);
/** Hashtable entry mapping a pair of digests (actually an ed25519 key and an
* RSA SHA1 digest) to an array of vote_routerstatus_t. */
-typedef struct ddmap_entry_s {
- HT_ENTRY(ddmap_entry_s) node;
+typedef struct ddmap_entry_t {
+ HT_ENTRY(ddmap_entry_t) node;
/** A SHA1-RSA1024 identity digest and Ed25519 identity key,
* concatenated. (If there is no ed25519 identity key, there is no
* entry in this table.) */
@@ -89,10 +89,10 @@ ddmap_entry_set_digests(ddmap_entry_t *ent,
memcpy(ent->d + DIGEST_LEN, ed25519, DIGEST256_LEN);
}
-HT_PROTOTYPE(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash,
- ddmap_entry_eq)
-HT_GENERATE2(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash,
- ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_)
+HT_PROTOTYPE(double_digest_map, ddmap_entry_t, node, ddmap_entry_hash,
+ ddmap_entry_eq);
+HT_GENERATE2(double_digest_map, ddmap_entry_t, node, ddmap_entry_hash,
+ ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_);
/** Helper: add a single vote_routerstatus_t <b>vrs</b> to the collator
* <b>dc</b>, indexing it by its RSA key digest, and by the 2-tuple of its RSA
@@ -324,4 +324,3 @@ dircollator_get_votes_for_router(dircollator_t *dc, int idx)
return digestmap_get(dc->by_collated_rsa_sha1,
smartlist_get(dc->all_rsa_sha1_lst, idx));
}
-
diff --git a/src/feature/dirauth/dircollate.h b/src/feature/dirauth/dircollate.h
index 754a094817..90c6bddad5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,7 +15,7 @@
#include "lib/testsupport/testsupport.h"
#include "core/or/or.h"
-typedef struct dircollator_s dircollator_t;
+typedef struct dircollator_t dircollator_t;
dircollator_t *dircollator_new(int n_votes, int n_authorities);
void dircollator_free_(dircollator_t *obj);
@@ -30,11 +30,11 @@ vote_routerstatus_t **dircollator_get_votes_for_router(dircollator_t *dc,
int idx);
#ifdef DIRCOLLATE_PRIVATE
-struct ddmap_entry_s;
-typedef HT_HEAD(double_digest_map, ddmap_entry_s) double_digest_map_t;
+struct ddmap_entry_t;
+typedef HT_HEAD(double_digest_map, ddmap_entry_t) double_digest_map_t;
/** A dircollator keeps track of all the routerstatus entries in a
* set of networkstatus votes, and matches them by an appropriate rule. */
-struct dircollator_s {
+struct dircollator_t {
/** True iff we have run the collation algorithm. */
int is_collated;
/** The total number of votes that we received. */
diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index 043bbfc227..79651563b4 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -1,11 +1,12 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DIRVOTE_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/or/policies.h"
#include "core/or/protover.h"
#include "core/or/tor_version_st.h"
@@ -36,15 +37,17 @@
#include "feature/stats/rephist.h"
#include "feature/client/entrynodes.h" /* needed for guardfraction methods */
#include "feature/nodelist/torcert.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/authmode.h"
#include "feature/dirauth/shared_random_state.h"
+#include "feature/dirauth/dirauth_sys.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/dircache/cached_dir_st.h"
#include "feature/dirclient/dir_server_st.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/document_signature_st.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -319,43 +322,47 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
tor_free(digest_algo_b64_digest_bw_file);
}
- smartlist_add_asprintf(chunks,
- "network-status-version 3\n"
- "vote-status %s\n"
- "consensus-methods %s\n"
- "published %s\n"
- "valid-after %s\n"
- "fresh-until %s\n"
- "valid-until %s\n"
- "voting-delay %d %d\n"
- "%s%s" /* versions */
- "%s" /* protocols */
- "known-flags %s\n"
- "flag-thresholds %s\n"
- "params %s\n"
- "%s" /* bandwidth file headers */
- "%s" /* bandwidth file digest */
- "dir-source %s %s %s %s %d %d\n"
- "contact %s\n"
- "%s" /* shared randomness information */
- ,
- v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion",
- methods,
- published, va, fu, vu,
- v3_ns->vote_seconds, v3_ns->dist_seconds,
- client_versions_line,
- server_versions_line,
- protocols_lines,
- flags,
- flag_thresholds,
- params,
- bw_headers_line ? bw_headers_line : "",
- bw_file_digest ? bw_file_digest: "",
- voter->nickname, fingerprint, voter->address,
- fmt_addr32(addr), voter->dir_port, voter->or_port,
- voter->contact,
- shared_random_vote_str ?
- shared_random_vote_str : "");
+ const char *ip_str = fmt_addr32(addr);
+
+ if (ip_str[0]) {
+ smartlist_add_asprintf(chunks,
+ "network-status-version 3\n"
+ "vote-status %s\n"
+ "consensus-methods %s\n"
+ "published %s\n"
+ "valid-after %s\n"
+ "fresh-until %s\n"
+ "valid-until %s\n"
+ "voting-delay %d %d\n"
+ "%s%s" /* versions */
+ "%s" /* protocols */
+ "known-flags %s\n"
+ "flag-thresholds %s\n"
+ "params %s\n"
+ "%s" /* bandwidth file headers */
+ "%s" /* bandwidth file digest */
+ "dir-source %s %s %s %s %d %d\n"
+ "contact %s\n"
+ "%s" /* shared randomness information */
+ ,
+ v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion",
+ methods,
+ published, va, fu, vu,
+ v3_ns->vote_seconds, v3_ns->dist_seconds,
+ client_versions_line,
+ server_versions_line,
+ protocols_lines,
+ flags,
+ flag_thresholds,
+ params,
+ bw_headers_line ? bw_headers_line : "",
+ bw_file_digest ? bw_file_digest: "",
+ voter->nickname, fingerprint, voter->address,
+ ip_str, voter->dir_port, voter->or_port,
+ voter->contact,
+ shared_random_vote_str ?
+ shared_random_vote_str : "");
+ }
tor_free(params);
tor_free(flags);
@@ -365,6 +372,9 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
tor_free(bw_headers_line);
tor_free(bw_file_digest);
+ if (ip_str[0] == '\0')
+ goto err;
+
if (!tor_digest_is_zero(voter->legacy_id_digest)) {
char fpbuf[HEX_DIGEST_LEN+1];
base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN);
@@ -382,7 +392,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
rsf = routerstatus_format_entry(&vrs->status,
vrs->version, vrs->protocols,
NS_V3_VOTE,
- ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD,
vrs);
if (rsf)
smartlist_add(chunks, rsf);
@@ -885,7 +894,7 @@ dirvote_get_intermediate_param_value(const smartlist_t *param_list,
int ok;
value = (int32_t)
tor_parse_long(integer_str, 10, INT32_MIN, INT32_MAX, &ok, NULL);
- if (BUG(! ok))
+ if (BUG(!ok))
return default_val;
++n_found;
}
@@ -1538,14 +1547,11 @@ networkstatus_compute_consensus(smartlist_t *votes,
consensus_method = MAX_SUPPORTED_CONSENSUS_METHOD;
}
- if (consensus_method >= MIN_METHOD_FOR_INIT_BW_WEIGHTS_ONE) {
+ {
/* It's smarter to initialize these weights to 1, so that later on,
* we can't accidentally divide by zero. */
G = M = E = D = 1;
T = 4;
- } else {
- /* ...but originally, they were set to zero. */
- G = M = E = D = T = 0;
}
/* Compute medians of time-related things, and figure out how many
@@ -2246,7 +2252,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
/* Okay!! Now we can write the descriptor... */
/* First line goes into "buf". */
buf = routerstatus_format_entry(&rs_out, NULL, NULL,
- rs_format, consensus_method, NULL);
+ rs_format, NULL);
if (buf)
smartlist_add(chunks, buf);
}
@@ -2266,8 +2272,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add_strdup(chunks, chosen_version);
}
smartlist_add_strdup(chunks, "\n");
- if (chosen_protocol_list &&
- consensus_method >= MIN_METHOD_FOR_RS_PROTOCOLS) {
+ if (chosen_protocol_list) {
smartlist_add_asprintf(chunks, "pr %s\n", chosen_protocol_list);
}
/* Now the weight line. */
@@ -2530,9 +2535,12 @@ compute_consensus_package_lines(smartlist_t *votes)
* any new signatures in <b>src_voter_list</b> that should be added to
* <b>target</b>. (A signature should be added if we have no signature for that
* voter in <b>target</b> yet, or if we have no verifiable signature and the
- * new signature is verifiable.) Return the number of signatures added or
- * changed, or -1 if the document signed by <b>sigs</b> isn't the same
- * document as <b>target</b>. */
+ * new signature is verifiable.)
+ *
+ * Return the number of signatures added or changed, or -1 if the document
+ * signatures are invalid. Sets *<b>msg_out</b> to a string constant
+ * describing the signature status.
+ */
STATIC int
networkstatus_add_detached_signatures(networkstatus_t *target,
ns_detached_signatures_t *sigs,
@@ -2853,7 +2861,7 @@ dirvote_act(const or_options_t *options, time_t now)
"Mine is %s.",
keys, hex_str(c->cache_info.identity_digest, DIGEST_LEN));
tor_free(keys);
- voting_schedule_recalculate_timing(options, now);
+ dirauth_sched_recalculate_timing(options, now);
}
#define IF_TIME_FOR_NEXT_ACTION(when_field, done_field) \
@@ -2899,7 +2907,7 @@ dirvote_act(const or_options_t *options, time_t now)
networkstatus_get_latest_consensus_by_flavor(FLAV_NS));
/* XXXX We will want to try again later if we haven't got enough
* signatures yet. Implement this if it turns out to ever happen. */
- voting_schedule_recalculate_timing(options, now);
+ dirauth_sched_recalculate_timing(options, now);
return voting_schedule.voting_starts;
} ENDIF
@@ -2966,7 +2974,7 @@ dirvote_perform_vote(void)
if (!contents)
return -1;
- pending_vote = dirvote_add_vote(contents, &msg, &status);
+ pending_vote = dirvote_add_vote(contents, 0, &msg, &status);
tor_free(contents);
if (!pending_vote) {
log_warn(LD_DIR, "Couldn't store my own vote! (I told myself, '%s'.)",
@@ -3122,13 +3130,45 @@ list_v3_auth_ids(void)
return keys;
}
+/* Check the voter information <b>vi</b>, and assert that at least one
+ * signature is good. Asserts on failure. */
+static void
+assert_any_sig_good(const networkstatus_voter_info_t *vi)
+{
+ int any_sig_good = 0;
+ SMARTLIST_FOREACH(vi->sigs, document_signature_t *, sig,
+ if (sig->good_signature)
+ any_sig_good = 1);
+ tor_assert(any_sig_good);
+}
+
+/* Add <b>cert</b> to our list of known authority certificates. */
+static void
+add_new_cert_if_needed(const struct authority_cert_t *cert)
+{
+ tor_assert(cert);
+ if (!authority_cert_get_by_digests(cert->cache_info.identity_digest,
+ cert->signing_key_digest)) {
+ /* Hey, it's a new cert! */
+ trusted_dirs_load_certs_from_string(
+ cert->cache_info.signed_descriptor_body,
+ TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/,
+ NULL);
+ if (!authority_cert_get_by_digests(cert->cache_info.identity_digest,
+ cert->signing_key_digest)) {
+ log_warn(LD_BUG, "We added a cert, but still couldn't find it.");
+ }
+ }
+}
+
/** Called when we have received a networkstatus vote in <b>vote_body</b>.
* Parse and validate it, and on success store it as a pending vote (which we
* then return). Return NULL on failure. Sets *<b>msg_out</b> and
* *<b>status_out</b> to an HTTP response and status code. (V3 authority
* only) */
pending_vote_t *
-dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
+dirvote_add_vote(const char *vote_body, time_t time_posted,
+ const char **msg_out, int *status_out)
{
networkstatus_t *vote;
networkstatus_voter_info_t *vi;
@@ -3159,13 +3199,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
}
tor_assert(smartlist_len(vote->voters) == 1);
vi = get_voter(vote);
- {
- int any_sig_good = 0;
- SMARTLIST_FOREACH(vi->sigs, document_signature_t *, sig,
- if (sig->good_signature)
- any_sig_good = 1);
- tor_assert(any_sig_good);
- }
+ assert_any_sig_good(vi);
ds = trusteddirserver_get_by_v3_auth_digest(vi->identity_digest);
if (!ds) {
char *keys = list_v3_auth_ids();
@@ -3178,19 +3212,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
*msg_out = "Vote not from a recognized v3 authority";
goto err;
}
- tor_assert(vote->cert);
- if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest,
- vote->cert->signing_key_digest)) {
- /* Hey, it's a new cert! */
- trusted_dirs_load_certs_from_string(
- vote->cert->cache_info.signed_descriptor_body,
- TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/,
- NULL);
- if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest,
- vote->cert->signing_key_digest)) {
- log_warn(LD_BUG, "We added a cert, but still couldn't find it.");
- }
- }
+ add_new_cert_if_needed(vote->cert);
/* Is it for the right period? */
if (vote->valid_after != voting_schedule.interval_starts) {
@@ -3203,6 +3225,23 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
goto err;
}
+ /* Check if we received it, as a post, after the cutoff when we
+ * start asking other dir auths for it. If we do, the best plan
+ * is to discard it, because using it greatly increases the chances
+ * of a split vote for this round (some dir auths got it in time,
+ * some didn't). */
+ if (time_posted && time_posted > voting_schedule.fetch_missing_votes) {
+ char tbuf1[ISO_TIME_LEN+1], tbuf2[ISO_TIME_LEN+1];
+ format_iso_time(tbuf1, time_posted);
+ format_iso_time(tbuf2, voting_schedule.fetch_missing_votes);
+ log_warn(LD_DIR, "Rejecting posted vote from %s received at %s; "
+ "our cutoff for received votes is %s. Check your clock, "
+ "CPU load, and network load. Also check the authority that "
+ "posted the vote.", vi->address, tbuf1, tbuf2);
+ *msg_out = "Posted vote received too late, would be dangerous to count it";
+ goto err;
+ }
+
/* Fetch any new router descriptors we just learned about */
update_consensus_router_descriptor_downloads(time(NULL), 1, vote);
@@ -3567,6 +3606,14 @@ dirvote_add_signatures_to_pending_consensus(
return r;
}
+/** Helper: we just got the <b>detached_signatures_body</b> sent to us as
+ * signatures on the currently pending consensus. Add them to the pending
+ * consensus (if we have one).
+ *
+ * Set *<b>msg</b> to a string constant describing the status, regardless of
+ * success or failure.
+ *
+ * Return negative on failure, nonnegative on success. */
static int
dirvote_add_signatures_to_all_pending_consensuses(
const char *detached_signatures_body,
@@ -3629,7 +3676,12 @@ dirvote_add_signatures_to_all_pending_consensuses(
/** Helper: we just got the <b>detached_signatures_body</b> sent to us as
* signatures on the currently pending consensus. Add them to the pending
* consensus (if we have one); otherwise queue them until we have a
- * consensus. Return negative on failure, nonnegative on success. */
+ * consensus.
+ *
+ * Set *<b>msg</b> to a string constant describing the status, regardless of
+ * success or failure.
+ *
+ * Return negative on failure, nonnegative on success. */
int
dirvote_add_signatures(const char *detached_signatures_body,
const char *source,
@@ -3803,13 +3855,6 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
}
- /* We originally put a lines in the micrdescriptors, but then we worked out
- * that we needed them in the microdesc consensus. See #20916. */
- if (consensus_method < MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC &&
- !tor_addr_is_null(&ri->ipv6_addr) && ri->ipv6_orport)
- smartlist_add_asprintf(chunks, "a %s\n",
- fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport));
-
if (family) {
if (consensus_method < MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS) {
smartlist_add_asprintf(chunks, "family %s\n", family);
@@ -3915,8 +3960,7 @@ static const struct consensus_method_range_t {
int low;
int high;
} microdesc_consensus_methods[] = {
- {MIN_SUPPORTED_CONSENSUS_METHOD, MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC - 1},
- {MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC,
+ {MIN_SUPPORTED_CONSENSUS_METHOD,
MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1},
{MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS,
MAX_SUPPORTED_CONSENSUS_METHOD},
@@ -4228,7 +4272,7 @@ compare_routerinfo_by_ip_and_bw_(const void **a, const void **b)
static digestmap_t *
get_possible_sybil_list(const smartlist_t *routers)
{
- const or_options_t *options = get_options();
+ const dirauth_options_t *options = dirauth_get_options();
digestmap_t *omit_as_sybil;
smartlist_t *routers_by_ip = smartlist_new();
uint32_t last_addr;
@@ -4417,6 +4461,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
authority_cert_t *cert)
{
const or_options_t *options = get_options();
+ const dirauth_options_t *d_options = dirauth_get_options();
networkstatus_t *v3_out = NULL;
uint32_t addr;
char *hostname = NULL, *client_versions = NULL, *server_versions = NULL;
@@ -4424,7 +4469,7 @@ 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];
- int listbadexits = options->AuthDirListBadExits;
+ const int listbadexits = d_options->AuthDirListBadExits;
routerlist_t *rl = router_get_routerlist();
time_t now = time(NULL);
time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
@@ -4456,11 +4501,16 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
hostname = tor_dup_ip(addr);
}
- if (options->VersioningAuthoritativeDir) {
+ if (!hostname) {
+ log_err(LD_BUG, "Failed to determine hostname AND duplicate address");
+ return NULL;
+ }
+
+ if (d_options->VersioningAuthoritativeDirectory) {
client_versions =
- format_recommended_version_list(options->RecommendedClientVersions, 0);
+ format_recommended_version_list(d_options->RecommendedClientVersions, 0);
server_versions =
- format_recommended_version_list(options->RecommendedServerVersions, 0);
+ format_recommended_version_list(d_options->RecommendedServerVersions, 0);
}
contact = get_options()->ContactInfo;
@@ -4607,7 +4657,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
else
last_consensus_interval = options->TestingV3AuthInitialVotingInterval;
v3_out->valid_after =
- voting_schedule_get_start_of_next_interval(now,
+ voting_sched_get_start_of_interval_after(now,
(int)last_consensus_interval,
options->TestingV3AuthVotingStartOffset);
format_iso_time(tbuf, v3_out->valid_after);
@@ -4629,17 +4679,14 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/* These are hardwired, to avoid disaster. */
v3_out->recommended_relay_protocols =
- tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
- "Link=4 Microdesc=1-2 Relay=2");
+ tor_strdup(DIRVOTE_RECOMMEND_RELAY_PROTO);
v3_out->recommended_client_protocols =
- tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
- "Link=4 Microdesc=1-2 Relay=2");
- v3_out->required_client_protocols =
- tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
- "Link=4 Microdesc=1-2 Relay=2");
+ tor_strdup(DIRVOTE_RECOMMEND_CLIENT_PROTO);
+
v3_out->required_relay_protocols =
- tor_strdup("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
- "Link=3-4 Microdesc=1 Relay=1-2");
+ tor_strdup(DIRVOTE_REQUIRE_RELAY_PROTO);
+ v3_out->required_client_protocols =
+ tor_strdup(DIRVOTE_REQUIRE_CLIENT_PROTO);
/* We are not allowed to vote to require anything we don't have. */
tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL));
@@ -4661,10 +4708,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
smartlist_add_strdup(v3_out->known_flags, "BadExit");
smartlist_sort_strings(v3_out->known_flags);
- if (options->ConsensusParams) {
+ if (d_options->ConsensusParams) {
v3_out->net_params = smartlist_new();
smartlist_split_string(v3_out->net_params,
- options->ConsensusParams, NULL, 0, 0);
+ d_options->ConsensusParams, NULL, 0, 0);
smartlist_sort_strings(v3_out->net_params);
}
v3_out->bw_file_headers = bw_file_headers;
diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h
index b7df33a3a9..1b1c9f2cc7 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -49,36 +49,12 @@
#define MIN_VOTE_INTERVAL_TESTING_INITIAL \
((MIN_VOTE_SECONDS_TESTING)+(MIN_DIST_SECONDS_TESTING)+1)
-/* A placeholder for routerstatus_format_entry() when the consensus method
- * argument is not applicable. */
-#define ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD 0
-
/** The lowest consensus method that we currently support. */
-#define MIN_SUPPORTED_CONSENSUS_METHOD 25
+#define MIN_SUPPORTED_CONSENSUS_METHOD 28
/** The highest consensus method that we currently support. */
#define MAX_SUPPORTED_CONSENSUS_METHOD 29
-/** Lowest consensus method where authorities vote on required/recommended
- * protocols. */
-#define MIN_METHOD_FOR_RECOMMENDED_PROTOCOLS 25
-
-/** Lowest consensus method where authorities add protocols to routerstatus
- * entries. */
-#define MIN_METHOD_FOR_RS_PROTOCOLS 25
-
-/** Lowest consensus method where authorities initialize bandwidth weights to 1
- * instead of 0. See #14881 */
-#define MIN_METHOD_FOR_INIT_BW_WEIGHTS_ONE 26
-
-/** Lowest consensus method where the microdesc consensus contains relay IPv6
- * addresses. See #23826 and #20916. */
-#define MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS 27
-
-/** Lowest consensus method where microdescriptors do not contain relay IPv6
- * addresses. See #23828 and #20916. */
-#define MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC 28
-
/**
* Lowest consensus method where microdescriptor lines are put in canonical
* form for improved compressibility and ease of storage. See proposal 298.
@@ -118,6 +94,7 @@ void dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items,
/* Storing signatures and votes functions */
struct pending_vote_t * dirvote_add_vote(const char *vote_body,
+ time_t time_posted,
const char **msg_out,
int *status_out);
int dirvote_add_signatures(const char *detached_signatures_body,
@@ -166,9 +143,13 @@ dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items,
}
static inline struct pending_vote_t *
-dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
+dirvote_add_vote(const char *vote_body,
+ time_t time_posted,
+ const char **msg_out,
+ int *status_out)
{
(void) vote_body;
+ (void) time_posted;
/* If the dirauth module is disabled, this should NEVER be called else we
* failed to safeguard the dirauth module. */
tor_assert_nonfatal_unreached();
@@ -186,7 +167,7 @@ dirvote_add_signatures(const char *detached_signatures_body,
{
(void) detached_signatures_body;
(void) source;
- (void) msg_out;
+ *msg_out = "No directory authority support";
/* If the dirauth module is disabled, this should NEVER be called else we
* failed to safeguard the dirauth module. */
tor_assert_nonfatal_unreached();
@@ -254,6 +235,36 @@ char *networkstatus_get_detached_signatures(smartlist_t *consensuses);
STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri,
int consensus_method);
+/** The recommended relay protocols for this authority's votes.
+ * Recommending a new protocol causes old tor versions to log a warning.
+ */
+#define DIRVOTE_RECOMMEND_RELAY_PROTO \
+ "Cons=1-2 Desc=1-2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " \
+ "Link=5 LinkAuth=3 Microdesc=1-2 Relay=2"
+/** The recommended client protocols for this authority's votes.
+ * Recommending a new protocol causes old tor versions to log a warning.
+ */
+#define DIRVOTE_RECOMMEND_CLIENT_PROTO \
+ "Cons=1-2 Desc=1-2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " \
+ "Link=5 LinkAuth=3 Microdesc=1-2 Relay=2"
+
+/** The required relay protocols for this authority's votes.
+ * WARNING: Requiring a new protocol causes old tor versions to shut down.
+ * Requiring the wrong protocols can break the tor network.
+ * See Proposal 303: When and how to remove support for protocol versions.
+ */
+#define DIRVOTE_REQUIRE_RELAY_PROTO \
+ "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " \
+ "Link=3-4 Microdesc=1 Relay=1-2"
+/** The required relay protocols for this authority's votes.
+ * WARNING: Requiring a new protocol causes old tor versions to shut down.
+ * Requiring the wrong protocols can break the tor network.
+ * See Proposal 303: When and how to remove support for protocol versions.
+ */
+#define DIRVOTE_REQUIRE_CLIENT_PROTO \
+ "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " \
+ "Link=4 Microdesc=1-2 Relay=2"
+
#endif /* defined(DIRVOTE_PRIVATE) */
#endif /* !defined(TOR_DIRVOTE_H) */
diff --git a/src/feature/dirauth/dsigs_parse.c b/src/feature/dirauth/dsigs_parse.c
index c5c8e18866..d0bb931814 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 0cc53072f8..b25e3e0b28 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/feature_dirauth.md b/src/feature/dirauth/feature_dirauth.md
new file mode 100644
index 0000000000..b152b94894
--- /dev/null
+++ b/src/feature/dirauth/feature_dirauth.md
@@ -0,0 +1,9 @@
+@dir /feature/dirauth
+@brief feature/dirauth: Directory authority implementation.
+
+This module handles running Tor as a directory authority.
+
+The directory protocol is specified in
+[dir-spec.txt](https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt).
+
+
diff --git a/src/feature/dirauth/guardfraction.c b/src/feature/dirauth/guardfraction.c
index d1a7f194d4..b84f804f5f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -188,7 +188,7 @@ guardfraction_file_parse_inputs_line(const char *inputs_line,
*
* guardfraction-file-version 1
* written-at <date and time>
- * n-inputs <number of consesuses parsed> <number of days considered>
+ * n-inputs <number of consensuses parsed> <number of days considered>
*
* guard-seen <fpr 1> <guardfraction percentage> <consensus appearances>
* guard-seen <fpr 2> <guardfraction percentage> <consensus appearances>
diff --git a/src/feature/dirauth/guardfraction.h b/src/feature/dirauth/guardfraction.h
index 9f01ded838..c10fd9b7bb 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,7 +16,7 @@
STATIC int
dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str,
smartlist_t *vote_routerstatuses);
-#endif /* defined(DIRSERV_PRIVATE) */
+#endif
int dirserv_read_guardfraction_file(const char *fname,
smartlist_t *vote_routerstatuses);
diff --git a/src/feature/dirauth/include.am b/src/feature/dirauth/include.am
new file mode 100644
index 0000000000..e26f120d4e
--- /dev/null
+++ b/src/feature/dirauth/include.am
@@ -0,0 +1,54 @@
+
+# The Directory Authority module.
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+MODULE_DIRAUTH_SOURCES = \
+ src/feature/dirauth/authmode.c \
+ src/feature/dirauth/bridgeauth.c \
+ src/feature/dirauth/bwauth.c \
+ src/feature/dirauth/dirauth_config.c \
+ src/feature/dirauth/dirauth_periodic.c \
+ src/feature/dirauth/dirauth_sys.c \
+ src/feature/dirauth/dircollate.c \
+ src/feature/dirauth/dirvote.c \
+ src/feature/dirauth/dsigs_parse.c \
+ src/feature/dirauth/guardfraction.c \
+ src/feature/dirauth/keypin.c \
+ src/feature/dirauth/process_descs.c \
+ src/feature/dirauth/reachability.c \
+ src/feature/dirauth/recommend_pkg.c \
+ src/feature/dirauth/shared_random.c \
+ src/feature/dirauth/shared_random_state.c \
+ src/feature/dirauth/voteflags.c \
+ src/feature/dirauth/voting_schedule.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/dirauth/authmode.h \
+ src/feature/dirauth/bridgeauth.h \
+ src/feature/dirauth/bwauth.h \
+ src/feature/dirauth/dirauth_config.h \
+ src/feature/dirauth/dirauth_options.inc \
+ src/feature/dirauth/dirauth_options_st.h \
+ src/feature/dirauth/dirauth_periodic.h \
+ src/feature/dirauth/dirauth_sys.h \
+ src/feature/dirauth/dircollate.h \
+ src/feature/dirauth/dirvote.h \
+ src/feature/dirauth/dsigs_parse.h \
+ src/feature/dirauth/guardfraction.h \
+ src/feature/dirauth/keypin.h \
+ src/feature/dirauth/ns_detached_signatures_st.h \
+ src/feature/dirauth/reachability.h \
+ src/feature/dirauth/recommend_pkg.h \
+ src/feature/dirauth/process_descs.h \
+ src/feature/dirauth/shared_random.h \
+ src/feature/dirauth/shared_random_state.h \
+ src/feature/dirauth/vote_microdesc_hash_st.h \
+ src/feature/dirauth/voteflags.h \
+ src/feature/dirauth/voting_schedule.h
+
+if BUILD_MODULE_DIRAUTH
+LIBTOR_APP_A_SOURCES += $(MODULE_DIRAUTH_SOURCES)
+else
+LIBTOR_APP_A_STUB_SOURCES += src/feature/dirauth/dirauth_stub.c
+endif
diff --git a/src/feature/dirauth/keypin.c b/src/feature/dirauth/keypin.c
index 316b7d6c2f..5072a58573 100644
--- a/src/feature/dirauth/keypin.c
+++ b/src/feature/dirauth/keypin.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,8 +15,6 @@
#include "lib/cc/torint.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_format.h"
-#include "lib/crypt_ops/crypto_format.h"
-#include "lib/ctime/di_ops.h"
#include "lib/ctime/di_ops.h"
#include "lib/encoding/binascii.h"
#include "lib/encoding/time_fmt.h"
@@ -120,14 +118,14 @@ return (unsigned) siphash24g(a->ed25519_key, sizeof(a->ed25519_key));
}
HT_PROTOTYPE(rsamap, keypin_ent_st, rsamap_node, keypin_ent_hash_rsa,
- keypin_ents_eq_rsa)
+ keypin_ents_eq_rsa);
HT_GENERATE2(rsamap, keypin_ent_st, rsamap_node, keypin_ent_hash_rsa,
- keypin_ents_eq_rsa, 0.6, tor_reallocarray, tor_free_)
+ keypin_ents_eq_rsa, 0.6, tor_reallocarray, tor_free_);
HT_PROTOTYPE(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
- keypin_ents_eq_ed)
+ keypin_ents_eq_ed);
HT_GENERATE2(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
- keypin_ents_eq_ed, 0.6, tor_reallocarray, tor_free_)
+ keypin_ents_eq_ed, 0.6, tor_reallocarray, tor_free_);
/**
* Check whether we already have an entry in the key pinning table for a
diff --git a/src/feature/dirauth/keypin.h b/src/feature/dirauth/keypin.h
index 1de84f6d4a..881f010f0e 100644
--- a/src/feature/dirauth/keypin.h
+++ b/src/feature/dirauth/keypin.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file keypin.h
+ * @brief Header for keypin.c
+ **/
+
#ifndef TOR_KEYPIN_H
#define TOR_KEYPIN_H
@@ -40,6 +45,8 @@ int keypin_check_lone_rsa(const uint8_t *rsa_id_digest);
#ifdef KEYPIN_PRIVATE
+#include "ext/ht.h"
+
/**
* In-memory representation of a key-pinning table entry.
*/
diff --git a/src/feature/dirauth/ns_detached_signatures_st.h b/src/feature/dirauth/ns_detached_signatures_st.h
index 61d20b7525..f409431ec1 100644
--- a/src/feature/dirauth/ns_detached_signatures_st.h
+++ b/src/feature/dirauth/ns_detached_signatures_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file ns_detached_signatures_st.h
+ * @brief Detached consensus signatures structure.
+ **/
+
#ifndef NS_DETACHED_SIGNATURES_ST_H
#define NS_DETACHED_SIGNATURES_ST_H
@@ -19,4 +24,3 @@ struct ns_detached_signatures_t {
};
#endif /* !defined(NS_DETACHED_SIGNATURES_ST_H) */
-
diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c
index 71e3195c01..5025d0ae39 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,17 +12,21 @@
* them make those decisions.
**/
+#define PROCESS_DESCS_PRIVATE
+
#include "core/or/or.h"
#include "feature/dirauth/process_descs.h"
#include "app/config/config.h"
#include "core/or/policies.h"
#include "core/or/versions.h"
+#include "feature/dirauth/dirauth_sys.h"
#include "feature/dirauth/keypin.h"
#include "feature/dirauth/reachability.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/describe.h"
+#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerinfo.h"
@@ -32,46 +36,28 @@
#include "feature/relay/router.h"
#include "core/or/tor_version_st.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/extrainfo_st.h"
#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerstatus_st.h"
+#include "feature/nodelist/vote_routerstatus_st.h"
#include "lib/encoding/confline.h"
+#include "lib/crypt_ops/crypto_format.h"
/** How far in the future do we allow a router to get? (seconds) */
#define ROUTER_ALLOW_SKEW (60*60*12)
static void directory_remove_invalid(void);
-struct authdir_config_t;
static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
const char **msg);
static uint32_t
-dirserv_get_status_impl(const char *fp, const char *nickname,
- uint32_t addr, uint16_t or_port,
- const char *platform, const char **msg,
- int severity);
-
-/* 1 Historically used to indicate Named */
-#define FP_INVALID 2 /**< Believed invalid. */
-#define FP_REJECT 4 /**< We will not publish this router. */
-/* 8 Historically used to avoid using this as a dir. */
-#define FP_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */
-/* 32 Historically used to indicade Unnamed */
-
-/** Target of status_by_digest map. */
-typedef uint32_t router_status_t;
-
-static void add_fingerprint_to_dir(const char *fp,
- struct authdir_config_t *list,
- router_status_t add_status);
-
-/** List of nickname-\>identity fingerprint mappings for all the routers
- * that we name. Used to prevent router impersonation. */
-typedef struct authdir_config_t {
- strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */
- digestmap_t *status_by_digest; /**< Map from digest to router_status_t. */
-} authdir_config_t;
+dirserv_get_status_impl(const char *id_digest,
+ const ed25519_public_key_t *ed25519_public_key,
+ const char *nickname, uint32_t addr, uint16_t or_port,
+ const char *platform, const char **msg, int severity);
/** Should be static; exposed for testing. */
static authdir_config_t *fingerprint_list = NULL;
@@ -83,20 +69,39 @@ authdir_config_new(void)
authdir_config_t *list = tor_malloc_zero(sizeof(authdir_config_t));
list->fp_by_name = strmap_new();
list->status_by_digest = digestmap_new();
+ list->status_by_digest256 = digest256map_new();
return list;
}
+#ifdef TOR_UNIT_TESTS
+
+/** Initialize fingerprint_list to a new authdir_config_t. Used for tests. */
+void
+authdir_init_fingerprint_list(void)
+{
+ fingerprint_list = authdir_config_new();
+}
+
+/* Return the current fingerprint_list. Used for tests. */
+authdir_config_t *
+authdir_return_fingerprint_list(void)
+{
+ return fingerprint_list;
+}
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
/** Add the fingerprint <b>fp</b> to the smartlist of fingerprint_entry_t's
* <b>list</b>, or-ing the currently set status flags with
* <b>add_status</b>.
*/
-/* static */ void
-add_fingerprint_to_dir(const char *fp, authdir_config_t *list,
- router_status_t add_status)
+int
+add_rsa_fingerprint_to_dir(const char *fp, authdir_config_t *list,
+ rtr_flags_t add_status)
{
char *fingerprint;
char d[DIGEST_LEN];
- router_status_t *status;
+ rtr_flags_t *status;
tor_assert(fp);
tor_assert(list);
@@ -107,24 +112,52 @@ add_fingerprint_to_dir(const char *fp, authdir_config_t *list,
log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"",
escaped(fp));
tor_free(fingerprint);
- return;
+ return -1;
}
status = digestmap_get(list->status_by_digest, d);
if (!status) {
- status = tor_malloc_zero(sizeof(router_status_t));
+ status = tor_malloc_zero(sizeof(rtr_flags_t));
digestmap_set(list->status_by_digest, d, status);
}
tor_free(fingerprint);
*status |= add_status;
- return;
+ return 0;
+}
+
+/** Add the ed25519 key <b>edkey</b> to the smartlist of fingerprint_entry_t's
+ * <b>list</b>, or-ing the currently set status flags with <b>add_status</b>.
+ * Return -1 if we were unable to decode the key, else return 0.
+ */
+int
+add_ed25519_to_dir(const ed25519_public_key_t *edkey, authdir_config_t *list,
+ rtr_flags_t add_status)
+{
+ rtr_flags_t *status;
+
+ tor_assert(edkey);
+ tor_assert(list);
+
+ if (ed25519_validate_pubkey(edkey) < 0) {
+ log_warn(LD_DIRSERV, "Invalid ed25519 key \"%s\"", ed25519_fmt(edkey));
+ return -1;
+ }
+
+ status = digest256map_get(list->status_by_digest256, edkey->pubkey);
+ if (!status) {
+ status = tor_malloc_zero(sizeof(rtr_flags_t));
+ digest256map_set(list->status_by_digest256, edkey->pubkey, status);
+ }
+
+ *status |= add_status;
+ return 0;
}
/** Add the fingerprint for this OR to the global list of recognized
* identity key fingerprints. */
int
-dirserv_add_own_fingerprint(crypto_pk_t *pk)
+dirserv_add_own_fingerprint(crypto_pk_t *pk, const ed25519_public_key_t *edkey)
{
char fp[FINGERPRINT_LEN+1];
if (crypto_pk_get_fingerprint(pk, fp, 0)<0) {
@@ -133,7 +166,14 @@ dirserv_add_own_fingerprint(crypto_pk_t *pk)
}
if (!fingerprint_list)
fingerprint_list = authdir_config_new();
- add_fingerprint_to_dir(fp, fingerprint_list, 0);
+ if (add_rsa_fingerprint_to_dir(fp, fingerprint_list, 0) < 0) {
+ log_err(LD_BUG, "Error adding RSA fingerprint");
+ return -1;
+ }
+ if (add_ed25519_to_dir(edkey, fingerprint_list, 0) < 0) {
+ log_err(LD_BUG, "Error adding ed25519 key");
+ return -1;
+ }
return 0;
}
@@ -174,27 +214,46 @@ dirserv_load_fingerprint_file(void)
fingerprint_list_new = authdir_config_new();
for (list=front; list; list=list->next) {
- char digest_tmp[DIGEST_LEN];
- router_status_t add_status = 0;
+ rtr_flags_t add_status = 0;
nickname = list->key; fingerprint = list->value;
tor_strstrip(fingerprint, " "); /* remove spaces */
- if (strlen(fingerprint) != HEX_DIGEST_LEN ||
- base16_decode(digest_tmp, sizeof(digest_tmp),
- fingerprint, HEX_DIGEST_LEN) != sizeof(digest_tmp)) {
- log_notice(LD_CONFIG,
- "Invalid fingerprint (nickname '%s', "
- "fingerprint %s). Skipping.",
- nickname, fingerprint);
- continue;
- }
+
+ /* Determine what we should do with the relay with the nickname field. */
if (!strcasecmp(nickname, "!reject")) {
- add_status = FP_REJECT;
+ add_status = RTR_REJECT;
} else if (!strcasecmp(nickname, "!badexit")) {
- add_status = FP_BADEXIT;
+ add_status = RTR_BADEXIT;
} else if (!strcasecmp(nickname, "!invalid")) {
- add_status = FP_INVALID;
+ add_status = RTR_INVALID;
+ }
+
+ /* Check if fingerprint is RSA or ed25519 by verifying it. */
+ int ed25519_not_ok = -1, rsa_not_ok = -1;
+
+ /* Attempt to add the RSA key. */
+ if (strlen(fingerprint) == HEX_DIGEST_LEN) {
+ rsa_not_ok = add_rsa_fingerprint_to_dir(fingerprint,
+ fingerprint_list_new,
+ add_status);
+ }
+
+ /* Check ed25519 key. We check the size to prevent buffer overflows.
+ * If valid, attempt to add it, */
+ ed25519_public_key_t ed25519_pubkey_tmp;
+ if (strlen(fingerprint) == BASE64_DIGEST256_LEN) {
+ if (!digest256_from_base64((char *) ed25519_pubkey_tmp.pubkey,
+ fingerprint)) {
+ ed25519_not_ok = add_ed25519_to_dir(&ed25519_pubkey_tmp,
+ fingerprint_list_new, add_status);
+ }
+ }
+
+ /* If both keys are invalid (or missing), log and skip. */
+ if (ed25519_not_ok && rsa_not_ok) {
+ log_warn(LD_CONFIG, "Invalid fingerprint (nickname '%s', "
+ "fingerprint %s). Skipping.", nickname, fingerprint);
+ continue;
}
- add_fingerprint_to_dir(fingerprint, fingerprint_list_new, add_status);
}
config_free_lines(front);
@@ -225,26 +284,33 @@ dirserv_load_fingerprint_file(void)
*
* Return the appropriate router status.
*
- * If the status is 'FP_REJECT' and <b>msg</b> is provided, set
- * *<b>msg</b> to an explanation of why. */
+ * If the status is 'RTR_REJECT' and <b>msg</b> is provided, set
+ * *<b>msg</b> to a string constant explaining why. */
uint32_t
dirserv_router_get_status(const routerinfo_t *router, const char **msg,
int severity)
{
char d[DIGEST_LEN];
- const int key_pinning = get_options()->AuthDirPinKeys;
+ const int key_pinning = dirauth_get_options()->AuthDirPinKeys;
+ uint32_t r;
+ ed25519_public_key_t *signing_key = NULL;
if (crypto_pk_get_digest(router->identity_pkey, d)) {
log_warn(LD_BUG,"Error computing fingerprint");
if (msg)
*msg = "Bug: Error computing fingerprint";
- return FP_REJECT;
+ return RTR_REJECT;
}
- /* Check for the more common reasons to reject a router first. */
- const uint32_t r = dirserv_get_status_impl(d, router->nickname,
- router->addr, router->or_port,
- router->platform, msg, severity);
+ /* First, check for the more common reasons to reject a router. */
+ if (router->cache_info.signing_key_cert) {
+ /* This has an ed25519 identity key. */
+ signing_key = &router->cache_info.signing_key_cert->signing_key;
+ }
+ r = dirserv_get_status_impl(d, signing_key, router->nickname, router->addr,
+ router->or_port, router->platform, msg,
+ severity);
+
if (r)
return r;
@@ -259,7 +325,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
"key.", router_describe(router));
if (msg)
*msg = "Missing ntor curve25519 onion key. Please upgrade!";
- return FP_REJECT;
+ return RTR_REJECT;
}
if (router->cache_info.signing_key_cert) {
@@ -275,7 +341,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
if (msg) {
*msg = "Ed25519 identity key or RSA identity key has changed.";
}
- return FP_REJECT;
+ return RTR_REJECT;
}
}
} else {
@@ -292,7 +358,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
if (msg) {
*msg = "Ed25519 identity key has disappeared.";
}
- return FP_REJECT;
+ return RTR_REJECT;
}
#endif /* defined(DISABLE_DISABLING_ED25519) */
}
@@ -304,15 +370,17 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
/** Return true if there is no point in downloading the router described by
* <b>rs</b> because this directory would reject it. */
int
-dirserv_would_reject_router(const routerstatus_t *rs)
+dirserv_would_reject_router(const routerstatus_t *rs,
+ const vote_routerstatus_t *vrs)
{
uint32_t res;
+ struct ed25519_public_key_t pk;
+ memcpy(&pk.pubkey, vrs->ed25519_id, ED25519_PUBKEY_LEN);
- res = dirserv_get_status_impl(rs->identity_digest, rs->nickname,
- rs->addr, rs->or_port,
- NULL, NULL, LOG_DEBUG);
+ res = dirserv_get_status_impl(rs->identity_digest, &pk, rs->nickname,
+ rs->addr, rs->or_port, NULL, NULL, LOG_DEBUG);
- return (res & FP_REJECT) != 0;
+ return (res & RTR_REJECT) != 0;
}
/**
@@ -331,22 +399,21 @@ 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.2.9 are unsupported. Versions between 0.2.9.0 and
- * 0.2.9.4 suffer from bug #20499, where relays don't keep their consensus
- * up to date */
- if (!tor_version_as_new_as(platform,"0.2.9.5-alpha")) {
+ /* 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)
*msg = please_upgrade_string;
return true;
}
- /* Series between Tor 0.3.0 and 0.3.4 inclusive are unsupported, and some
- * have bug #27841, which makes them broken as intro points. Reject them.
- *
- * Also reject unstable versions of 0.3.5, since (as of this writing)
- * they are almost none of the network. */
- if (tor_version_as_new_as(platform,"0.3.0.0-alpha-dev") &&
- !tor_version_as_new_as(platform,"0.3.5.7")) {
+ /* Series between Tor 0.3.6 and 0.4.1.4-rc 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.1.5")) {
if (msg) {
*msg = please_upgrade_string;
}
@@ -357,19 +424,20 @@ dirserv_rejects_tor_version(const char *platform,
}
/** Helper: As dirserv_router_get_status, but takes the router fingerprint
- * (hex, no spaces), nickname, address (used for logging only), IP address, OR
- * port and platform (logging only) as arguments.
+ * (hex, no spaces), ed25519 key, nickname, address (used for logging only),
+ * IP address, OR port and platform (logging only) as arguments.
*
* Log messages at 'severity'. (There's not much point in
* logging that we're rejecting servers we'll not download.)
*/
static uint32_t
-dirserv_get_status_impl(const char *id_digest, const char *nickname,
- uint32_t addr, uint16_t or_port,
+dirserv_get_status_impl(const char *id_digest,
+ const ed25519_public_key_t *ed25519_public_key,
+ const char *nickname, uint32_t addr, uint16_t or_port,
const char *platform, const char **msg, int severity)
{
uint32_t result = 0;
- router_status_t *status_by_digest;
+ rtr_flags_t *status_by_digest;
if (!fingerprint_list)
fingerprint_list = authdir_config_new();
@@ -384,13 +452,13 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
if (msg) {
*msg = "Malformed platform string.";
}
- return FP_REJECT;
+ return RTR_REJECT;
}
}
/* Check whether the version is obsolete, broken, insecure, etc... */
if (platform && dirserv_rejects_tor_version(platform, msg)) {
- return FP_REJECT;
+ return RTR_REJECT;
}
status_by_digest = digestmap_get(fingerprint_list->status_by_digest,
@@ -398,23 +466,30 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
if (status_by_digest)
result |= *status_by_digest;
- if (result & FP_REJECT) {
+ if (ed25519_public_key) {
+ status_by_digest = digest256map_get(fingerprint_list->status_by_digest256,
+ ed25519_public_key->pubkey);
+ if (status_by_digest)
+ result |= *status_by_digest;
+ }
+
+ if (result & RTR_REJECT) {
if (msg)
- *msg = "Fingerprint is marked rejected -- if you think this is a "
- "mistake please set a valid email address in ContactInfo and "
- "send an email to bad-relays@lists.torproject.org mentioning "
- "your fingerprint(s)?";
- return FP_REJECT;
- } else if (result & FP_INVALID) {
+ *msg = "Fingerprint and/or ed25519 identity is marked rejected -- if "
+ "you think this is a mistake please set a valid email address "
+ "in ContactInfo and send an email to "
+ "bad-relays@lists.torproject.org mentioning your fingerprint(s)?";
+ return RTR_REJECT;
+ } else if (result & RTR_INVALID) {
if (msg)
- *msg = "Fingerprint is marked invalid";
+ *msg = "Fingerprint and/or ed25519 identity is marked invalid";
}
if (authdir_policy_badexit_address(addr, or_port)) {
log_fn(severity, LD_DIRSERV,
"Marking '%s' as bad exit because of address '%s'",
nickname, fmt_addr32(addr));
- result |= FP_BADEXIT;
+ result |= RTR_BADEXIT;
}
if (!authdir_policy_permits_address(addr, or_port)) {
@@ -425,13 +500,13 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
"mistake please set a valid email address in ContactInfo and "
"send an email to bad-relays@lists.torproject.org mentioning "
"your address(es) and fingerprint(s)?";
- return FP_REJECT;
+ return RTR_REJECT;
}
if (!authdir_policy_valid_address(addr, or_port)) {
log_fn(severity, LD_DIRSERV,
"Not marking '%s' valid because of address '%s'",
nickname, fmt_addr32(addr));
- result |= FP_INVALID;
+ result |= RTR_INVALID;
}
return result;
@@ -446,6 +521,7 @@ dirserv_free_fingerprint_list(void)
strmap_free(fingerprint_list->fp_by_name, tor_free_);
digestmap_free(fingerprint_list->status_by_digest, tor_free_);
+ digest256map_free(fingerprint_list->status_by_digest256, tor_free_);
tor_free(fingerprint_list);
}
@@ -487,7 +563,8 @@ dirserv_router_has_valid_address(routerinfo_t *ri)
/** Check whether we, as a directory server, want to accept <b>ri</b>. If so,
* set its is_valid,running fields and return 0. Otherwise, return -1.
*
- * If the router is rejected, set *<b>msg</b> to an explanation of why.
+ * If the router is rejected, set *<b>msg</b> to a string constant explining
+ * why.
*
* If <b>complain</b> then explain at log-level 'notice' why we refused
* a descriptor; else explain at log-level 'info'.
@@ -501,7 +578,7 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
int severity = (complain && ri->contact_info) ? LOG_NOTICE : LOG_INFO;
uint32_t status = dirserv_router_get_status(ri, msg, severity);
tor_assert(msg);
- if (status & FP_REJECT)
+ if (status & RTR_REJECT)
return -1; /* msg is already set. */
/* Is there too much clock skew? */
@@ -537,7 +614,7 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
return -1;
}
- *valid_out = ! (status & FP_INVALID);
+ *valid_out = ! (status & RTR_INVALID);
return 0;
}
@@ -549,8 +626,8 @@ void
dirserv_set_node_flags_from_authoritative_status(node_t *node,
uint32_t authstatus)
{
- node->is_valid = (authstatus & FP_INVALID) ? 0 : 1;
- node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0;
+ node->is_valid = (authstatus & RTR_INVALID) ? 0 : 1;
+ node->is_bad_exit = (authstatus & RTR_BADEXIT) ? 1 : 0;
}
/** True iff <b>a</b> is more severe than <b>b</b>. */
@@ -653,7 +730,8 @@ dirserv_add_multiple_descriptors(const char *desc, size_t desclen,
* That means the caller must not access <b>ri</b> after this function
* returns, since it might have been freed.
*
- * Return the status of the operation.
+ * Return the status of the operation, and set *<b>msg</b> to a string
+ * constant describing the status.
*
* This function is only called when fresh descriptors are posted, not when
* we re-load the cache.
@@ -666,7 +744,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
char *desc, *nickname;
const size_t desclen = ri->cache_info.signed_descriptor_len +
ri->cache_info.annotations_len;
- const int key_pinning = get_options()->AuthDirPinKeys;
+ const int key_pinning = dirauth_get_options()->AuthDirPinKeys;
*msg = NULL;
/* If it's too big, refuse it now. Otherwise we'll cache it all over the
@@ -864,21 +942,21 @@ directory_remove_invalid(void)
continue;
r = dirserv_router_get_status(ent, &msg, LOG_INFO);
description = router_describe(ent);
- if (r & FP_REJECT) {
+ if (r & RTR_REJECT) {
log_info(LD_DIRSERV, "Router %s is now rejected: %s",
description, msg?msg:"");
routerlist_remove(rl, ent, 0, time(NULL));
continue;
}
- if (bool_neq((r & FP_INVALID), !node->is_valid)) {
+ if (bool_neq((r & RTR_INVALID), !node->is_valid)) {
log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description,
- (r&FP_INVALID) ? "in" : "");
- node->is_valid = (r&FP_INVALID)?0:1;
+ (r&RTR_INVALID) ? "in" : "");
+ node->is_valid = (r&RTR_INVALID)?0:1;
}
- if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) {
+ if (bool_neq((r & RTR_BADEXIT), node->is_bad_exit)) {
log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description,
- (r & FP_BADEXIT) ? "bad" : "good");
- node->is_bad_exit = (r&FP_BADEXIT) ? 1: 0;
+ (r & RTR_BADEXIT) ? "bad" : "good");
+ node->is_bad_exit = (r&RTR_BADEXIT) ? 1: 0;
}
} SMARTLIST_FOREACH_END(node);
diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h
index e504daa7b7..1461ab697d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,6 +15,48 @@
// for was_router_added_t.
#include "feature/nodelist/routerlist.h"
+#include "lib/crypt_ops/crypto_ed25519.h"
+
+struct authdir_config_t;
+
+/** Target of status_by_digest map. */
+typedef uint32_t rtr_flags_t;
+
+int add_rsa_fingerprint_to_dir(const char *fp, struct authdir_config_t *list,
+ rtr_flags_t add_status);
+
+int add_ed25519_to_dir(const ed25519_public_key_t *edkey,
+ struct authdir_config_t *list,
+ rtr_flags_t add_status);
+
+/** List of nickname-\>identity fingerprint mappings for all the routers
+ * that we name. Used to prevent router impersonation. */
+typedef struct authdir_config_t {
+ strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */
+ digestmap_t *status_by_digest; /**< Map from digest to router_status_t. */
+ digest256map_t *status_by_digest256; /**< Map from digest256 to
+ * router_status_t. */
+} authdir_config_t;
+
+#if defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS)
+
+/* 1 Historically used to indicate Named */
+#define RTR_INVALID 2 /**< Believed invalid. */
+#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 */
+
+#endif /* defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) */
+
+#ifdef TOR_UNIT_TESTS
+
+void authdir_init_fingerprint_list(void);
+
+authdir_config_t *authdir_return_fingerprint_list(void);
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
void dirserv_free_fingerprint_list(void);
#ifdef HAVE_MODULE_DIRAUTH
@@ -28,11 +70,13 @@ enum was_router_added_t dirserv_add_descriptor(routerinfo_t *ri,
const char **msg,
const char *source);
-int dirserv_would_reject_router(const routerstatus_t *rs);
+int dirserv_would_reject_router(const routerstatus_t *rs,
+ const vote_routerstatus_t *vrs);
int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
int complain,
int *valid_out);
-int dirserv_add_own_fingerprint(crypto_pk_t *pk);
+int dirserv_add_own_fingerprint(crypto_pk_t *pk,
+ const ed25519_public_key_t *edkey);
uint32_t dirserv_router_get_status(const routerinfo_t *router,
const char **msg,
int severity);
@@ -54,7 +98,7 @@ dirserv_add_multiple_descriptors(const char *desc, size_t desclen,
(void)desclen;
(void)purpose;
(void)source;
- (void)msg;
+ *msg = "No directory authority support";
return (enum was_router_added_t)0;
}
static inline enum was_router_added_t
@@ -63,14 +107,16 @@ dirserv_add_descriptor(routerinfo_t *ri,
const char *source)
{
(void)ri;
- (void)msg;
(void)source;
+ *msg = "No directory authority support";
return (enum was_router_added_t)0;
}
static inline int
-dirserv_would_reject_router(const routerstatus_t *rs)
+dirserv_would_reject_router(const routerstatus_t *rs,
+ const vote_routerstatus_t *vrs)
{
(void)rs;
+ (void)vrs;
return 0;
}
static inline int
@@ -79,15 +125,16 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
int *valid_out)
{
(void)ri;
- (void)msg;
(void)complain;
- (void)valid_out;
+ *msg = "No directory authority support";
+ *valid_out = 0;
return 0;
}
static inline int
-dirserv_add_own_fingerprint(crypto_pk_t *pk)
+dirserv_add_own_fingerprint(crypto_pk_t *pk, const ed25519_public_key_t *edkey)
{
(void)pk;
+ (void)edkey;
return 0;
}
static inline uint32_t
@@ -96,8 +143,9 @@ dirserv_router_get_status(const routerinfo_t *router,
int severity)
{
(void)router;
- (void)msg;
(void)severity;
+ if (msg)
+ *msg = "No directory authority support";
return 0;
}
static inline void
diff --git a/src/feature/dirauth/reachability.c b/src/feature/dirauth/reachability.c
index 883b692cbb..65fa27ed80 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,6 +17,7 @@
#include "core/or/channeltls.h"
#include "core/or/command.h"
#include "feature/dirauth/authmode.h"
+#include "feature/dirauth/dirauth_sys.h"
#include "feature/nodelist/describe.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerinfo.h"
@@ -24,6 +25,7 @@
#include "feature/nodelist/torcert.h"
#include "feature/stats/rephist.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerlist_st.h"
@@ -53,7 +55,7 @@ dirserv_orconn_tls_done(const tor_addr_t *addr,
ri = node->ri;
- if (get_options()->AuthDirTestEd25519LinkKeys &&
+ if (dirauth_get_options()->AuthDirTestEd25519LinkKeys &&
node_supports_ed25519_link_authentication(node, 1) &&
ri->cache_info.signing_key_cert) {
/* We allow the node to have an ed25519 key if we haven't been told one in
@@ -125,7 +127,7 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
void
dirserv_single_reachability_test(time_t now, routerinfo_t *router)
{
- const or_options_t *options = get_options();
+ const dirauth_options_t *dirauth_options = dirauth_get_options();
channel_t *chan = NULL;
const node_t *node = NULL;
tor_addr_t router_addr;
@@ -136,7 +138,7 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
node = node_get_by_id(router->cache_info.identity_digest);
tor_assert(node);
- if (options->AuthDirTestEd25519LinkKeys &&
+ if (dirauth_options->AuthDirTestEd25519LinkKeys &&
node_supports_ed25519_link_authentication(node, 1) &&
router->cache_info.signing_key_cert) {
ed_id_key = &router->cache_info.signing_key_cert->signing_key;
@@ -154,7 +156,7 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
if (chan) command_setup_channel(chan);
/* Possible IPv6. */
- if (get_options()->AuthDirHasIPv6Connectivity == 1 &&
+ if (dirauth_get_options()->AuthDirHasIPv6Connectivity == 1 &&
!tor_addr_is_null(&router->ipv6_addr)) {
char addrstr[TOR_ADDR_BUF_LEN];
log_debug(LD_OR, "Testing reachability of %s at %s:%u.",
diff --git a/src/feature/dirauth/reachability.h b/src/feature/dirauth/reachability.h
index 46d0e7ee2e..19448a67f3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -24,10 +24,10 @@
#define REACHABILITY_TEST_CYCLE_PERIOD \
(REACHABILITY_TEST_INTERVAL*REACHABILITY_MODULO_PER_TEST)
+#ifdef HAVE_MODULE_DIRAUTH
void dirserv_single_reachability_test(time_t now, routerinfo_t *router);
void dirserv_test_reachability(time_t now);
-#ifdef HAVE_MODULE_DIRAUTH
int dirserv_should_launch_reachability_test(const routerinfo_t *ri,
const routerinfo_t *ri_old);
void dirserv_orconn_tls_done(const tor_addr_t *addr,
@@ -35,25 +35,16 @@ void dirserv_orconn_tls_done(const tor_addr_t *addr,
const char *digest_rcvd,
const struct ed25519_public_key_t *ed_id_rcvd);
#else /* !defined(HAVE_MODULE_DIRAUTH) */
-static inline int
-dirserv_should_launch_reachability_test(const routerinfo_t *ri,
- const routerinfo_t *ri_old)
-{
- (void)ri;
- (void)ri_old;
- return 0;
-}
-static inline void
-dirserv_orconn_tls_done(const tor_addr_t *addr,
- uint16_t or_port,
- const char *digest_rcvd,
- const struct ed25519_public_key_t *ed_id_rcvd)
-{
- (void)addr;
- (void)or_port;
- (void)digest_rcvd;
- (void)ed_id_rcvd;
-}
+#define dirserv_single_reachability_test(now, router) \
+ (((void)(now)),((void)(router)))
+#define dirserv_test_reachability(now) \
+ (((void)(now)))
+
+#define dirserv_should_launch_reachability_test(ri, ri_old) \
+ (((void)(ri)),((void)(ri_old)),0)
+#define dirserv_orconn_tls_done(addr, or_port, digest_rcvd, ed_id_rcvd) \
+ (((void)(addr)),((void)(or_port)),((void)(digest_rcvd)), \
+ ((void)(ed_id_rcvd)))
#endif /* defined(HAVE_MODULE_DIRAUTH) */
#endif /* !defined(TOR_REACHABILITY_H) */
diff --git a/src/feature/dirauth/recommend_pkg.c b/src/feature/dirauth/recommend_pkg.c
index 0456ff8463..84254566c6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 af17e945e8..dcd9f8be8a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 a45f0a29c3..fd55008242 100644
--- a/src/feature/dirauth/shared_random.c
+++ b/src/feature/dirauth/shared_random.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -90,7 +90,7 @@
#include "core/or/or.h"
#include "feature/dirauth/shared_random.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/nodelist/networkstatus.h"
@@ -99,27 +99,29 @@
#include "feature/nodelist/dirlist.h"
#include "feature/hs_common/shared_random_client.h"
#include "feature/dirauth/shared_random_state.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/authmode.h"
+#include "feature/dirauth/dirauth_sys.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/networkstatus_st.h"
-/* String prefix of shared random values in votes/consensuses. */
+/** String prefix of shared random values in votes/consensuses. */
static const char previous_srv_str[] = "shared-rand-previous-value";
static const char current_srv_str[] = "shared-rand-current-value";
static const char commit_ns_str[] = "shared-rand-commit";
static const char sr_flag_ns_str[] = "shared-rand-participate";
-/* The value of the consensus param AuthDirNumSRVAgreements found in the
+/** The value of the consensus param AuthDirNumSRVAgreements found in the
* vote. This is set once the consensus creation subsystem requests the
* SRV(s) that should be put in the consensus. We use this value to decide
* if we keep or not an SRV. */
static int32_t num_srv_agreements_from_vote;
-/* Return a heap allocated copy of the SRV <b>orig</b>. */
+/** Return a heap allocated copy of the SRV <b>orig</b>. */
sr_srv_t *
sr_srv_dup(const sr_srv_t *orig)
{
@@ -135,7 +137,7 @@ sr_srv_dup(const sr_srv_t *orig)
return duplicate;
}
-/* Allocate a new commit object and initializing it with <b>rsa_identity</b>
+/** Allocate a new commit object and initializing it with <b>rsa_identity</b>
* that MUST be provided. The digest algorithm is set to the default one
* that is supported. The rest is uninitialized. This never returns NULL. */
static sr_commit_t *
@@ -153,7 +155,7 @@ commit_new(const char *rsa_identity)
return commit;
}
-/* Issue a log message describing <b>commit</b>. */
+/** Issue a log message describing <b>commit</b>. */
static void
commit_log(const sr_commit_t *commit)
{
@@ -166,7 +168,7 @@ commit_log(const sr_commit_t *commit)
commit->reveal_ts, safe_str(commit->encoded_reveal));
}
-/* Make sure that the commitment and reveal information in <b>commit</b>
+/** Make sure that the commitment and reveal information in <b>commit</b>
* match. If they match return 0, return -1 otherwise. This function MUST be
* used everytime we receive a new reveal value. Furthermore, the commit
* object MUST have a reveal value and the hash of the reveal value. */
@@ -220,7 +222,7 @@ verify_commit_and_reveal(const sr_commit_t *commit)
return -1;
}
-/* Return true iff the commit contains an encoded reveal value. */
+/** Return true iff the commit contains an encoded reveal value. */
STATIC int
commit_has_reveal_value(const sr_commit_t *commit)
{
@@ -228,7 +230,7 @@ commit_has_reveal_value(const sr_commit_t *commit)
sizeof(commit->encoded_reveal));
}
-/* Parse the encoded commit. The format is:
+/** Parse the encoded commit. The format is:
* base64-encode( TIMESTAMP || H(REVEAL) )
*
* If successfully decoded and parsed, commit is updated and 0 is returned.
@@ -283,7 +285,7 @@ commit_decode(const char *encoded, sr_commit_t *commit)
return -1;
}
-/* Parse the b64 blob at <b>encoded</b> containing reveal information and
+/** Parse the b64 blob at <b>encoded</b> containing reveal information and
* store the information in-place in <b>commit</b>. Return 0 on success else
* a negative value. */
STATIC int
@@ -333,7 +335,7 @@ reveal_decode(const char *encoded, sr_commit_t *commit)
return -1;
}
-/* Encode a reveal element using a given commit object to dst which is a
+/** Encode a reveal element using a given commit object to dst which is a
* buffer large enough to put the base64-encoded reveal construction. The
* format is as follow:
* REVEAL = base64-encode( TIMESTAMP || H(RN) )
@@ -362,7 +364,7 @@ reveal_encode(const sr_commit_t *commit, char *dst, size_t len)
return ret;
}
-/* Encode the given commit object to dst which is a buffer large enough to
+/** Encode the given commit object to dst which is a buffer large enough to
* put the base64-encoded commit. The format is as follow:
* COMMIT = base64-encode( TIMESTAMP || H(H(RN)) )
* Return base64 encoded length on success else a negative value.
@@ -388,14 +390,14 @@ commit_encode(const sr_commit_t *commit, char *dst, size_t len)
return base64_encode(dst, len, buf, sizeof(buf), 0);
}
-/* Cleanup both our global state and disk state. */
+/** Cleanup both our global state and disk state. */
static void
sr_cleanup(void)
{
sr_state_free_all();
}
-/* Using <b>commit</b>, return a newly allocated string containing the commit
+/** Using <b>commit</b>, return a newly allocated string containing the commit
* information that should be used during SRV calculation. It's the caller
* responsibility to free the memory. Return NULL if this is not a commit to be
* used for SRV calculation. */
@@ -414,7 +416,7 @@ get_srv_element_from_commit(const sr_commit_t *commit)
return element;
}
-/* Return a srv object that is built with the construction:
+/** Return a srv object that is built with the construction:
* SRV = SHA3-256("shared-random" | INT_8(reveal_num) |
* INT_4(version) | HASHED_REVEALS | previous_SRV)
* This function cannot fail. */
@@ -456,7 +458,7 @@ generate_srv(const char *hashed_reveals, uint64_t reveal_num,
return srv;
}
-/* Compare reveal values and return the result. This should exclusively be
+/** Compare reveal values and return the result. This should exclusively be
* used by smartlist_sort(). */
static int
compare_reveal_(const void **_a, const void **_b)
@@ -466,7 +468,7 @@ compare_reveal_(const void **_a, const void **_b)
sizeof(a->hashed_reveal));
}
-/* Given <b>commit</b> give the line that we should place in our votes.
+/** Given <b>commit</b> give the line that we should place in our votes.
* It's the responsibility of the caller to free the string. */
static char *
get_vote_line_from_commit(const sr_commit_t *commit, sr_phase_t phase)
@@ -506,7 +508,7 @@ get_vote_line_from_commit(const sr_commit_t *commit, sr_phase_t phase)
return vote_line;
}
-/* Return a heap allocated string that contains the given <b>srv</b> string
+/** Return a heap allocated string that contains the given <b>srv</b> string
* representation formatted for a networkstatus document using the
* <b>key</b> as the start of the line. This doesn't return NULL. */
static char *
@@ -524,7 +526,7 @@ srv_to_ns_string(const sr_srv_t *srv, const char *key)
return srv_str;
}
-/* Given the previous SRV and the current SRV, return a heap allocated
+/** Given the previous SRV and the current SRV, return a heap allocated
* string with their data that could be put in a vote or a consensus. Caller
* must free the returned string. Return NULL if no SRVs were provided. */
static char *
@@ -557,7 +559,7 @@ get_ns_str_from_sr_values(const sr_srv_t *prev_srv, const sr_srv_t *cur_srv)
return srv_str;
}
-/* Return 1 iff the two commits have the same commitment values. This
+/** Return 1 iff the two commits have the same commitment values. This
* function does not care about reveal values. */
STATIC int
commitments_are_the_same(const sr_commit_t *commit_one,
@@ -572,7 +574,7 @@ commitments_are_the_same(const sr_commit_t *commit_one,
return 1;
}
-/* We just received a commit from the vote of authority with
+/** We just received a commit from the vote of authority with
* <b>identity_digest</b>. Return 1 if this commit is authorititative that
* is, it belongs to the authority that voted it. Else return 0 if not. */
STATIC int
@@ -586,7 +588,7 @@ commit_is_authoritative(const sr_commit_t *commit,
sizeof(commit->rsa_identity));
}
-/* Decide if the newly received <b>commit</b> should be kept depending on
+/** Decide if the newly received <b>commit</b> should be kept depending on
* the current phase and state of the protocol. The <b>voter_key</b> is the
* RSA identity key fingerprint of the authority's vote from which the
* commit comes from. The <b>phase</b> is the phase we should be validating
@@ -705,7 +707,7 @@ should_keep_commit(const sr_commit_t *commit, const char *voter_key,
return 0;
}
-/* We are in reveal phase and we found a valid and verified <b>commit</b> in
+/** We are in reveal phase and we found a valid and verified <b>commit</b> in
* a vote that contains reveal values that we could use. Update the commit
* we have in our state. Never call this with an unverified commit. */
STATIC void
@@ -726,7 +728,7 @@ save_commit_during_reveal_phase(const sr_commit_t *commit)
sr_state_copy_reveal_info(saved_commit, commit);
}
-/* Save <b>commit</b> to our persistent state. Depending on the current
+/** Save <b>commit</b> to our persistent state. Depending on the current
* phase, different actions are taken. Steals reference of <b>commit</b>.
* The commit object MUST be valid and verified before adding it to the
* state. */
@@ -751,7 +753,7 @@ save_commit_to_state(sr_commit_t *commit)
}
}
-/* Return 1 if we should we keep an SRV voted by <b>n_agreements</b> auths.
+/** Return 1 if we should we keep an SRV voted by <b>n_agreements</b> auths.
* Return 0 if we should ignore it. */
static int
should_keep_srv(int n_agreements)
@@ -781,7 +783,7 @@ should_keep_srv(int n_agreements)
return 1;
}
-/* Helper: compare two DIGEST256_LEN digests. */
+/** Helper: compare two DIGEST256_LEN digests. */
static int
compare_srvs_(const void **_a, const void **_b)
{
@@ -789,7 +791,7 @@ compare_srvs_(const void **_a, const void **_b)
return tor_memcmp(a->value, b->value, sizeof(a->value));
}
-/* Return the most frequent member of the sorted list of DIGEST256_LEN
+/** Return the most frequent member of the sorted list of DIGEST256_LEN
* digests in <b>sl</b> with the count of that most frequent element. */
static sr_srv_t *
smartlist_get_most_frequent_srv(const smartlist_t *sl, int *count_out)
@@ -806,7 +808,7 @@ compare_srv_(const void **_a, const void **_b)
sizeof(a->value));
}
-/* Using a list of <b>votes</b>, return the SRV object from them that has
+/** Using a list of <b>votes</b>, return the SRV object from them that has
* been voted by the majority of dirauths. If <b>current</b> is set, we look
* for the current SRV value else the previous one. The returned pointer is
* an object located inside a vote. NULL is returned if no appropriate value
@@ -868,7 +870,7 @@ get_majority_srv_from_votes(const smartlist_t *votes, int current)
return the_srv;
}
-/* Free a commit object. */
+/** Free a commit object. */
void
sr_commit_free_(sr_commit_t *commit)
{
@@ -880,7 +882,7 @@ sr_commit_free_(sr_commit_t *commit)
tor_free(commit);
}
-/* Generate the commitment/reveal value for the protocol run starting at
+/** Generate the commitment/reveal value for the protocol run starting at
* <b>timestamp</b>. <b>my_rsa_cert</b> is our authority RSA certificate. */
sr_commit_t *
sr_generate_our_commit(time_t timestamp, const authority_cert_t *my_rsa_cert)
@@ -937,7 +939,8 @@ sr_generate_our_commit(time_t timestamp, const authority_cert_t *my_rsa_cert)
return NULL;
}
-/* Compute the shared random value based on the active commits in our state. */
+/** Compute the shared random value based on the active commits in our
+ * state. */
void
sr_compute_srv(void)
{
@@ -1010,7 +1013,7 @@ sr_compute_srv(void)
tor_free(reveals);
}
-/* Parse a commit from a vote or from our disk state and return a newly
+/** Parse a commit from a vote or from our disk state and return a newly
* allocated commit object. NULL is returned on error.
*
* The commit's data is in <b>args</b> and the order matters very much:
@@ -1082,7 +1085,7 @@ sr_parse_commit(const smartlist_t *args)
return NULL;
}
-/* Called when we are done parsing a vote by <b>voter_key</b> that might
+/** Called when we are done parsing a vote by <b>voter_key</b> that might
* contain some useful <b>commits</b>. Find if any of them should be kept
* and update our state accordingly. Once done, the list of commitments will
* be empty. */
@@ -1120,7 +1123,7 @@ sr_handle_received_commits(smartlist_t *commits, crypto_pk_t *voter_key)
} SMARTLIST_FOREACH_END(commit);
}
-/* Return a heap-allocated string containing commits that should be put in
+/** Return a heap-allocated string containing commits that should be put in
* the votes. It's the responsibility of the caller to free the string.
* This always return a valid string, either empty or with line(s). */
char *
@@ -1129,7 +1132,7 @@ sr_get_string_for_vote(void)
char *vote_str = NULL;
digestmap_t *state_commits;
smartlist_t *chunks = smartlist_new();
- const or_options_t *options = get_options();
+ const dirauth_options_t *options = dirauth_get_options();
/* Are we participating in the protocol? */
if (!options->AuthDirSharedRandomness) {
@@ -1178,7 +1181,7 @@ sr_get_string_for_vote(void)
return vote_str;
}
-/* Return a heap-allocated string that should be put in the consensus and
+/** Return a heap-allocated string that should be put in the consensus and
* contains the shared randomness values. It's the responsibility of the
* caller to free the string. NULL is returned if no SRV(s) available.
*
@@ -1194,7 +1197,7 @@ sr_get_string_for_consensus(const smartlist_t *votes,
int32_t num_srv_agreements)
{
char *srv_str;
- const or_options_t *options = get_options();
+ const dirauth_options_t *options = dirauth_get_options();
tor_assert(votes);
@@ -1222,7 +1225,7 @@ sr_get_string_for_consensus(const smartlist_t *votes,
return NULL;
}
-/* We just computed a new <b>consensus</b>. Update our state with the SRVs
+/** We just computed a new <b>consensus</b>. Update our state with the SRVs
* from the consensus (might be NULL as well). Register the SRVs in our SR
* state and prepare for the upcoming protocol round. */
void
@@ -1258,10 +1261,10 @@ sr_act_post_consensus(const networkstatus_t *consensus)
}
/* Prepare our state so that it's ready for the next voting period. */
- sr_state_update(voting_schedule_get_next_valid_after_time());
+ sr_state_update(dirauth_sched_get_next_valid_after_time());
}
-/* Initialize shared random subsystem. This MUST be called early in the boot
+/** Initialize shared random subsystem. This MUST be called early in the boot
* process of tor. Return 0 on success else -1 on error. */
int
sr_init(int save_to_disk)
@@ -1269,7 +1272,7 @@ sr_init(int save_to_disk)
return sr_state_init(save_to_disk, 1);
}
-/* Save our state to disk and cleanup everything. */
+/** Save our state to disk and cleanup everything. */
void
sr_save_and_cleanup(void)
{
@@ -1279,7 +1282,7 @@ sr_save_and_cleanup(void)
#ifdef TOR_UNIT_TESTS
-/* Set the global value of number of SRV agreements so the test can play
+/** Set the global value of number of SRV agreements so the test can play
* along by calling specific functions that don't parse the votes prior for
* the AuthDirNumSRVAgreements value. */
void
diff --git a/src/feature/dirauth/shared_random.h b/src/feature/dirauth/shared_random.h
index 7ff9f15512..c4e259dcdb 100644
--- a/src/feature/dirauth/shared_random.h
+++ b/src/feature/dirauth/shared_random.h
@@ -1,86 +1,88 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_SHARED_RANDOM_H
#define TOR_SHARED_RANDOM_H
-/*
- * This file contains ABI/API of the shared random protocol defined in
+/**
+ * \file shared_random.h
+ *
+ * \brief This file contains ABI/API of the shared random protocol defined in
* proposal #250. Every public functions and data structure are namespaced
* with "sr_" which stands for shared random.
*/
#include "core/or/or.h"
-/* Protocol version */
+/** Protocol version */
#define SR_PROTO_VERSION 1
-/* Default digest algorithm. */
+/** Default digest algorithm. */
#define SR_DIGEST_ALG DIGEST_SHA3_256
-/* Invariant token in the SRV calculation. */
+/** Invariant token in the SRV calculation. */
#define SR_SRV_TOKEN "shared-random"
-/* Don't count the NUL terminated byte even though the TOKEN has it. */
+/** Don't count the NUL terminated byte even though the TOKEN has it. */
#define SR_SRV_TOKEN_LEN (sizeof(SR_SRV_TOKEN) - 1)
-/* Length of the random number (in bytes). */
+/** Length of the random number (in bytes). */
#define SR_RANDOM_NUMBER_LEN 32
-/* Size of a decoded commit value in a vote or state. It's a hash and a
+/** Size of a decoded commit value in a vote or state. It's a hash and a
* timestamp. It adds up to 40 bytes. */
#define SR_COMMIT_LEN (sizeof(uint64_t) + DIGEST256_LEN)
-/* Size of a decoded reveal value from a vote or state. It's a 64 bit
+/** Size of a decoded reveal value from a vote or state. It's a 64 bit
* timestamp and the hashed random number. This adds up to 40 bytes. */
#define SR_REVEAL_LEN (sizeof(uint64_t) + DIGEST256_LEN)
-/* Size of SRV message length. The construction is has follow:
+/** Size of SRV message length. The construction is has follow:
* "shared-random" | INT_8(reveal_num) | INT_4(version) | PREV_SRV */
#define SR_SRV_MSG_LEN \
(SR_SRV_TOKEN_LEN + sizeof(uint64_t) + sizeof(uint32_t) + DIGEST256_LEN)
-/* Length of base64 encoded commit NOT including the NUL terminated byte.
+/** Length of base64 encoded commit NOT including the NUL terminated byte.
* Formula is taken from base64_encode_size. This adds up to 56 bytes. */
#define SR_COMMIT_BASE64_LEN (BASE64_LEN(SR_COMMIT_LEN))
-/* Length of base64 encoded reveal NOT including the NUL terminated byte.
+/** Length of base64 encoded reveal NOT including the NUL terminated byte.
* Formula is taken from base64_encode_size. This adds up to 56 bytes. */
#define SR_REVEAL_BASE64_LEN (BASE64_LEN(SR_REVEAL_LEN))
-/* Length of base64 encoded shared random value. It's 32 bytes long so 44
+/** Length of base64 encoded shared random value. It's 32 bytes long so 44
* bytes from the base64_encode_size formula. That includes the '='
* character at the end. */
#define SR_SRV_VALUE_BASE64_LEN (BASE64_LEN(DIGEST256_LEN))
-/* Assert if commit valid flag is not set. */
+/** Assert if commit valid flag is not set. */
#define ASSERT_COMMIT_VALID(c) tor_assert((c)->valid)
-/* Protocol phase. */
+/** Protocol phase. */
typedef enum {
- /* Commitment phase */
+ /** Commitment phase */
SR_PHASE_COMMIT = 1,
- /* Reveal phase */
+ /** Reveal phase */
SR_PHASE_REVEAL = 2,
} sr_phase_t;
-/* A shared random value (SRV). */
+/** A shared random value (SRV). */
typedef struct sr_srv_t {
- /* The number of reveal values used to derive this SRV. */
+ /** The number of reveal values used to derive this SRV. */
uint64_t num_reveals;
- /* The actual value. This is the stored result of SHA3-256. */
+ /** The actual value. This is the stored result of SHA3-256. */
uint8_t value[DIGEST256_LEN];
} sr_srv_t;
-/* A commit (either ours or from another authority). */
+/** A commit (either ours or from another authority). */
typedef struct sr_commit_t {
- /* Hashing algorithm used. */
+ /** Hashing algorithm used. */
digest_algorithm_t alg;
- /* Indicate if this commit has been verified thus valid. */
+ /** Indicate if this commit has been verified thus valid. */
unsigned int valid:1;
/* Commit owner info */
- /* The RSA identity key of the authority and its base16 representation,
+ /** The RSA identity key of the authority and its base16 representation,
* which includes the NUL terminated byte. */
char rsa_identity[DIGEST_LEN];
char rsa_identity_hex[HEX_DIGEST_LEN + 1];
/* Commitment information */
- /* Timestamp of reveal. Correspond to TIMESTAMP. */
+ /** Timestamp of reveal. Correspond to TIMESTAMP. */
uint64_t reveal_ts;
/* H(REVEAL) as found in COMMIT message. */
char hashed_reveal[DIGEST256_LEN];
@@ -89,13 +91,13 @@ typedef struct sr_commit_t {
/* Reveal information */
- /* H(RN) which is what we used as the random value for this commit. We
+ /** H(RN) which is what we used as the random value for this commit. We
* don't use the raw bytes since those are sent on the network thus
* avoiding possible information leaks of our PRNG. */
uint8_t random_number[SR_RANDOM_NUMBER_LEN];
- /* Timestamp of commit. Correspond to TIMESTAMP. */
+ /** Timestamp of commit. Correspond to TIMESTAMP. */
uint64_t commit_ts;
- /* This is the whole reveal message. We use it during verification */
+ /** This is the whole reveal message. We use it during verification */
char encoded_reveal[SR_REVEAL_BASE64_LEN + 1];
} sr_commit_t;
@@ -191,4 +193,3 @@ void set_num_srv_agreements(int32_t value);
#endif /* TOR_UNIT_TESTS */
#endif /* !defined(TOR_SHARED_RANDOM_H) */
-
diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c
index 4078d6a24a..07bc757506 100644
--- a/src/feature/dirauth/shared_random_state.c
+++ b/src/feature/dirauth/shared_random_state.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,7 +12,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/dirauth/dirvote.h"
#include "feature/nodelist/networkstatus.h"
@@ -20,24 +20,24 @@
#include "feature/dirauth/shared_random.h"
#include "feature/hs_common/shared_random_client.h"
#include "feature/dirauth/shared_random_state.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "lib/encoding/confline.h"
#include "lib/version/torversion.h"
#include "app/config/or_state_st.h"
-/* Default filename of the shared random state on disk. */
+/** Default filename of the shared random state on disk. */
static const char default_fname[] = "sr-state";
-/* String representation of a protocol phase. */
+/** String representation of a protocol phase. */
static const char *phase_str[] = { "unknown", "commit", "reveal" };
-/* Our shared random protocol state. There is only one possible state per
+/** Our shared random protocol state. There is only one possible state per
* protocol run so this is the global state which is reset at every run once
* the shared random value has been computed. */
static sr_state_t *sr_state = NULL;
-/* Representation of our persistent state on disk. The sr_state above
+/** Representation of our persistent state on disk. The sr_state above
* contains the data parsed from this state. When we save to disk, we
* translate the sr_state to this sr_disk_state. */
static sr_disk_state_t *sr_disk_state = NULL;
@@ -56,14 +56,11 @@ DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t);
#define V(member,conftype,initvalue) \
VAR(#member, conftype, member, initvalue)
-/* Our persistent state magic number. */
+/** Our persistent state magic number. */
#define SR_DISK_STATE_MAGIC 0x98AB1254
-static int
-disk_state_validate_cb(void *old_state, void *state, void *default_state,
- int from_setconf, char **msg);
-
-/* Array of variables that are saved to disk as a persistent state. */
+/** Array of variables that are saved to disk as a persistent state. */
+// clang-format off
static const config_var_t state_vars[] = {
V(Version, POSINT, "0"),
V(TorVersion, STRING, NULL),
@@ -77,8 +74,9 @@ static const config_var_t state_vars[] = {
VAR("SharedRandCurrentValue", LINELIST_S, SharedRandValues, NULL),
END_OF_CONFIG_VARS
};
+// clang-format on
-/* "Extra" variable in the state that receives lines we can't parse. This
+/** "Extra" variable in the state that receives lines we can't parse. This
* lets us preserve options from versions of Tor newer than us. */
static const struct_member_t state_extra_var = {
.name = "__extra",
@@ -86,24 +84,19 @@ static const struct_member_t state_extra_var = {
.offset = offsetof(sr_disk_state_t, ExtraLines),
};
-/* Configuration format of sr_disk_state_t. */
+/** Configuration format of sr_disk_state_t. */
static const config_format_t state_format = {
- sizeof(sr_disk_state_t),
- {
+ .size = sizeof(sr_disk_state_t),
+ .magic = {
"sr_disk_state_t",
SR_DISK_STATE_MAGIC,
offsetof(sr_disk_state_t, magic_),
},
- NULL,
- NULL,
- state_vars,
- disk_state_validate_cb,
- NULL,
- &state_extra_var,
- -1,
+ .vars = state_vars,
+ .extra = &state_extra_var,
};
-/* Global configuration manager for the shared-random state file */
+/** Global configuration manager for the shared-random state file */
static config_mgr_t *shared_random_state_mgr = NULL;
/** Return the configuration manager for the shared-random state file. */
@@ -119,7 +112,7 @@ get_srs_mgr(void)
static void state_query_del_(sr_state_object_t obj_type, void *data);
-/* Return a string representation of a protocol phase. */
+/** Return a string representation of a protocol phase. */
STATIC const char *
get_phase_str(sr_phase_t phase)
{
@@ -137,7 +130,7 @@ get_phase_str(sr_phase_t phase)
return the_string;
}
-/* Return the time we should expire the state file created at <b>now</b>.
+/** Return the time we should expire the state file created at <b>now</b>.
* We expire the state file in the beginning of the next protocol run. */
STATIC time_t
get_state_valid_until_time(time_t now)
@@ -148,7 +141,7 @@ get_state_valid_until_time(time_t now)
voting_interval = get_voting_interval();
/* Find the time the current round started. */
- beginning_of_current_round = get_start_time_of_current_round();
+ beginning_of_current_round = dirauth_sched_get_cur_valid_after_time();
/* Find how many rounds are left till the end of the protocol run */
current_round = (now / voting_interval) % total_rounds;
@@ -168,7 +161,7 @@ get_state_valid_until_time(time_t now)
return valid_until;
}
-/* Given the consensus 'valid-after' time, return the protocol phase we should
+/** Given the consensus 'valid-after' time, return the protocol phase we should
* be in. */
STATIC sr_phase_t
get_sr_protocol_phase(time_t valid_after)
@@ -188,7 +181,7 @@ get_sr_protocol_phase(time_t valid_after)
}
}
-/* Add the given <b>commit</b> to <b>state</b>. It MUST be a valid commit
+/** Add the given <b>commit</b> to <b>state</b>. It MUST be a valid commit
* and there shouldn't be a commit from the same authority in the state
* already else verification hasn't been done prior. This takes ownership of
* the commit once in our state. */
@@ -213,7 +206,7 @@ commit_add_to_state(sr_commit_t *commit, sr_state_t *state)
}
}
-/* Helper: deallocate a commit object. (Used with digestmap_free(), which
+/** Helper: deallocate a commit object. (Used with digestmap_free(), which
* requires a function pointer whose argument is void *). */
static void
commit_free_(void *p)
@@ -224,7 +217,7 @@ commit_free_(void *p)
#define state_free(val) \
FREE_AND_NULL(sr_state_t, state_free_, (val))
-/* Free a state that was allocated with state_new(). */
+/** Free a state that was allocated with state_new(). */
static void
state_free_(sr_state_t *state)
{
@@ -238,7 +231,7 @@ state_free_(sr_state_t *state)
tor_free(state);
}
-/* Allocate an sr_state_t object and returns it. If no <b>fname</b>, the
+/** Allocate an sr_state_t object and returns it. If no <b>fname</b>, the
* default file name is used. This function does NOT initialize the state
* timestamp, phase or shared random value. NULL is never returned. */
static sr_state_t *
@@ -257,7 +250,7 @@ state_new(const char *fname, time_t now)
return new_state;
}
-/* Set our global state pointer with the one given. */
+/** Set our global state pointer with the one given. */
static void
state_set(sr_state_t *state)
{
@@ -271,7 +264,7 @@ state_set(sr_state_t *state)
#define disk_state_free(val) \
FREE_AND_NULL(sr_disk_state_t, disk_state_free_, (val))
-/* Free an allocated disk state. */
+/** Free an allocated disk state. */
static void
disk_state_free_(sr_disk_state_t *state)
{
@@ -281,7 +274,7 @@ disk_state_free_(sr_disk_state_t *state)
config_free(get_srs_mgr(), state);
}
-/* Allocate a new disk state, initialize it and return it. */
+/** Allocate a new disk state, initialize it and return it. */
static sr_disk_state_t *
disk_state_new(time_t now)
{
@@ -297,7 +290,7 @@ disk_state_new(time_t now)
return new_state;
}
-/* Set our global disk state with the given state. */
+/** Set our global disk state with the given state. */
static void
disk_state_set(sr_disk_state_t *state)
{
@@ -308,7 +301,7 @@ disk_state_set(sr_disk_state_t *state)
sr_disk_state = state;
}
-/* Return -1 if the disk state is invalid (something in there that we can't or
+/** Return -1 if the disk state is invalid (something in there that we can't or
* shouldn't use). Return 0 if everything checks out. */
static int
disk_state_validate(const sr_disk_state_t *state)
@@ -343,25 +336,7 @@ disk_state_validate(const sr_disk_state_t *state)
return -1;
}
-/* Validate the disk state (NOP for now). */
-static int
-disk_state_validate_cb(void *old_state, void *state, void *default_state,
- int from_setconf, char **msg)
-{
- /* We don't use these; only options do. */
- (void) from_setconf;
- (void) default_state;
- (void) old_state;
-
- /* This is called by config_dump which is just before we are about to
- * write it to disk. At that point, our global memory state has been
- * copied to the disk state so it's fair to assume it's trustable. */
- (void) state;
- (void) msg;
- return 0;
-}
-
-/* Parse the Commit line(s) in the disk state and translate them to the
+/** Parse the Commit line(s) in the disk state and translate them to the
* the memory state. Return 0 on success else -1 on error. */
static int
disk_state_parse_commits(sr_state_t *state,
@@ -416,7 +391,7 @@ disk_state_parse_commits(sr_state_t *state,
return -1;
}
-/* Parse a share random value line from the disk state and save it to dst
+/** Parse a share random value line from the disk state and save it to dst
* which is an allocated srv object. Return 0 on success else -1. */
static int
disk_state_parse_srv(const char *value, sr_srv_t *dst)
@@ -451,7 +426,7 @@ disk_state_parse_srv(const char *value, sr_srv_t *dst)
return ret;
}
-/* Parse both SharedRandCurrentValue and SharedRandPreviousValue line from
+/** Parse both SharedRandCurrentValue and SharedRandPreviousValue line from
* the state. Return 0 on success else -1. */
static int
disk_state_parse_sr_values(sr_state_t *state,
@@ -502,7 +477,7 @@ disk_state_parse_sr_values(sr_state_t *state,
return -1;
}
-/* Parse the given disk state and set a newly allocated state. On success,
+/** Parse the given disk state and set a newly allocated state. On success,
* return that state else NULL. */
static sr_state_t *
disk_state_parse(const sr_disk_state_t *new_disk_state)
@@ -536,7 +511,7 @@ disk_state_parse(const sr_disk_state_t *new_disk_state)
return NULL;
}
-/* From a valid commit object and an allocated config line, set the line's
+/** From a valid commit object and an allocated config line, set the line's
* value to the state string representation of a commit. */
static void
disk_state_put_commit_line(const sr_commit_t *commit, config_line_t *line)
@@ -563,7 +538,7 @@ disk_state_put_commit_line(const sr_commit_t *commit, config_line_t *line)
}
}
-/* From a valid srv object and an allocated config line, set the line's
+/** From a valid srv object and an allocated config line, set the line's
* value to the state string representation of a shared random value. */
static void
disk_state_put_srv_line(const sr_srv_t *srv, config_line_t *line)
@@ -581,7 +556,7 @@ disk_state_put_srv_line(const sr_srv_t *srv, config_line_t *line)
tor_asprintf(&line->value, "%" PRIu64 " %s", srv->num_reveals, encoded);
}
-/* Reset disk state that is free allocated memory and zeroed the object. */
+/** Reset disk state that is free allocated memory and zeroed the object. */
static void
disk_state_reset(void)
{
@@ -600,7 +575,7 @@ disk_state_reset(void)
sr_disk_state->TorVersion = tor_strdup(get_version());
}
-/* Update our disk state based on our global SR state. */
+/** Update our disk state based on our global SR state. */
static void
disk_state_update(void)
{
@@ -644,7 +619,7 @@ disk_state_update(void)
} DIGESTMAP_FOREACH_END;
}
-/* Load state from disk and put it into our disk state. If the state passes
+/** Load state from disk and put it into our disk state. If the state passes
* validation, our global state will be updated with it. Return 0 on
* success. On error, -EINVAL is returned if the state on disk did contained
* something malformed or is unreadable. -ENOENT is returned indicating that
@@ -662,7 +637,7 @@ disk_state_load_from_disk(void)
return ret;
}
-/* Helper for disk_state_load_from_disk(). */
+/** Helper for disk_state_load_from_disk(). */
STATIC int
disk_state_load_from_disk_impl(const char *fname)
{
@@ -724,7 +699,7 @@ disk_state_load_from_disk_impl(const char *fname)
return ret;
}
-/* Save the disk state to disk but before that update it from the current
+/** Save the disk state to disk but before that update it from the current
* state so we always have the latest. Return 0 on success else -1. */
static int
disk_state_save_to_disk(void)
@@ -768,7 +743,7 @@ disk_state_save_to_disk(void)
return ret;
}
-/* Reset our state to prepare for a new protocol run. Once this returns, all
+/** Reset our state to prepare for a new protocol run. Once this returns, all
* commits in the state will be removed and freed. */
STATIC void
reset_state_for_new_protocol_run(time_t valid_after)
@@ -789,7 +764,7 @@ reset_state_for_new_protocol_run(time_t valid_after)
sr_state_delete_commits();
}
-/* This is the first round of the new protocol run starting at
+/** This is the first round of the new protocol run starting at
* <b>valid_after</b>. Do the necessary housekeeping. */
STATIC void
new_protocol_run(time_t valid_after)
@@ -823,7 +798,7 @@ new_protocol_run(time_t valid_after)
}
}
-/* Return 1 iff the <b>next_phase</b> is a phase transition from the current
+/** Return 1 iff the <b>next_phase</b> is a phase transition from the current
* phase that is it's different. */
STATIC int
is_phase_transition(sr_phase_t next_phase)
@@ -831,7 +806,7 @@ is_phase_transition(sr_phase_t next_phase)
return sr_state->phase != next_phase;
}
-/* Helper function: return a commit using the RSA fingerprint of the
+/** Helper function: return a commit using the RSA fingerprint of the
* authority or NULL if no such commit is known. */
static sr_commit_t *
state_query_get_commit(const char *rsa_fpr)
@@ -840,7 +815,7 @@ state_query_get_commit(const char *rsa_fpr)
return digestmap_get(sr_state->commits, rsa_fpr);
}
-/* Helper function: This handles the GET state action using an
+/** Helper function: This handles the GET state action using an
* <b>obj_type</b> and <b>data</b> needed for the action. */
static void *
state_query_get_(sr_state_object_t obj_type, const void *data)
@@ -875,7 +850,7 @@ state_query_get_(sr_state_object_t obj_type, const void *data)
return obj;
}
-/* Helper function: This handles the PUT state action using an
+/** Helper function: This handles the PUT state action using an
* <b>obj_type</b> and <b>data</b> needed for the action.
* PUT frees the previous data before replacing it, if needed. */
static void
@@ -928,7 +903,7 @@ state_query_put_(sr_state_object_t obj_type, void *data)
}
}
-/* Helper function: This handles the DEL_ALL state action using an
+/** Helper function: This handles the DEL_ALL state action using an
* <b>obj_type</b> and <b>data</b> needed for the action. */
static void
state_query_del_all_(sr_state_object_t obj_type)
@@ -957,7 +932,7 @@ state_query_del_all_(sr_state_object_t obj_type)
}
}
-/* Helper function: This handles the DEL state action using an
+/** Helper function: This handles the DEL state action using an
* <b>obj_type</b> and <b>data</b> needed for the action. */
static void
state_query_del_(sr_state_object_t obj_type, void *data)
@@ -983,7 +958,7 @@ state_query_del_(sr_state_object_t obj_type, void *data)
}
}
-/* Query state using an <b>action</b> for an object type <b>obj_type</b>.
+/** Query state using an <b>action</b> for an object type <b>obj_type</b>.
* The <b>data</b> pointer needs to point to an object that the action needs
* to use and if anything is required to be returned, it is stored in
* <b>out</b>.
@@ -1025,7 +1000,7 @@ state_query(sr_state_action_t action, sr_state_object_t obj_type,
}
}
-/* Delete the current SRV value from the state freeing it and the value is set
+/** Delete the current SRV value from the state freeing it and the value is set
* to NULL meaning empty. */
STATIC void
state_del_current_srv(void)
@@ -1033,7 +1008,7 @@ state_del_current_srv(void)
state_query(SR_STATE_ACTION_DEL, SR_STATE_OBJ_CURSRV, NULL, NULL);
}
-/* Delete the previous SRV value from the state freeing it and the value is
+/** Delete the previous SRV value from the state freeing it and the value is
* set to NULL meaning empty. */
STATIC void
state_del_previous_srv(void)
@@ -1041,7 +1016,7 @@ state_del_previous_srv(void)
state_query(SR_STATE_ACTION_DEL, SR_STATE_OBJ_PREVSRV, NULL, NULL);
}
-/* Rotate SRV value by setting the previous SRV to the current SRV, and
+/** Rotate SRV value by setting the previous SRV to the current SRV, and
* clearing the current SRV. */
STATIC void
state_rotate_srv(void)
@@ -1054,7 +1029,7 @@ state_rotate_srv(void)
sr_state_set_current_srv(NULL);
}
-/* Set valid after time in the our state. */
+/** Set valid after time in the our state. */
void
sr_state_set_valid_after(time_t valid_after)
{
@@ -1062,7 +1037,7 @@ sr_state_set_valid_after(time_t valid_after)
(void *) &valid_after, NULL);
}
-/* Return the phase we are currently in according to our state. */
+/** Return the phase we are currently in according to our state. */
sr_phase_t
sr_state_get_phase(void)
{
@@ -1072,7 +1047,7 @@ sr_state_get_phase(void)
return *(sr_phase_t *) ptr;
}
-/* Return the previous SRV value from our state. Value CAN be NULL.
+/** Return the previous SRV value from our state. Value CAN be NULL.
* The state object owns the SRV, so the calling code should not free the SRV.
* Use sr_srv_dup() if you want to keep a copy of the SRV. */
const sr_srv_t *
@@ -1084,7 +1059,7 @@ sr_state_get_previous_srv(void)
return srv;
}
-/* Set the current SRV value from our state. Value CAN be NULL. The srv
+/** Set the current SRV value from our state. Value CAN be NULL. The srv
* object ownership is transferred to the state object. */
void
sr_state_set_previous_srv(const sr_srv_t *srv)
@@ -1093,7 +1068,7 @@ sr_state_set_previous_srv(const sr_srv_t *srv)
NULL);
}
-/* Return the current SRV value from our state. Value CAN be NULL.
+/** Return the current SRV value from our state. Value CAN be NULL.
* The state object owns the SRV, so the calling code should not free the SRV.
* Use sr_srv_dup() if you want to keep a copy of the SRV. */
const sr_srv_t *
@@ -1105,7 +1080,7 @@ sr_state_get_current_srv(void)
return srv;
}
-/* Set the current SRV value from our state. Value CAN be NULL. The srv
+/** Set the current SRV value from our state. Value CAN be NULL. The srv
* object ownership is transferred to the state object. */
void
sr_state_set_current_srv(const sr_srv_t *srv)
@@ -1114,7 +1089,7 @@ sr_state_set_current_srv(const sr_srv_t *srv)
NULL);
}
-/* Clean all the SRVs in our state. */
+/** Clean all the SRVs in our state. */
void
sr_state_clean_srvs(void)
{
@@ -1123,7 +1098,7 @@ sr_state_clean_srvs(void)
state_del_current_srv();
}
-/* Return a pointer to the commits map from our state. CANNOT be NULL. */
+/** Return a pointer to the commits map from our state. CANNOT be NULL. */
digestmap_t *
sr_state_get_commits(void)
{
@@ -1134,7 +1109,7 @@ sr_state_get_commits(void)
return commits;
}
-/* Update the current SR state as needed for the upcoming voting round at
+/** Update the current SR state as needed for the upcoming voting round at
* <b>valid_after</b>. */
void
sr_state_update(time_t valid_after)
@@ -1198,7 +1173,7 @@ sr_state_update(time_t valid_after)
}
}
-/* Return commit object from the given authority digest <b>rsa_identity</b>.
+/** Return commit object from the given authority digest <b>rsa_identity</b>.
* Return NULL if not found. */
sr_commit_t *
sr_state_get_commit(const char *rsa_identity)
@@ -1212,7 +1187,7 @@ sr_state_get_commit(const char *rsa_identity)
return commit;
}
-/* Add <b>commit</b> to the permanent state. The commit object ownership is
+/** Add <b>commit</b> to the permanent state. The commit object ownership is
* transferred to the state so the caller MUST not free it. */
void
sr_state_add_commit(sr_commit_t *commit)
@@ -1227,14 +1202,14 @@ sr_state_add_commit(sr_commit_t *commit)
sr_commit_get_rsa_fpr(commit));
}
-/* Remove all commits from our state. */
+/** Remove all commits from our state. */
void
sr_state_delete_commits(void)
{
state_query(SR_STATE_ACTION_DEL_ALL, SR_STATE_OBJ_COMMIT, NULL, NULL);
}
-/* Copy the reveal information from <b>commit</b> into <b>saved_commit</b>.
+/** Copy the reveal information from <b>commit</b> into <b>saved_commit</b>.
* This <b>saved_commit</b> MUST come from our current SR state. Once modified,
* the disk state is updated. */
void
@@ -1255,7 +1230,7 @@ sr_state_copy_reveal_info(sr_commit_t *saved_commit, const sr_commit_t *commit)
sr_commit_get_rsa_fpr(saved_commit));
}
-/* Set the fresh SRV flag from our state. This doesn't need to trigger a
+/** Set the fresh SRV flag from our state. This doesn't need to trigger a
* disk state synchronization so we directly change the state. */
void
sr_state_set_fresh_srv(void)
@@ -1263,7 +1238,7 @@ sr_state_set_fresh_srv(void)
sr_state->is_srv_fresh = 1;
}
-/* Unset the fresh SRV flag from our state. This doesn't need to trigger a
+/** Unset the fresh SRV flag from our state. This doesn't need to trigger a
* disk state synchronization so we directly change the state. */
void
sr_state_unset_fresh_srv(void)
@@ -1271,14 +1246,14 @@ sr_state_unset_fresh_srv(void)
sr_state->is_srv_fresh = 0;
}
-/* Return the value of the fresh SRV flag. */
+/** Return the value of the fresh SRV flag. */
unsigned int
sr_state_srv_is_fresh(void)
{
return sr_state->is_srv_fresh;
}
-/* Cleanup and free our disk and memory state. */
+/** Cleanup and free our disk and memory state. */
void
sr_state_free_all(void)
{
@@ -1290,7 +1265,7 @@ sr_state_free_all(void)
config_mgr_free(shared_random_state_mgr);
}
-/* Save our current state in memory to disk. */
+/** Save our current state in memory to disk. */
void
sr_state_save(void)
{
@@ -1298,7 +1273,7 @@ sr_state_save(void)
state_query(SR_STATE_ACTION_SAVE, 0, NULL, NULL);
}
-/* Return 1 iff the state has been initialized that is it exists in memory.
+/** Return 1 iff the state has been initialized that is it exists in memory.
* Return 0 otherwise. */
int
sr_state_is_initialized(void)
@@ -1306,7 +1281,7 @@ sr_state_is_initialized(void)
return sr_state == NULL ? 0 : 1;
}
-/* Initialize the disk and memory state.
+/** Initialize the disk and memory state.
*
* If save_to_disk is set to 1, the state is immediately saved to disk after
* creation else it's not thus only kept in memory.
@@ -1358,7 +1333,7 @@ sr_state_init(int save_to_disk, int read_from_disk)
/* We have a state in memory, let's make sure it's updated for the current
* and next voting round. */
{
- time_t valid_after = voting_schedule_get_next_valid_after_time();
+ time_t valid_after = dirauth_sched_get_next_valid_after_time();
sr_state_update(valid_after);
}
return 0;
@@ -1369,7 +1344,7 @@ sr_state_init(int save_to_disk, int read_from_disk)
#ifdef TOR_UNIT_TESTS
-/* Set the current phase of the protocol. Used only by unit tests. */
+/** Set the current phase of the protocol. Used only by unit tests. */
void
set_sr_phase(sr_phase_t phase)
{
@@ -1378,7 +1353,7 @@ set_sr_phase(sr_phase_t phase)
sr_state->phase = phase;
}
-/* Get the SR state. Used only by unit tests */
+/** Get the SR state. Used only by unit tests */
sr_state_t *
get_sr_state(void)
{
diff --git a/src/feature/dirauth/shared_random_state.h b/src/feature/dirauth/shared_random_state.h
index 08f999f9d4..3a34bcc3e7 100644
--- a/src/feature/dirauth/shared_random_state.h
+++ b/src/feature/dirauth/shared_random_state.h
@@ -1,12 +1,17 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file shared_random_state.h
+ * @brief Header for shared_random_state.c
+ **/
+
#ifndef TOR_SHARED_RANDOM_STATE_H
#define TOR_SHARED_RANDOM_STATE_H
#include "feature/dirauth/shared_random.h"
-/* Action that can be performed on the state for any objects. */
+/** Action that can be performed on the state for any objects. */
typedef enum {
SR_STATE_ACTION_GET = 1,
SR_STATE_ACTION_PUT = 2,
@@ -15,52 +20,53 @@ typedef enum {
SR_STATE_ACTION_SAVE = 5,
} sr_state_action_t;
-/* Object in the state that can be queried through the state API. */
+/** Object in the state that can be queried through the state API. */
typedef enum {
- /* Will return a single commit using an authority identity key. */
+ /** Will return a single commit using an authority identity key. */
SR_STATE_OBJ_COMMIT,
- /* Returns the entire list of commits from the state. */
+ /** Returns the entire list of commits from the state. */
SR_STATE_OBJ_COMMITS,
- /* Return the current SRV object pointer. */
+ /** Return the current SRV object pointer. */
SR_STATE_OBJ_CURSRV,
- /* Return the previous SRV object pointer. */
+ /** Return the previous SRV object pointer. */
SR_STATE_OBJ_PREVSRV,
- /* Return the phase. */
+ /** Return the phase. */
SR_STATE_OBJ_PHASE,
- /* Get or Put the valid after time. */
+ /** Get or Put the valid after time. */
SR_STATE_OBJ_VALID_AFTER,
} sr_state_object_t;
-/* State of the protocol. It's also saved on disk in fname. This data
+/** State of the protocol. It's also saved on disk in fname. This data
* structure MUST be synchronized at all time with the one on disk. */
typedef struct sr_state_t {
- /* Filename of the state file on disk. */
+ /** Filename of the state file on disk. */
char *fname;
- /* Version of the protocol. */
+ /** Version of the protocol. */
uint32_t version;
- /* The valid-after of the voting period we have prepared the state for. */
+ /** The valid-after of the voting period we have prepared the state for. */
time_t valid_after;
- /* Until when is this state valid? */
+ /** Until when is this state valid? */
time_t valid_until;
- /* Protocol phase. */
+ /** Protocol phase. */
sr_phase_t phase;
- /* Number of runs completed. */
+ /** Number of runs completed. */
uint64_t n_protocol_runs;
- /* The number of commitment rounds we've performed in this protocol run. */
+ /** The number of commitment rounds we've performed in this protocol run. */
unsigned int n_commit_rounds;
- /* The number of reveal rounds we've performed in this protocol run. */
+ /** The number of reveal rounds we've performed in this protocol run. */
unsigned int n_reveal_rounds;
- /* A map of all the received commitments for this protocol run. This is
+ /** A map of all the received commitments for this protocol run. This is
* indexed by authority RSA identity digest. */
digestmap_t *commits;
- /* Current and previous shared random value. */
+ /** Current shared random value. */
sr_srv_t *previous_srv;
+ /** Previous shared random value. */
sr_srv_t *current_srv;
- /* Indicate if the state contains an SRV that was _just_ generated. This is
+ /** Indicate if the state contains an SRV that was _just_ generated. This is
* used during voting so that we know whether to use the super majority rule
* or not when deciding on keeping it for the consensus. It is _always_ set
* to 0 post consensus.
@@ -73,22 +79,22 @@ typedef struct sr_state_t {
unsigned int is_srv_fresh:1;
} sr_state_t;
-/* Persistent state of the protocol, as saved to disk. */
+/** Persistent state of the protocol, as saved to disk. */
typedef struct sr_disk_state_t {
uint32_t magic_;
- /* Version of the protocol. */
+ /** Version of the protocol. */
int Version;
- /* Version of our running tor. */
+ /** Version of our running tor. */
char *TorVersion;
- /* Creation time of this state */
+ /** Creation time of this state */
time_t ValidAfter;
- /* State valid until? */
+ /** State valid until? */
time_t ValidUntil;
- /* All commits seen that are valid. */
+ /** All commits seen that are valid. */
struct config_line_t *Commit;
- /* Previous and current shared random value. */
+ /** Previous and current shared random value. */
struct config_line_t *SharedRandValues;
- /* Extra Lines for configuration we might not know. */
+ /** Extra Lines for configuration we might not know. */
struct config_line_t *ExtraLines;
} sr_disk_state_t;
diff --git a/src/feature/dirauth/vote_microdesc_hash_st.h b/src/feature/dirauth/vote_microdesc_hash_st.h
index 7869f92b4f..7f8ebf7fd7 100644
--- a/src/feature/dirauth/vote_microdesc_hash_st.h
+++ b/src/feature/dirauth/vote_microdesc_hash_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file vote_microdesc_hash_st.h
+ * @brief Microdescriptor-hash voting strcture.
+ **/
+
#ifndef VOTE_MICRODESC_HASH_ST_H
#define VOTE_MICRODESC_HASH_ST_H
@@ -19,4 +24,3 @@ struct vote_microdesc_hash_t {
};
#endif /* !defined(VOTE_MICRODESC_HASH_ST_H) */
-
diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c
index f552af98c4..477eb6f0b7 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,6 +18,7 @@
#include "core/or/policies.h"
#include "feature/dirauth/bwauth.h"
#include "feature/dirauth/reachability.h"
+#include "feature/dirauth/dirauth_sys.h"
#include "feature/hibernate/hibernate.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/networkstatus.h"
@@ -27,6 +28,7 @@
#include "feature/relay/router.h"
#include "feature/stats/rephist.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerlist_st.h"
@@ -145,7 +147,7 @@ router_is_active(const routerinfo_t *ri, const node_t *node, time_t now)
* if TestingTorNetwork, and TestingMinExitFlagThreshold is non-zero */
if (!ri->bandwidthcapacity) {
if (get_options()->TestingTorNetwork) {
- if (get_options()->TestingMinExitFlagThreshold > 0) {
+ if (dirauth_get_options()->TestingMinExitFlagThreshold > 0) {
/* If we're in a TestingTorNetwork, and TestingMinExitFlagThreshold is,
* then require bandwidthcapacity */
return 0;
@@ -175,14 +177,14 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
long uptime;
/* If we haven't been running for at least
- * get_options()->MinUptimeHidServDirectoryV2 seconds, we can't
+ * MinUptimeHidServDirectoryV2 seconds, we can't
* have accurate data telling us a relay has been up for at least
* that long. We also want to allow a bit of slack: Reachability
* tests aren't instant. If we haven't been running long enough,
* trust the relay. */
if (get_uptime() >
- get_options()->MinUptimeHidServDirectoryV2 * 1.1)
+ dirauth_get_options()->MinUptimeHidServDirectoryV2 * 1.1)
uptime = MIN(rep_hist_get_uptime(router->cache_info.identity_digest, now),
real_uptime(router, now));
else
@@ -191,7 +193,7 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
return (router->wants_to_be_hs_dir &&
router->supports_tunnelled_dir_requests &&
node->is_stable && node->is_fast &&
- uptime >= get_options()->MinUptimeHidServDirectoryV2 &&
+ uptime >= dirauth_get_options()->MinUptimeHidServDirectoryV2 &&
router_is_active(router, node, now));
}
@@ -214,9 +216,10 @@ router_counts_toward_thresholds(const node_t *node, time_t now,
dirserv_has_measured_bw(node->identity);
uint64_t min_bw_kb = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB;
const or_options_t *options = get_options();
+ const dirauth_options_t *dirauth_options = dirauth_get_options();
if (options->TestingTorNetwork) {
- min_bw_kb = (int64_t)options->TestingMinExitFlagThreshold / 1000;
+ min_bw_kb = (int64_t)dirauth_options->TestingMinExitFlagThreshold / 1000;
}
return node->ri && router_is_active(node->ri, node, now) &&
@@ -242,11 +245,12 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
const smartlist_t *nodelist;
time_t now = time(NULL);
const or_options_t *options = get_options();
+ const dirauth_options_t *dirauth_options = dirauth_get_options();
/* Require mbw? */
int require_mbw =
(dirserv_get_last_n_measured_bws() >
- options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0;
+ dirauth_options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0;
/* initialize these all here, in case there are no routers */
stable_uptime = 0;
@@ -338,7 +342,7 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG,
INT32_MAX);
if (options->TestingTorNetwork) {
- min_fast = (int32_t)options->TestingMinFastFlagThreshold;
+ min_fast = (int32_t)dirauth_options->TestingMinFastFlagThreshold;
}
max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold",
INT32_MAX, min_fast, INT32_MAX);
@@ -352,9 +356,11 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
}
/* Protect sufficiently fast nodes from being pushed out of the set
* of Fast nodes. */
- if (options->AuthDirFastGuarantee &&
- fast_bandwidth_kb > options->AuthDirFastGuarantee/1000)
- fast_bandwidth_kb = (uint32_t)options->AuthDirFastGuarantee/1000;
+ {
+ const uint64_t fast_opt = dirauth_get_options()->AuthDirFastGuarantee;
+ if (fast_opt && fast_bandwidth_kb > fast_opt / 1000)
+ fast_bandwidth_kb = (uint32_t)(fast_opt / 1000);
+ }
/* Now that we have a time-known that 7/8 routers are known longer than,
* fill wfus with the wfu of every such "familiar" router. */
@@ -428,7 +434,7 @@ dirserv_get_flag_thresholds_line(void)
{
char *result=NULL;
const int measured_threshold =
- get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
+ dirauth_get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
const int enough_measured_bw =
dirserv_get_last_n_measured_bws() > measured_threshold;
@@ -455,8 +461,9 @@ dirserv_get_flag_thresholds_line(void)
int
running_long_enough_to_decide_unreachable(void)
{
- return time_of_process_start
- + get_options()->TestingAuthDirTimeToLearnReachability < approx_time();
+ const dirauth_options_t *opts = dirauth_get_options();
+ return time_of_process_start +
+ opts->TestingAuthDirTimeToLearnReachability < approx_time();
}
/** Each server needs to have passed a reachability test no more
@@ -481,6 +488,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
*/
int answer;
const or_options_t *options = get_options();
+ const dirauth_options_t *dirauth_options = dirauth_get_options();
node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest);
tor_assert(node);
@@ -507,7 +515,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
IPv6 OR port since that'd kill all dual stack relays until a
majority of the dir auths have IPv6 connectivity. */
answer = (now < node->last_reachable + REACHABLE_TIMEOUT &&
- (options->AuthDirHasIPv6Connectivity != 1 ||
+ (dirauth_options->AuthDirHasIPv6Connectivity != 1 ||
tor_addr_is_null(&router->ipv6_addr) ||
now < node->last_reachable6 + REACHABLE_TIMEOUT));
}
@@ -538,7 +546,7 @@ static int
should_publish_node_ipv6(const node_t *node, const routerinfo_t *ri,
time_t now)
{
- const or_options_t *options = get_options();
+ const dirauth_options_t *options = dirauth_get_options();
return options->AuthDirHasIPv6Connectivity == 1 &&
!tor_addr_is_null(&ri->ipv6_addr) &&
@@ -571,10 +579,10 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
set_routerstatus_from_routerinfo(rs, node, ri);
/* Override rs->is_possible_guard. */
+ const uint64_t bw_opt = dirauth_get_options()->AuthDirGuardBWGuarantee;
if (node->is_fast && node->is_stable &&
ri->supports_tunnelled_dir_requests &&
- ((options->AuthDirGuardBWGuarantee &&
- routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) ||
+ ((bw_opt && routerbw_kb >= bw_opt / 1000) ||
routerbw_kb >= MIN(guard_bandwidth_including_exits_kb,
guard_bandwidth_excluding_exits_kb))) {
long tk = rep_hist_get_weighted_time_known(
@@ -612,9 +620,9 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
STATIC void
dirserv_set_routerstatus_testing(routerstatus_t *rs)
{
- const or_options_t *options = get_options();
+ const dirauth_options_t *options = dirauth_get_options();
- tor_assert(options->TestingTorNetwork);
+ tor_assert(get_options()->TestingTorNetwork);
if (routerset_contains_routerstatus(options->TestingDirAuthVoteExit,
rs, 0)) {
diff --git a/src/feature/dirauth/voteflags.h b/src/feature/dirauth/voteflags.h
index c4f36e7817..91f3854573 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircommon/voting_schedule.c b/src/feature/dirauth/voting_schedule.c
index 5576ec69f7..efc4a0b316 100644
--- a/src/feature/dircommon/voting_schedule.c
+++ b/src/feature/dirauth/voting_schedule.c
@@ -1,15 +1,13 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file voting_schedule.c
- * \brief This file contains functions that are from the directory authority
- * subsystem related to voting specifically but used by many part of
- * tor. The full feature is built as part of the dirauth module.
+ * \brief Compute information about our voting schedule as a directory
+ * authority.
**/
-#define VOTING_SCHEDULE_PRIVATE
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "core/or/or.h"
#include "app/config/config.h"
@@ -21,55 +19,11 @@
* Vote scheduling
* ===== */
-/** Return the start of the next interval of size <b>interval</b> (in
- * seconds) after <b>now</b>, plus <b>offset</b>. Midnight always
- * starts a fresh interval, and if the last interval of a day would be
- * truncated to less than half its size, it is rolled into the
- * previous interval. */
-time_t
-voting_schedule_get_start_of_next_interval(time_t now, int interval,
- int offset)
-{
- struct tm tm;
- time_t midnight_today=0;
- time_t midnight_tomorrow;
- time_t next;
-
- tor_gmtime_r(&now, &tm);
- tm.tm_hour = 0;
- tm.tm_min = 0;
- tm.tm_sec = 0;
-
- if (tor_timegm(&tm, &midnight_today) < 0) {
- // LCOV_EXCL_START
- log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight.");
- // LCOV_EXCL_STOP
- }
- midnight_tomorrow = midnight_today + (24*60*60);
-
- next = midnight_today + ((now-midnight_today)/interval + 1)*interval;
-
- /* Intervals never cross midnight. */
- if (next > midnight_tomorrow)
- next = midnight_tomorrow;
-
- /* If the interval would only last half as long as it's supposed to, then
- * skip over to the next day. */
- if (next + interval/2 > midnight_tomorrow)
- next = midnight_tomorrow;
-
- next += offset;
- if (next - interval > now)
- next -= interval;
-
- return next;
-}
-
/* Populate and return a new voting_schedule_t that can be used to schedule
* voting. The object is allocated on the heap and it's the responsibility of
* the caller to free it. Can't fail. */
static voting_schedule_t *
-get_voting_schedule(const or_options_t *options, time_t now, int severity)
+create_voting_schedule(const or_options_t *options, time_t now, int severity)
{
int interval, vote_delay, dist_delay;
time_t start;
@@ -96,14 +50,15 @@ get_voting_schedule(const or_options_t *options, time_t now, int severity)
}
tor_assert(interval > 0);
+ new_voting_schedule->interval = interval;
if (vote_delay + dist_delay > interval/2)
vote_delay = dist_delay = interval / 4;
start = new_voting_schedule->interval_starts =
- voting_schedule_get_start_of_next_interval(now,interval,
+ voting_sched_get_start_of_interval_after(now,interval,
options->TestingV3AuthVotingStartOffset);
- end = voting_schedule_get_start_of_next_interval(start+1, interval,
+ end = voting_sched_get_start_of_interval_after(start+1, interval,
options->TestingV3AuthVotingStartOffset);
tor_assert(end > start);
@@ -140,9 +95,13 @@ voting_schedule_free_(voting_schedule_t *voting_schedule_to_free)
voting_schedule_t voting_schedule;
-/* Using the time <b>now</b>, return the next voting valid-after time. */
-time_t
-voting_schedule_get_next_valid_after_time(void)
+/**
+ * Return the current voting schedule, recreating it if necessary.
+ *
+ * Dirauth only.
+ **/
+static const voting_schedule_t *
+dirauth_get_voting_schedule(void)
{
time_t now = approx_time();
bool need_to_recalculate_voting_schedule = false;
@@ -168,27 +127,62 @@ voting_schedule_get_next_valid_after_time(void)
done:
if (need_to_recalculate_voting_schedule) {
- voting_schedule_recalculate_timing(get_options(), approx_time());
+ dirauth_sched_recalculate_timing(get_options(), approx_time());
voting_schedule.created_on_demand = 1;
}
- return voting_schedule.interval_starts;
+ return &voting_schedule;
+}
+
+/** Return the next voting valid-after time.
+ *
+ * Dirauth only. */
+time_t
+dirauth_sched_get_next_valid_after_time(void)
+{
+ return dirauth_get_voting_schedule()->interval_starts;
+}
+
+/**
+ * Return our best idea of what the valid-after time for the _current_
+ * consensus, whether we have one or not.
+ *
+ * Dirauth only.
+ **/
+time_t
+dirauth_sched_get_cur_valid_after_time(void)
+{
+ const voting_schedule_t *sched = dirauth_get_voting_schedule();
+ time_t next_start = sched->interval_starts;
+ int interval = sched->interval;
+ int offset = get_options()->TestingV3AuthVotingStartOffset;
+ return voting_sched_get_start_of_interval_after(next_start - interval - 1,
+ interval,
+ offset);
+}
+
+/** Return the voting interval that we are configured to use.
+ *
+ * Dirauth only. */
+int
+dirauth_sched_get_configured_interval(void)
+{
+ return get_options()->V3AuthVotingInterval;
}
/** Set voting_schedule to hold the timing for the next vote we should be
* doing. All type of tor do that because HS subsystem needs the timing as
* well to function properly. */
void
-voting_schedule_recalculate_timing(const or_options_t *options, time_t now)
+dirauth_sched_recalculate_timing(const or_options_t *options, time_t now)
{
voting_schedule_t *new_voting_schedule;
/* get the new voting schedule */
- new_voting_schedule = get_voting_schedule(options, now, LOG_INFO);
+ new_voting_schedule = create_voting_schedule(options, now, LOG_INFO);
tor_assert(new_voting_schedule);
/* Fill in the global static struct now */
memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule));
voting_schedule_free(new_voting_schedule);
}
-
diff --git a/src/feature/dircommon/voting_schedule.h b/src/feature/dirauth/voting_schedule.h
index d78c7ee2da..9e2ac29c75 100644
--- a/src/feature/dircommon/voting_schedule.h
+++ b/src/feature/dirauth/voting_schedule.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,6 +11,8 @@
#include "core/or/or.h"
+#ifdef HAVE_MODULE_DIRAUTH
+
/** Scheduling information for a voting interval. */
typedef struct {
/** When do we generate and distribute our vote for this interval? */
@@ -26,15 +28,18 @@ typedef struct {
/** When do we publish the consensus? */
time_t interval_starts;
- /* True iff we have generated and distributed our vote. */
+ /** Our computed dirauth interval */
+ int interval;
+
+ /** True iff we have generated and distributed our vote. */
int have_voted;
- /* True iff we've requested missing votes. */
+ /** True iff we've requested missing votes. */
int have_fetched_missing_votes;
- /* True iff we have built a consensus and sent the signatures around. */
+ /** True iff we have built a consensus and sent the signatures around. */
int have_built_consensus;
- /* True iff we've fetched missing signatures. */
+ /** True iff we've fetched missing signatures. */
int have_fetched_missing_signatures;
- /* True iff we have published our consensus. */
+ /** True iff we have published our consensus. */
int have_published_consensus;
/* True iff this voting schedule was set on demand meaning not through the
@@ -53,13 +58,36 @@ typedef struct {
extern voting_schedule_t voting_schedule;
-void voting_schedule_recalculate_timing(const or_options_t *options,
+void dirauth_sched_recalculate_timing(const or_options_t *options,
time_t now);
-time_t voting_schedule_get_start_of_next_interval(time_t now,
- int interval,
- int offset);
-time_t voting_schedule_get_next_valid_after_time(void);
+time_t dirauth_sched_get_next_valid_after_time(void);
+time_t dirauth_sched_get_cur_valid_after_time(void);
+int dirauth_sched_get_configured_interval(void);
-#endif /* !defined(TOR_VOTING_SCHEDULE_H) */
+#else /* !defined(HAVE_MODULE_DIRAUTH) */
+#define dirauth_sched_recalculate_timing(opt,now) \
+ ((void)(opt), (void)(now))
+
+static inline time_t
+dirauth_sched_get_next_valid_after_time(void)
+{
+ tor_assert_unreached();
+ return 0;
+}
+static inline time_t
+dirauth_sched_get_cur_valid_after_time(void)
+{
+ tor_assert_unreached();
+ return 0;
+}
+static inline int
+dirauth_sched_get_configured_interval(void)
+{
+ tor_assert_unreached();
+ return 1;
+}
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
+
+#endif /* !defined(TOR_VOTING_SCHEDULE_H) */
diff --git a/src/feature/dircache/.may_include b/src/feature/dircache/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/dircache/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/dircache/cached_dir_st.h b/src/feature/dircache/cached_dir_st.h
index a28802f905..ede1d028da 100644
--- a/src/feature/dircache/cached_dir_st.h
+++ b/src/feature/dircache/cached_dir_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file cached_dir_st.h
+ * @brief Cached large directory object structure.
+ **/
+
#ifndef CACHED_DIR_ST_H
#define CACHED_DIR_ST_H
@@ -22,4 +27,3 @@ struct cached_dir_t {
};
#endif /* !defined(CACHED_DIR_ST_H) */
-
diff --git a/src/feature/dircache/conscache.c b/src/feature/dircache/conscache.c
index 2ec9981c03..2a831aa447 100644
--- a/src/feature/dircache/conscache.c
+++ b/src/feature/dircache/conscache.c
@@ -1,6 +1,11 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file conscache.c
+ * @brief Consensus and diff on-disk cache.
+ **/
+
#include "core/or/or.h"
#include "app/config/config.h"
@@ -127,13 +132,22 @@ consensus_cache_may_overallocate(consensus_cache_t *cache)
#endif
}
+// HACK: GCC on Appveyor hates that we may assert before returning. Work around
+// the error.
+#ifdef _WIN32
+#ifndef COCCI
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
+#endif
+#endif /* defined(_WIN32) */
+
/**
* Tell the sandbox (if any) configured by <b>cfg</b> to allow the
* operations that <b>cache</b> will need.
*/
int
consensus_cache_register_with_sandbox(consensus_cache_t *cache,
- struct sandbox_cfg_elem **cfg)
+ struct sandbox_cfg_elem_t **cfg)
{
#ifdef MUST_UNMAP_TO_UNLINK
/* Our Linux sandbox doesn't support huge file lists like the one that would
@@ -151,6 +165,12 @@ consensus_cache_register_with_sandbox(consensus_cache_t *cache,
return storage_dir_register_with_sandbox(cache->dir, cfg);
}
+#ifdef _WIN32
+#ifndef COCCI
+#pragma GCC diagnostic pop
+#endif
+#endif
+
/**
* Helper: clear all entries from <b>cache</b> (but do not delete
* any that aren't marked for removal
@@ -246,7 +266,7 @@ consensus_cache_find_first(consensus_cache_t *cache,
}
/**
- * Given a <b>cache</b>, add every entry to <b>out<b> for which
+ * Given a <b>cache</b>, add every entry to <b>out</b> for which
* <b>key</b>=<b>value</b>. If <b>key</b> is NULL, add every entry.
*
* Do not add any entry that has been marked for removal.
diff --git a/src/feature/dircache/conscache.h b/src/feature/dircache/conscache.h
index d848e57617..ace5908e40 100644
--- a/src/feature/dircache/conscache.h
+++ b/src/feature/dircache/conscache.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file conscache.h
+ * @brief Header for conscache.c
+ **/
+
#ifndef TOR_CONSCACHE_H
#define TOR_CONSCACHE_H
@@ -9,6 +14,8 @@
typedef struct consensus_cache_entry_t consensus_cache_entry_t;
typedef struct consensus_cache_t consensus_cache_t;
+struct config_line_t;
+
HANDLE_DECL(consensus_cache_entry, consensus_cache_entry_t, )
#define consensus_cache_entry_handle_free(h) \
FREE_AND_NULL(consensus_cache_entry_handle_t, \
@@ -18,10 +25,10 @@ consensus_cache_t *consensus_cache_open(const char *subdir, int max_entries);
void consensus_cache_free_(consensus_cache_t *cache);
#define consensus_cache_free(cache) \
FREE_AND_NULL(consensus_cache_t, consensus_cache_free_, (cache))
-struct sandbox_cfg_elem;
+struct sandbox_cfg_elem_t;
int consensus_cache_may_overallocate(consensus_cache_t *cache);
int consensus_cache_register_with_sandbox(consensus_cache_t *cache,
- struct sandbox_cfg_elem **cfg);
+ struct sandbox_cfg_elem_t **cfg);
void consensus_cache_unmap_lazy(consensus_cache_t *cache, time_t cutoff);
void consensus_cache_delete_pending(consensus_cache_t *cache,
int force);
diff --git a/src/feature/dircache/consdiffmgr.c b/src/feature/dircache/consdiffmgr.c
index 397efa0341..10590cd6d2 100644
--- a/src/feature/dircache/consdiffmgr.c
+++ b/src/feature/dircache/consdiffmgr.c
@@ -1,8 +1,8 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file consdiffmsr.c
+ * \file consdiffmgr.c
*
* \brief consensus diff manager functions
*
@@ -218,9 +218,9 @@ cdm_diff_eq(const cdm_diff_t *diff1, const cdm_diff_t *diff2)
diff1->compress_method == diff2->compress_method;
}
-HT_PROTOTYPE(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq)
+HT_PROTOTYPE(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq);
HT_GENERATE2(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq,
- 0.6, tor_reallocarray, tor_free_)
+ 0.6, tor_reallocarray, tor_free_);
#define cdm_diff_free(diff) \
FREE_AND_NULL(cdm_diff_t, cdm_diff_free_, (diff))
@@ -844,7 +844,7 @@ consdiffmgr_configure(const consdiff_cfg_t *cfg)
* operations that the consensus diff manager will need.
*/
int
-consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem **cfg)
+consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem_t **cfg)
{
return consensus_cache_register_with_sandbox(cdm_cache_get(), cfg);
}
@@ -1293,7 +1293,7 @@ typedef struct compressed_result_t {
/**
* Compress the bytestring <b>input</b> of length <b>len</b> using the
- * <n>n_methods</b> compression methods listed in the array <b>methods</b>.
+ * <b>n_methods</b> compression methods listed in the array <b>methods</b>.
*
* For each successful compression, set the fields in the <b>results_out</b>
* array in the position corresponding to the compression method. Use
diff --git a/src/feature/dircache/consdiffmgr.h b/src/feature/dircache/consdiffmgr.h
index b1b3323b6c..27b8165e94 100644
--- a/src/feature/dircache/consdiffmgr.h
+++ b/src/feature/dircache/consdiffmgr.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file consdiffmgr.h
+ * @brief Header for consdiffmgr.c
+ **/
+
#ifndef TOR_CONSDIFFMGR_H
#define TOR_CONSDIFFMGR_H
@@ -55,23 +60,25 @@ void consdiffmgr_rescan(void);
int consdiffmgr_cleanup(void);
void consdiffmgr_enable_background_compression(void);
void consdiffmgr_configure(const consdiff_cfg_t *cfg);
-struct sandbox_cfg_elem;
-int consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem **cfg);
+struct sandbox_cfg_elem_t;
+int consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem_t **cfg);
void consdiffmgr_free_all(void);
int consdiffmgr_validate(void);
#ifdef CONSDIFFMGR_PRIVATE
+struct consensus_cache_t;
+struct consensus_cache_entry_t;
STATIC unsigned n_diff_compression_methods(void);
STATIC unsigned n_consensus_compression_methods(void);
-STATIC consensus_cache_t *cdm_cache_get(void);
-STATIC consensus_cache_entry_t *cdm_cache_lookup_consensus(
+STATIC struct consensus_cache_t *cdm_cache_get(void);
+STATIC struct consensus_cache_entry_t *cdm_cache_lookup_consensus(
consensus_flavor_t flavor, time_t valid_after);
STATIC int cdm_entry_get_sha3_value(uint8_t *digest_out,
- consensus_cache_entry_t *ent,
+ struct consensus_cache_entry_t *ent,
const char *label);
STATIC int uncompress_or_set_ptr(const char **out, size_t *outlen,
char **owned_out,
- consensus_cache_entry_t *ent);
+ struct consensus_cache_entry_t *ent);
#endif /* defined(CONSDIFFMGR_PRIVATE) */
#ifdef TOR_UNIT_TESTS
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
index 59cdcc5e02..ca127720f2 100644
--- a/src/feature/dircache/dircache.c
+++ b/src/feature/dircache/dircache.c
@@ -1,13 +1,19 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dircache.c
+ * @brief Cache directories and serve them to clients.
+ **/
+
#define DIRCACHE_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/mainloop/connection.h"
#include "core/or/relay.h"
#include "feature/dirauth/dirvote.h"
@@ -23,6 +29,7 @@
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/networkstatus.h"
#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"
@@ -328,7 +335,7 @@ typedef struct get_handler_args_t {
* an arguments structure, and must return 0 on success or -1 if we should
* close the connection.
**/
-typedef struct url_table_ent_s {
+typedef struct url_table_ent_t {
const char *string;
int is_prefix;
int (*handler)(dir_connection_t *conn, const get_handler_args_t *args);
@@ -473,7 +480,7 @@ static int
handle_get_frontpage(dir_connection_t *conn, const get_handler_args_t *args)
{
(void) args; /* unused */
- const char *frontpage = get_dirportfrontpage();
+ const char *frontpage = relay_get_dirportfrontpage();
if (frontpage) {
size_t dlen;
@@ -560,7 +567,7 @@ parse_one_diff_hash(uint8_t *digest, const char *hex, const char *location,
}
/** If there is an X-Or-Diff-From-Consensus header included in <b>headers</b>,
- * set <b>digest_out<b> to a new smartlist containing every 256-bit
+ * set <b>digest_out</b> to a new smartlist containing every 256-bit
* hex-encoded digest listed in that header and return 0. Otherwise return
* -1. */
static int
@@ -1378,7 +1385,7 @@ handle_get_hs_descriptor_v2(dir_connection_t *conn,
return 0;
}
-/** Helper function for GET /tor/hs/3/<z>. 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,
@@ -1689,7 +1696,7 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
!strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */
const char *msg = "OK";
int status;
- if (dirvote_add_vote(body, &msg, &status)) {
+ if (dirvote_add_vote(body, approx_time(), &msg, &status)) {
write_short_http_response(conn, status, "Vote stored");
} else {
tor_assert(msg);
diff --git a/src/feature/dircache/dircache.h b/src/feature/dircache/dircache.h
index de0d205f6a..d6392e2d42 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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
new file mode 100644
index 0000000000..87811597d1
--- /dev/null
+++ b/src/feature/dircache/dircache_stub.c
@@ -0,0 +1,78 @@
+/* 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 dircache_stub.c
+ * @brief Stub declarations for use when dircache module is disabled.
+ **/
+
+#include "core/or/or.h"
+#include "feature/dircache/consdiffmgr.h"
+#include "feature/dircache/dircache.h"
+#include "feature/dircache/dirserv.h"
+#include "feature/dircommon/dir_connection_st.h"
+
+int
+directory_handle_command(dir_connection_t *conn)
+{
+ (void) conn;
+ tor_assert_nonfatal_unreached_once();
+ return -1;
+}
+
+int
+connection_dirserv_flushed_some(dir_connection_t *conn)
+{
+ (void) conn;
+ tor_assert_nonfatal_unreached_once();
+ return -1;
+}
+
+void
+dir_conn_clear_spool(dir_connection_t *conn)
+{
+ if (!conn)
+ return;
+ tor_assert_nonfatal_once(conn->spool == NULL);
+}
+
+void
+consdiffmgr_enable_background_compression(void)
+{
+}
+
+int
+consdiffmgr_add_consensus(const char *consensus,
+ size_t consensus_len,
+ const networkstatus_t *as_parsed)
+{
+ (void)consensus;
+ (void)consensus_len;
+ (void)as_parsed;
+ return 0;
+}
+
+int
+consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem_t **cfg)
+{
+ (void)cfg;
+ return 0;
+}
+
+int
+consdiffmgr_cleanup(void)
+{
+ return 0;
+}
+
+void
+consdiffmgr_free_all(void)
+{
+}
+
+void
+dirserv_free_all(void)
+{
+}
diff --git a/src/feature/dircache/dirserv.c b/src/feature/dircache/dirserv.c
index 79400bf15f..fb8db879a4 100644
--- a/src/feature/dircache/dirserv.c
+++ b/src/feature/dircache/dirserv.c
@@ -1,9 +1,8 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define DIRSERV_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
@@ -69,55 +68,7 @@ static cached_dir_t *lookup_cached_dir_by_fp(const uint8_t *fp);
/********************************************************************/
/* A set of functions to answer questions about how we'd like to behave
- * as a directory mirror/client. */
-
-/** Return 1 if we fetch our directory material directly from the
- * authorities, rather than from a mirror. */
-int
-directory_fetches_from_authorities(const or_options_t *options)
-{
- const routerinfo_t *me;
- uint32_t addr;
- int refuseunknown;
- if (options->FetchDirInfoEarly)
- return 1;
- if (options->BridgeRelay == 1)
- return 0;
- if (server_mode(options) &&
- router_pick_published_address(options, &addr, 1) < 0)
- return 1; /* we don't know our IP address; ask an authority. */
- refuseunknown = ! router_my_exit_policy_is_reject_star() &&
- should_refuse_unknown_exits(options);
- if (!dir_server_mode(options) && !refuseunknown)
- return 0;
- if (!server_mode(options) || !advertised_server_mode())
- return 0;
- me = router_get_my_routerinfo();
- if (!me || (!me->supports_tunnelled_dir_requests && !refuseunknown))
- return 0; /* if we don't service directory requests, return 0 too */
- return 1;
-}
-
-/** Return 1 if we should fetch new networkstatuses, descriptors, etc
- * on the "mirror" schedule rather than the "client" schedule.
- */
-int
-directory_fetches_dir_info_early(const or_options_t *options)
-{
- return directory_fetches_from_authorities(options);
-}
-
-/** Return 1 if we should fetch new networkstatuses, descriptors, etc
- * on a very passive schedule -- waiting long enough for ordinary clients
- * to probably have the info we want. These would include bridge users,
- * and maybe others in the future e.g. if a Tor client uses another Tor
- * client as a directory guard.
- */
-int
-directory_fetches_dir_info_later(const or_options_t *options)
-{
- return options->UseBridges != 0;
-}
+ * as a directory mirror */
/** Return true iff we want to serve certificates for authorities
* that we don't acknowledge as authorities ourself.
@@ -161,19 +112,6 @@ directory_permits_begindir_requests(const or_options_t *options)
return options->BridgeRelay != 0 || dir_server_mode(options);
}
-/** Return 1 if we have no need to fetch new descriptors. This generally
- * happens when we're not a dir cache and we haven't built any circuits
- * lately.
- */
-int
-directory_too_idle_to_fetch_descriptors(const or_options_t *options,
- time_t now)
-{
- return !directory_caches_dir_info(options) &&
- !options->FetchUselessDescriptors &&
- rep_hist_circbuilding_dormant(now);
-}
-
/********************************************************************/
/** Map from flavor name to the cached_dir_t for the v3 consensuses that we're
@@ -259,14 +197,45 @@ dirserv_set_cached_consensus_networkstatus(const char *networkstatus,
/** Return the latest downloaded consensus networkstatus in encoded, signed,
* optionally compressed format, suitable for sending to clients. */
-cached_dir_t *
-dirserv_get_consensus(const char *flavor_name)
+MOCK_IMPL(cached_dir_t *,
+dirserv_get_consensus,(const char *flavor_name))
{
if (!cached_consensuses)
return NULL;
return strmap_get(cached_consensuses, flavor_name);
}
+/** As dir_split_resource_into_fingerprints, but instead fills
+ * <b>spool_out</b> with a list of spoolable_resource_t for the resource
+ * identified through <b>source</b>. */
+int
+dir_split_resource_into_spoolable(const char *resource,
+ dir_spool_source_t source,
+ smartlist_t *spool_out,
+ int *compressed_out,
+ int flags)
+{
+ smartlist_t *fingerprints = smartlist_new();
+
+ tor_assert(flags & (DSR_HEX|DSR_BASE64));
+ const size_t digest_len =
+ (flags & DSR_DIGEST256) ? DIGEST256_LEN : DIGEST_LEN;
+
+ int r = dir_split_resource_into_fingerprints(resource, fingerprints,
+ compressed_out, flags);
+ /* This is not a very efficient implementation XXXX */
+ SMARTLIST_FOREACH_BEGIN(fingerprints, uint8_t *, digest) {
+ spooled_resource_t *spooled =
+ spooled_resource_new(source, digest, digest_len);
+ if (spooled)
+ smartlist_add(spool_out, spooled);
+ tor_free(digest);
+ } SMARTLIST_FOREACH_END(digest);
+
+ smartlist_free(fingerprints);
+ return r;
+}
+
/** As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t
* pointers, adds copies of digests to fps_out, and doesn't use the
* /tor/server/ prefix. For a /d/ request, adds descriptor digests; for other
@@ -333,87 +302,6 @@ dirserv_get_routerdesc_spool(smartlist_t *spool_out,
return 0;
}
-/** Add a signed_descriptor_t to <b>descs_out</b> for each router matching
- * <b>key</b>. The key should be either
- * - "/tor/server/authority" for our own routerinfo;
- * - "/tor/server/all" for all the routerinfos we have, concatenated;
- * - "/tor/server/fp/FP" where FP is a plus-separated sequence of
- * hex identity digests; or
- * - "/tor/server/d/D" where D is a plus-separated sequence
- * of server descriptor digests, in hex.
- *
- * Return 0 if we found some matching descriptors, or -1 if we do not
- * have any descriptors, no matching descriptors, or if we did not
- * recognize the key (URL).
- * If -1 is returned *<b>msg</b> will be set to an appropriate error
- * message.
- *
- * XXXX rename this function. It's only called from the controller.
- * XXXX in fact, refactor this function, merging as much as possible.
- */
-int
-dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
- const char **msg)
-{
- *msg = NULL;
-
- if (!strcmp(key, "/tor/server/all")) {
- routerlist_t *rl = router_get_routerlist();
- SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
- smartlist_add(descs_out, &(r->cache_info)));
- } else if (!strcmp(key, "/tor/server/authority")) {
- const routerinfo_t *ri = router_get_my_routerinfo();
- if (ri)
- smartlist_add(descs_out, (void*) &(ri->cache_info));
- } else if (!strcmpstart(key, "/tor/server/d/")) {
- smartlist_t *digests = smartlist_new();
- key += strlen("/tor/server/d/");
- dir_split_resource_into_fingerprints(key, digests, NULL,
- DSR_HEX|DSR_SORT_UNIQ);
- SMARTLIST_FOREACH(digests, const char *, d,
- {
- signed_descriptor_t *sd = router_get_by_descriptor_digest(d);
- if (sd)
- smartlist_add(descs_out,sd);
- });
- SMARTLIST_FOREACH(digests, char *, d, tor_free(d));
- smartlist_free(digests);
- } else if (!strcmpstart(key, "/tor/server/fp/")) {
- smartlist_t *digests = smartlist_new();
- time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH;
- key += strlen("/tor/server/fp/");
- dir_split_resource_into_fingerprints(key, digests, NULL,
- DSR_HEX|DSR_SORT_UNIQ);
- SMARTLIST_FOREACH_BEGIN(digests, const char *, d) {
- if (router_digest_is_me(d)) {
- /* calling router_get_my_routerinfo() to make sure it exists */
- const routerinfo_t *ri = router_get_my_routerinfo();
- if (ri)
- smartlist_add(descs_out, (void*) &(ri->cache_info));
- } else {
- const routerinfo_t *ri = router_get_by_id_digest(d);
- /* Don't actually serve a descriptor that everyone will think is
- * expired. This is an (ugly) workaround to keep buggy 0.1.1.10
- * Tors from downloading descriptors that they will throw away.
- */
- if (ri && ri->cache_info.published_on > cutoff)
- smartlist_add(descs_out, (void*) &(ri->cache_info));
- }
- } SMARTLIST_FOREACH_END(d);
- SMARTLIST_FOREACH(digests, char *, d, tor_free(d));
- smartlist_free(digests);
- } else {
- *msg = "Key not recognized";
- return -1;
- }
-
- if (!smartlist_len(descs_out)) {
- *msg = "Servers unavailable";
- return -1;
- }
- return 0;
-}
-
/* ==========
* Spooling code.
* ========== */
diff --git a/src/feature/dircache/dirserv.h b/src/feature/dircache/dirserv.h
index 7f944459da..73a64b1b7e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -73,29 +73,52 @@ typedef struct spooled_resource_t {
int connection_dirserv_flushed_some(dir_connection_t *conn);
-int directory_fetches_from_authorities(const or_options_t *options);
-int directory_fetches_dir_info_early(const or_options_t *options);
-int directory_fetches_dir_info_later(const or_options_t *options);
+enum dir_spool_source_t;
+int dir_split_resource_into_spoolable(const char *resource,
+ enum dir_spool_source_t source,
+ smartlist_t *spool_out,
+ int *compressed_out,
+ int flags);
+
+#ifdef HAVE_MODULE_DIRCACHE
+/** Is the dircache module enabled? */
+#define have_module_dircache() (1)
int directory_caches_unknown_auth_certs(const or_options_t *options);
int directory_caches_dir_info(const or_options_t *options);
int directory_permits_begindir_requests(const or_options_t *options);
-int directory_too_idle_to_fetch_descriptors(const or_options_t *options,
- time_t now);
-
-cached_dir_t *dirserv_get_consensus(const char *flavor_name);
+MOCK_DECL(cached_dir_t *, dirserv_get_consensus, (const char *flavor_name));
void dirserv_set_cached_consensus_networkstatus(const char *consensus,
size_t consensus_len,
const char *flavor_name,
const common_digests_t *digests,
const uint8_t *sha3_as_signed,
time_t published);
+#else /* !defined(HAVE_MODULE_DIRCACHE) */
+#define have_module_dircache() (0)
+#define directory_caches_unknown_auth_certs(opt) \
+ ((void)(opt), 0)
+#define directory_caches_dir_info(opt) \
+ ((void)(opt), 0)
+#define directory_permits_begindir_requests(opt) \
+ ((void)(opt), 0)
+#define dirserv_get_consensus(flav) \
+ ((void)(flav), NULL)
+#define dirserv_set_cached_consensus_networkstatus(a,b,c,d,e,f) \
+ STMT_BEGIN { \
+ (void)(a); \
+ (void)(b); \
+ (void)(c); \
+ (void)(d); \
+ (void)(e); \
+ (void)(f); \
+ } STMT_END
+#endif /* defined(HAVE_MODULE_DIRCACHE) */
+
void dirserv_clear_old_networkstatuses(time_t cutoff);
int dirserv_get_routerdesc_spool(smartlist_t *spools_out, const char *key,
dir_spool_source_t source,
int conn_is_encrypted,
const char **msg_out);
-int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
- const char **msg);
void dirserv_free_all(void);
void cached_dir_decref(cached_dir_t *d);
diff --git a/src/feature/dircache/feature_dircache.md b/src/feature/dircache/feature_dircache.md
new file mode 100644
index 0000000000..97734f2a34
--- /dev/null
+++ b/src/feature/dircache/feature_dircache.md
@@ -0,0 +1,6 @@
+@dir /feature/dircache
+@brief feature/dircache: Run as a directory cache server
+
+This module handles the directory caching functionality that all relays may
+provide, for serving cached directory objects to objects.
+
diff --git a/src/feature/dircache/include.am b/src/feature/dircache/include.am
new file mode 100644
index 0000000000..ab162565f7
--- /dev/null
+++ b/src/feature/dircache/include.am
@@ -0,0 +1,21 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+MODULE_DIRCACHE_SOURCES = \
+ src/feature/dircache/conscache.c \
+ src/feature/dircache/consdiffmgr.c \
+ src/feature/dircache/dircache.c \
+ src/feature/dircache/dirserv.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/dircache/cached_dir_st.h \
+ src/feature/dircache/conscache.h \
+ src/feature/dircache/consdiffmgr.h \
+ src/feature/dircache/dircache.h \
+ src/feature/dircache/dirserv.h
+
+if BUILD_MODULE_DIRCACHE
+LIBTOR_APP_A_SOURCES += $(MODULE_DIRCACHE_SOURCES)
+else
+LIBTOR_APP_A_STUB_SOURCES += src/feature/dircache/dircache_stub.c
+endif
diff --git a/src/feature/dirclient/.may_include b/src/feature/dirclient/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/dirclient/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/dirclient/dir_server_st.h b/src/feature/dirclient/dir_server_st.h
index 8e35532435..37fa3148a7 100644
--- a/src/feature/dirclient/dir_server_st.h
+++ b/src/feature/dirclient/dir_server_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dir_server_st.h
+ * @brief Trusted/fallback directory server structure.
+ **/
+
#ifndef DIR_SERVER_ST_H
#define DIR_SERVER_ST_H
diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c
index fa82bdc1e7..ae1e018df2 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -1,8 +1,13 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dirclient.c
+ * @brief Download directory information
+ **/
+
#define DIRCLIENT_PRIVATE
#include "core/or/or.h"
@@ -16,10 +21,12 @@
#include "feature/client/entrynodes.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
+#include "feature/dirclient/dirclient.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/shared_random.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/consdiff.h"
#include "feature/dircommon/directory.h"
@@ -37,6 +44,7 @@
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
#include "feature/rend/rendcache.h"
@@ -45,6 +53,7 @@
#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
+#include "lib/cc/ctassert.h"
#include "lib/compress/compress.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -448,7 +457,7 @@ directory_get_from_dirserver,(
{
const routerstatus_t *rs = NULL;
const or_options_t *options = get_options();
- int prefer_authority = (directory_fetches_from_authorities(options)
+ int prefer_authority = (dirclient_fetches_from_authorities(options)
|| want_authority == DL_WANT_AUTHORITY);
int require_authority = 0;
int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose,
@@ -667,7 +676,7 @@ directory_choose_address_routerstatus(const routerstatus_t *status,
if (indirection == DIRIND_DIRECT_CONN ||
indirection == DIRIND_ANON_DIRPORT ||
(indirection == DIRIND_ONEHOP
- && !directory_must_use_begindir(options))) {
+ && !dirclient_must_use_begindir(options))) {
fascist_firewall_choose_address_rs(status, FIREWALL_DIR_CONNECTION, 0,
use_dir_ap);
have_dir = tor_addr_port_is_valid_ap(use_dir_ap, 0);
@@ -866,16 +875,6 @@ connection_dir_download_cert_failed(dir_connection_t *conn, int status)
update_certificate_downloads(time(NULL));
}
-/* Should this tor instance only use begindir for all its directory requests?
- */
-int
-directory_must_use_begindir(const or_options_t *options)
-{
- /* Clients, onion services, and bridges must use begindir,
- * relays and authorities do not have to */
- return !public_server_mode(options);
-}
-
/** Evaluate the situation and decide if we should use an encrypted
* "begindir-style" connection for this directory request.
* 0) If there is no DirPort, yes.
@@ -927,7 +926,7 @@ directory_command_should_use_begindir(const or_options_t *options,
}
/* Reasons why we want to avoid using begindir */
if (indirection == DIRIND_ONEHOP) {
- if (!directory_must_use_begindir(options)) {
+ if (!dirclient_must_use_begindir(options)) {
*reason = "in relay mode";
return 0;
}
@@ -1289,7 +1288,7 @@ directory_initiate_request,(directory_request_t *request))
/* use encrypted begindir connections for everything except relays
* this provides better protection for directory fetches */
- if (!use_begindir && directory_must_use_begindir(options)) {
+ if (!use_begindir && dirclient_must_use_begindir(options)) {
log_warn(LD_BUG, "Client could not use begindir connection: %s",
begindir_reason ? begindir_reason : "(NULL)");
return;
@@ -1447,9 +1446,7 @@ compare_strs_(const void **a, const void **b)
}
#define CONDITIONAL_CONSENSUS_FPR_LEN 3
-#if (CONDITIONAL_CONSENSUS_FPR_LEN > DIGEST_LEN)
-#error "conditional consensus fingerprint length is larger than digest length"
-#endif
+CTASSERT(CONDITIONAL_CONSENSUS_FPR_LEN <= DIGEST_LEN);
/** Return the URL we should use for a consensus download.
*
@@ -1968,6 +1965,44 @@ dir_client_decompress_response_body(char **bodyp, size_t *bodylenp,
return rv;
}
+/**
+ * Total number of bytes downloaded of each directory purpose, when
+ * bootstrapped, and when not bootstrapped.
+ *
+ * (For example, the number of bytes downloaded of purpose p while
+ * not fully bootstrapped is total_dl[p][false].)
+ **/
+static uint64_t total_dl[DIR_PURPOSE_MAX_][2];
+
+/**
+ * Heartbeat: dump a summary of how many bytes of which purpose we've
+ * downloaded, when bootstrapping and when not bootstrapping.
+ **/
+void
+dirclient_dump_total_dls(void)
+{
+ const or_options_t *options = get_options();
+ for (int bootstrapped = 0; bootstrapped < 2; ++bootstrapped) {
+ bool first_time = true;
+ for (int i=0; i < DIR_PURPOSE_MAX_; ++i) {
+ uint64_t n = total_dl[i][bootstrapped];
+ if (n == 0)
+ continue;
+ if (options->SafeLogging_ != SAFELOG_SCRUB_NONE &&
+ purpose_needs_anonymity(i, ROUTER_PURPOSE_GENERAL, NULL))
+ continue;
+ if (first_time) {
+ log_notice(LD_NET,
+ "While %sbootstrapping, fetched this many bytes: ",
+ bootstrapped?"not ":"");
+ first_time = false;
+ }
+ log_notice(LD_NET, " %"PRIu64" (%s)",
+ n, dir_conn_purpose_to_string(i));
+ }
+ }
+}
+
/** We are a client, and we've finished reading the server's
* response. Parse it and act appropriately.
*
@@ -2001,6 +2036,16 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
received_bytes = connection_get_inbuf_len(TO_CONN(conn));
+ log_debug(LD_DIR, "Downloaded %"TOR_PRIuSZ" bytes on connection of purpose "
+ "%s; bootstrap %d%%",
+ received_bytes,
+ dir_conn_purpose_to_string(conn->base_.purpose),
+ control_get_bootstrap_percent());
+ {
+ bool bootstrapped = control_get_bootstrap_percent() == 100;
+ total_dl[conn->base_.purpose][bootstrapped] += received_bytes;
+ }
+
switch (connection_fetch_from_buf_http(TO_CONN(conn),
&headers, MAX_HEADERS_SIZE,
&body, &body_len, MAX_DIR_DL_SIZE,
@@ -2368,7 +2413,7 @@ handle_response_fetch_status_vote(dir_connection_t *conn,
conn->base_.port, conn->requested_resource);
return -1;
}
- dirvote_add_vote(body, &msg, &st);
+ dirvote_add_vote(body, 0, &msg, &st);
if (st > 299) {
log_warn(LD_DIR, "Error adding retrieved vote: %s", msg);
} else {
@@ -2728,62 +2773,7 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
log_info(LD_REND,"Received v3 hsdesc (body size %d, status %d (%s))",
(int)body_len, status_code, escaped(reason));
- switch (status_code) {
- case 200:
- /* We got something: Try storing it in the cache. */
- if (hs_cache_store_as_client(body, &conn->hs_ident->identity_pk) < 0) {
- log_info(LD_REND, "Failed to store hidden service descriptor");
- /* Fire control port FAILED event. */
- hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
- "BAD_DESC");
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- NULL);
- } else {
- log_info(LD_REND, "Stored hidden service descriptor successfully.");
- TO_CONN(conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC;
- hs_client_desc_has_arrived(conn->hs_ident);
- /* Fire control port RECEIVED event. */
- hs_control_desc_event_received(conn->hs_ident, conn->identity_digest);
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- body);
- }
- break;
- case 404:
- /* Not there. We'll retry when connection_about_to_close_connection()
- * tries to clean this conn up. */
- log_info(LD_REND, "Fetching hidden service v3 descriptor not found: "
- "Retrying at another directory.");
- /* Fire control port FAILED event. */
- hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
- "NOT_FOUND");
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- NULL);
- break;
- case 400:
- log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
- "http status 400 (%s). Dirserver didn't like our "
- "query? Retrying at another directory.",
- escaped(reason));
- /* Fire control port FAILED event. */
- hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
- "QUERY_REJECTED");
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- NULL);
- break;
- default:
- log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
- "http status %d (%s) response unexpected from HSDir server "
- "'%s:%d'. Retrying at another directory.",
- status_code, escaped(reason), TO_CONN(conn)->address,
- TO_CONN(conn)->port);
- /* Fire control port FAILED event. */
- hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
- "UNEXPECTED");
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- NULL);
- break;
- }
-
+ hs_client_dir_fetch_done(conn, reason, body, status_code);
return 0;
}
@@ -3143,7 +3133,7 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
{
char digest[DIGEST_LEN];
time_t now = time(NULL);
- int server = directory_fetches_from_authorities(get_options());
+ int server = dirclient_fetches_from_authorities(get_options());
if (!was_descriptor_digests) {
if (router_purpose == ROUTER_PURPOSE_BRIDGE) {
tor_assert(!was_extrainfo);
@@ -3188,7 +3178,7 @@ dir_microdesc_download_failed(smartlist_t *failed,
routerstatus_t *rs;
download_status_t *dls;
time_t now = time(NULL);
- int server = directory_fetches_from_authorities(get_options());
+ int server = dirclient_fetches_from_authorities(get_options());
if (! consensus)
return;
diff --git a/src/feature/dirclient/dirclient.h b/src/feature/dirclient/dirclient.h
index be4374c7cf..096b197526 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,8 @@
#include "feature/hs/hs_ident.h"
+void dirclient_dump_total_dls(void);
+
int directories_have_accepted_server_descriptor(void);
void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
dirinfo_type_t type, const char *payload,
@@ -41,8 +43,6 @@ typedef enum {
DIRIND_ANON_DIRPORT,
} dir_indirection_t;
-int directory_must_use_begindir(const or_options_t *options);
-
/**
* A directory_request_t describes the information about a directory request
* at the client side. It describes what we're going to ask for, which
diff --git a/src/feature/dirclient/dirclient_modes.c b/src/feature/dirclient/dirclient_modes.c
new file mode 100644
index 0000000000..31a3f8af58
--- /dev/null
+++ b/src/feature/dirclient/dirclient_modes.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2001 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 dirclient_modes.c
+ * @brief Functions to answer questions about how we'd like to behave
+ * as a directory client
+ **/
+
+#include "orconfig.h"
+
+#include "core/or/or.h"
+
+#include "feature/dirclient/dirclient_modes.h"
+#include "feature/dircache/dirserv.h"
+#include "feature/relay/relay_find_addr.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+#include "feature/stats/predict_ports.h"
+
+#include "app/config/or_options_st.h"
+#include "feature/nodelist/routerinfo_st.h"
+
+/* Should this tor instance only use begindir for all its directory requests?
+ */
+int
+dirclient_must_use_begindir(const or_options_t *options)
+{
+ /* Clients, onion services, and bridges must use begindir,
+ * relays and authorities do not have to */
+ return !public_server_mode(options);
+}
+
+/** Return 1 if we fetch our directory material directly from the
+ * authorities, rather than from a mirror. */
+int
+dirclient_fetches_from_authorities(const or_options_t *options)
+{
+ const routerinfo_t *me;
+ uint32_t addr;
+ int refuseunknown;
+ if (options->FetchDirInfoEarly)
+ return 1;
+ if (options->BridgeRelay == 1)
+ return 0;
+ if (server_mode(options) &&
+ router_pick_published_address(options, &addr, 1) < 0)
+ return 1; /* we don't know our IP address; ask an authority. */
+ refuseunknown = ! router_my_exit_policy_is_reject_star() &&
+ should_refuse_unknown_exits(options);
+ if (!dir_server_mode(options) && !refuseunknown)
+ return 0;
+ if (!server_mode(options) || !advertised_server_mode())
+ return 0;
+ me = router_get_my_routerinfo();
+ if (!me || (!me->supports_tunnelled_dir_requests && !refuseunknown))
+ return 0; /* if we don't service directory requests, return 0 too */
+ return 1;
+}
+
+/** Return 1 if we should fetch new networkstatuses, descriptors, etc
+ * on the "mirror" schedule rather than the "client" schedule.
+ */
+int
+dirclient_fetches_dir_info_early(const or_options_t *options)
+{
+ return dirclient_fetches_from_authorities(options);
+}
+
+/** Return 1 if we should fetch new networkstatuses, descriptors, etc
+ * on a very passive schedule -- waiting long enough for ordinary clients
+ * to probably have the info we want. These would include bridge users,
+ * and maybe others in the future e.g. if a Tor client uses another Tor
+ * client as a directory guard.
+ */
+int
+dirclient_fetches_dir_info_later(const or_options_t *options)
+{
+ return options->UseBridges != 0;
+}
+
+/** Return 1 if we have no need to fetch new descriptors. This generally
+ * happens when we're not a dir cache and we haven't built any circuits
+ * lately.
+ */
+int
+dirclient_too_idle_to_fetch_descriptors(const or_options_t *options,
+ time_t now)
+{
+ return !directory_caches_dir_info(options) &&
+ !options->FetchUselessDescriptors &&
+ rep_hist_circbuilding_dormant(now);
+}
diff --git a/src/feature/dirclient/dirclient_modes.h b/src/feature/dirclient/dirclient_modes.h
new file mode 100644
index 0000000000..c402207724
--- /dev/null
+++ b/src/feature/dirclient/dirclient_modes.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dirclient_modes.h
+ * @brief Header for feature/dirclient/dirclient_modes.c
+ **/
+
+#ifndef TOR_FEATURE_DIRCLIENT_DIRCLIENT_MODES_H
+#define TOR_FEATURE_DIRCLIENT_DIRCLIENT_MODES_H
+
+struct or_options_t;
+
+int dirclient_must_use_begindir(const or_options_t *options);
+int dirclient_fetches_from_authorities(const struct or_options_t *options);
+int dirclient_fetches_dir_info_early(const struct or_options_t *options);
+int dirclient_fetches_dir_info_later(const struct or_options_t *options);
+int dirclient_too_idle_to_fetch_descriptors(const struct or_options_t *options,
+ time_t now);
+
+#endif /* !defined(TOR_FEATURE_DIRCLIENT_DIRCLIENT_MODES_H) */
diff --git a/src/feature/dirclient/dlstatus.c b/src/feature/dirclient/dlstatus.c
index 0842a2c676..ab3fbb8577 100644
--- a/src/feature/dirclient/dlstatus.c
+++ b/src/feature/dirclient/dlstatus.c
@@ -1,8 +1,13 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dlstatus.c
+ * @brief Track status and retry schedule of a downloadable object.
+ **/
+
#define DLSTATUS_PRIVATE
#include "core/or/or.h"
diff --git a/src/feature/dirclient/dlstatus.h b/src/feature/dirclient/dlstatus.h
index 681712b059..e5c8b756c4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 39a5ad2860..92efcb44d0 100644
--- a/src/feature/dirclient/download_status_st.h
+++ b/src/feature/dirclient/download_status_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file download_status_st.h
+ * @brief Directory download status/schedule structure.
+ **/
+
#ifndef DOWNLOAD_STATUS_ST_H
#define DOWNLOAD_STATUS_ST_H
@@ -62,4 +67,3 @@ struct download_status_t {
};
#endif /* !defined(DOWNLOAD_STATUS_ST_H) */
-
diff --git a/src/feature/dirclient/feature_dirclient.md b/src/feature/dirclient/feature_dirclient.md
new file mode 100644
index 0000000000..5c7ee964d3
--- /dev/null
+++ b/src/feature/dirclient/feature_dirclient.md
@@ -0,0 +1,7 @@
+@dir /feature/dirclient
+@brief feature/dirclient: Directory client implementation.
+
+The code here is used by all Tor instances that need to download directory
+information. Currently, that is all of them, since even authorities need to
+launch downloads to learn about relays that other authorities have listed.
+
diff --git a/src/feature/dirclient/include.am b/src/feature/dirclient/include.am
new file mode 100644
index 0000000000..24cae9eedd
--- /dev/null
+++ b/src/feature/dirclient/include.am
@@ -0,0 +1,14 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/dirclient/dirclient.c \
+ src/feature/dirclient/dirclient_modes.c \
+ src/feature/dirclient/dlstatus.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/dirclient/dir_server_st.h \
+ src/feature/dirclient/dirclient.h \
+ src/feature/dirclient/dirclient_modes.h \
+ src/feature/dirclient/dlstatus.h \
+ src/feature/dirclient/download_status_st.h
diff --git a/src/feature/dircommon/.may_include b/src/feature/dircommon/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/dircommon/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/dircommon/consdiff.c b/src/feature/dircommon/consdiff.c
index 8e93953f73..e42378c44c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -530,10 +530,12 @@ typedef struct router_id_iterator_t {
cdline_t hash;
} router_id_iterator_t;
+#ifndef COCCI
/**
* Initializer for a router_id_iterator_t.
*/
#define ROUTER_ID_ITERATOR_INIT { { NULL, 0 }, { NULL, 0 } }
+#endif /* !defined(COCCI) */
/** Given an index *<b>idxp</b> into the consensus at <b>cons</b>, advance
* the index to the next router line ("r ...") in the consensus, or to
@@ -570,7 +572,7 @@ find_next_router_line(const smartlist_t *cons,
/** Pre-process a consensus in <b>cons</b> (represented as a list of cdline_t)
* to remove the signatures from it. If the footer is removed, return a
* cdline_t containing a delete command to delete the footer, allocated in
- * <b>area</>. If no footer is removed, return NULL.
+ * <b>area</b>. If no footer is removed, return NULL.
*
* We remove the signatures here because they are not themselves signed, and
* as such there might be different encodings for them.
@@ -1048,7 +1050,7 @@ consdiff_gen_diff(const smartlist_t *cons1,
if (smartlist_len(cons2) == smartlist_len(ed_cons2)) {
SMARTLIST_FOREACH_BEGIN(cons2, const cdline_t *, line1) {
const cdline_t *line2 = smartlist_get(ed_cons2, line1_sl_idx);
- if (! lines_eq(line1, line2) ) {
+ if (!lines_eq(line1, line2)) {
cons2_eq = 0;
break;
}
diff --git a/src/feature/dircommon/consdiff.h b/src/feature/dircommon/consdiff.h
index b63fcb2cc6..c2dcb6da24 100644
--- a/src/feature/dircommon/consdiff.h
+++ b/src/feature/dircommon/consdiff.h
@@ -1,7 +1,12 @@
/* Copyright (c) 2014, Daniel Martí
- * Copyright (c) 2014-2019, The Tor Project, Inc. */
+ * Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file consdiff.h
+ * @brief Header for consdiff.c
+ **/
+
#ifndef TOR_CONSDIFF_H
#define TOR_CONSDIFF_H
diff --git a/src/feature/dircommon/dir_connection_st.h b/src/feature/dircommon/dir_connection_st.h
index a858560c29..12230e6741 100644
--- a/src/feature/dircommon/dir_connection_st.h
+++ b/src/feature/dircommon/dir_connection_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dir_connection_st.h
+ * @brief Client/server directory connection structure.
+ **/
+
#ifndef DIR_CONNECTION_ST_H
#define DIR_CONNECTION_ST_H
@@ -23,7 +28,9 @@ struct dir_connection_t {
* fingerprints.
**/
char *requested_resource;
- unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */
+ /** Is this dirconn direct, or via a multi-hop Tor circuit?
+ * Direct connections can use the DirPort, or BEGINDIR over the ORPort. */
+ unsigned int dirconn_direct:1;
/** If we're fetching descriptors, what router purpose shall we assign
* to them? */
diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c
index 8e5b413326..b177fe5201 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -702,34 +702,3 @@ dir_split_resource_into_fingerprints(const char *resource,
smartlist_free(fp_tmp);
return 0;
}
-
-/** As dir_split_resource_into_fingerprints, but instead fills
- * <b>spool_out</b> with a list of spoolable_resource_t for the resource
- * identified through <b>source</b>. */
-int
-dir_split_resource_into_spoolable(const char *resource,
- dir_spool_source_t source,
- smartlist_t *spool_out,
- int *compressed_out,
- int flags)
-{
- smartlist_t *fingerprints = smartlist_new();
-
- tor_assert(flags & (DSR_HEX|DSR_BASE64));
- const size_t digest_len =
- (flags & DSR_DIGEST256) ? DIGEST256_LEN : DIGEST_LEN;
-
- int r = dir_split_resource_into_fingerprints(resource, fingerprints,
- compressed_out, flags);
- /* This is not a very efficient implementation XXXX */
- SMARTLIST_FOREACH_BEGIN(fingerprints, uint8_t *, digest) {
- spooled_resource_t *spooled =
- spooled_resource_new(source, digest, digest_len);
- if (spooled)
- smartlist_add(spool_out, spooled);
- tor_free(digest);
- } SMARTLIST_FOREACH_END(digest);
-
- smartlist_free(fingerprints);
- return r;
-}
diff --git a/src/feature/dircommon/directory.h b/src/feature/dircommon/directory.h
index 4fc743ad3d..0f26cdeff9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -108,12 +108,6 @@ void connection_dir_about_to_close(dir_connection_t *dir_conn);
int dir_split_resource_into_fingerprints(const char *resource,
smartlist_t *fp_out, int *compressed_out,
int flags);
-enum dir_spool_source_t;
-int dir_split_resource_into_spoolable(const char *resource,
- enum dir_spool_source_t source,
- smartlist_t *spool_out,
- int *compressed_out,
- int flags);
int dir_split_resource_into_fingerprint_pairs(const char *res,
smartlist_t *pairs_out);
char *directory_dump_request_log(void);
diff --git a/src/feature/dircommon/feature_dircommon.md b/src/feature/dircommon/feature_dircommon.md
new file mode 100644
index 0000000000..359049ecd8
--- /dev/null
+++ b/src/feature/dircommon/feature_dircommon.md
@@ -0,0 +1,7 @@
+@dir /feature/dircommon
+@brief feature/dircommon: Directory client and server shared code
+
+This module has the code that directory clients (anybody who download
+information about relays) and directory servers (anybody who serves such
+information) share in common.
+
diff --git a/src/feature/dircommon/fp_pair.c b/src/feature/dircommon/fp_pair.c
index 284600df77..87e1c253bd 100644
--- a/src/feature/dircommon/fp_pair.c
+++ b/src/feature/dircommon/fp_pair.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,14 +22,14 @@
/* Define fp_pair_map_t structures */
-struct fp_pair_map_entry_s {
- HT_ENTRY(fp_pair_map_entry_s) node;
+struct fp_pair_map_entry_t {
+ HT_ENTRY(fp_pair_map_entry_t) node;
void *val;
fp_pair_t key;
};
-struct fp_pair_map_s {
- HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_s) head;
+struct fp_pair_map_t {
+ HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_t) head;
};
/*
@@ -56,11 +56,11 @@ fp_pair_map_entry_hash(const fp_pair_map_entry_t *a)
* Hash table functions for fp_pair_map_t
*/
-HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node,
- fp_pair_map_entry_hash, fp_pair_map_entries_eq)
-HT_GENERATE2(fp_pair_map_impl, fp_pair_map_entry_s, node,
+HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_t, node,
+ fp_pair_map_entry_hash, fp_pair_map_entries_eq);
+HT_GENERATE2(fp_pair_map_impl, fp_pair_map_entry_t, node,
fp_pair_map_entry_hash, fp_pair_map_entries_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
/** Constructor to create a new empty map from fp_pair_t to void *
*/
@@ -312,4 +312,3 @@ fp_pair_map_assert_ok(const fp_pair_map_t *map)
{
tor_assert(!fp_pair_map_impl_HT_REP_IS_BAD_(&(map->head)));
}
-
diff --git a/src/feature/dircommon/fp_pair.h b/src/feature/dircommon/fp_pair.h
index 5041583e88..ae71ea7b71 100644
--- a/src/feature/dircommon/fp_pair.h
+++ b/src/feature/dircommon/fp_pair.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,8 +19,8 @@ typedef struct {
* Declare fp_pair_map_t functions and structs
*/
-typedef struct fp_pair_map_entry_s fp_pair_map_entry_t;
-typedef struct fp_pair_map_s fp_pair_map_t;
+typedef struct fp_pair_map_entry_t fp_pair_map_entry_t;
+typedef struct fp_pair_map_t fp_pair_map_t;
typedef fp_pair_map_entry_t *fp_pair_map_iter_t;
fp_pair_map_t * fp_pair_map_new(void);
diff --git a/src/feature/dircommon/include.am b/src/feature/dircommon/include.am
new file mode 100644
index 0000000000..87850ce183
--- /dev/null
+++ b/src/feature/dircommon/include.am
@@ -0,0 +1,14 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/dircommon/consdiff.c \
+ src/feature/dircommon/directory.c \
+ src/feature/dircommon/fp_pair.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/dircommon/consdiff.h \
+ src/feature/dircommon/dir_connection_st.h \
+ src/feature/dircommon/directory.h \
+ src/feature/dircommon/fp_pair.h \
+ src/feature/dircommon/vote_timing_st.h
diff --git a/src/feature/dircommon/vote_timing_st.h b/src/feature/dircommon/vote_timing_st.h
index 814a325314..103d950f86 100644
--- a/src/feature/dircommon/vote_timing_st.h
+++ b/src/feature/dircommon/vote_timing_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file vote_timing_st.h
+ * @brief Directory voting schedule structure.
+ **/
+
#ifndef VOTE_TIMING_ST_H
#define VOTE_TIMING_ST_H
@@ -21,4 +26,3 @@ struct vote_timing_t {
};
#endif /* !defined(VOTE_TIMING_ST_H) */
-
diff --git a/src/feature/dirparse/.may_include b/src/feature/dirparse/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/dirparse/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/dirparse/authcert_members.h b/src/feature/dirparse/authcert_members.h
new file mode 100644
index 0000000000..53eab175d6
--- /dev/null
+++ b/src/feature/dirparse/authcert_members.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2001 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 authcert_members.h
+ *
+ * @brief List of tokens common to V3 authority certificates and V3
+ * consensuses.
+ **/
+
+#ifndef TOR_AUTHCERT_MEMBERS_H
+#define TOR_AUTHCERT_MEMBERS_H
+
+// clang-format off
+#define AUTHCERT_MEMBERS \
+ T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
+ GE(1), NO_OBJ ), \
+ T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),\
+ T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ),\
+ T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ),\
+ T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\
+ T1("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),\
+ T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,\
+ NO_ARGS, NEED_OBJ),\
+ T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ)
+// clang-format on
+
+#endif /* !defined(TOR_AUTHCERT_MEMBERS_H) */
diff --git a/src/feature/dirparse/authcert_members.i b/src/feature/dirparse/authcert_members.i
deleted file mode 100644
index 08cffca97a..0000000000
--- a/src/feature/dirparse/authcert_members.i
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * List of tokens common to V3 authority certificates and V3 consensuses.
- */
- T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION,
- GE(1), NO_OBJ ),
- T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),
- T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ),
- T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ),
- T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),
- T1("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),
- T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,
- NO_ARGS, NEED_OBJ),
- T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
diff --git a/src/feature/dirparse/authcert_parse.c b/src/feature/dirparse/authcert_parse.c
index 8ba5a53981..deb45c12de 100644
--- a/src/feature/dirparse/authcert_parse.c
+++ b/src/feature/dirparse/authcert_parse.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file authcert_parse.c
+ * @brief Authority certificate parsing.
+ **/
+
#include "core/or/or.h"
#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/parsecommon.h"
@@ -13,13 +18,16 @@
#include "lib/memarea/memarea.h"
#include "feature/nodelist/authority_cert_st.h"
+#include "feature/dirparse/authcert_members.h"
/** List of tokens recognized in V3 authority certificates. */
+// clang-format off
static token_rule_t dir_key_certificate_table[] = {
-#include "feature/dirparse/authcert_members.i"
+ AUTHCERT_MEMBERS,
T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
+// clang-format on
/** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
* the first character after the certificate. */
diff --git a/src/feature/dirparse/authcert_parse.h b/src/feature/dirparse/authcert_parse.h
index 800631c3de..7f6dd1c02f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/feature_dirparse.md b/src/feature/dirparse/feature_dirparse.md
new file mode 100644
index 0000000000..e4b34668ba
--- /dev/null
+++ b/src/feature/dirparse/feature_dirparse.md
@@ -0,0 +1,8 @@
+@dir /feature/dirparse
+@brief feature/dirparse: Parsing Tor directory objects
+
+We define a number of "directory objects" in
+[dir-spec.txt](https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt),
+all of them using a common line-oriented meta-format. This module is used by
+other parts of Tor to parse them.
+
diff --git a/src/feature/dirparse/include.am b/src/feature/dirparse/include.am
new file mode 100644
index 0000000000..edca04f6f7
--- /dev/null
+++ b/src/feature/dirparse/include.am
@@ -0,0 +1,25 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/dirparse/authcert_parse.c \
+ src/feature/dirparse/microdesc_parse.c \
+ src/feature/dirparse/ns_parse.c \
+ src/feature/dirparse/parsecommon.c \
+ src/feature/dirparse/policy_parse.c \
+ src/feature/dirparse/routerparse.c \
+ src/feature/dirparse/sigcommon.c \
+ src/feature/dirparse/signing.c \
+ src/feature/dirparse/unparseable.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/dirparse/authcert_members.h \
+ src/feature/dirparse/authcert_parse.h \
+ src/feature/dirparse/microdesc_parse.h \
+ src/feature/dirparse/ns_parse.h \
+ src/feature/dirparse/parsecommon.h \
+ src/feature/dirparse/policy_parse.h \
+ src/feature/dirparse/routerparse.h \
+ src/feature/dirparse/sigcommon.h \
+ src/feature/dirparse/signing.h \
+ src/feature/dirparse/unparseable.h
diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c
index 4bb4db7821..9231080aaa 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,6 +28,7 @@
#include "feature/nodelist/microdesc_st.h"
/** List of tokens recognized in microdescriptors */
+// clang-format off
static token_rule_t microdesc_token_table[] = {
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
@@ -39,6 +40,7 @@ static token_rule_t microdesc_token_table[] = {
A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
+// clang-format on
/** Assuming that s starts with a microdesc, return the start of the
* *NEXT* one. Return NULL on "not found." */
@@ -164,7 +166,7 @@ microdesc_extract_body(microdesc_t *md,
/**
* Parse a microdescriptor which begins at <b>s</b> and ends at
- * <b>start_of_next_microdesc. Store its fields into <b>md</b>. Use
+ * <b>start_of_next_microdesc</b>. Store its fields into <b>md</b>. Use
* <b>where</b> for generating log information. If <b>allow_annotations</b>
* is true, then one or more annotations may precede the microdescriptor body
* proper. Use <b>area</b> for memory management, clearing it when done.
diff --git a/src/feature/dirparse/microdesc_parse.h b/src/feature/dirparse/microdesc_parse.h
index 95af85544a..e81126b8cd 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 d5405e6464..ac9325a608 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -36,12 +36,14 @@
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/networkstatus_voter_info_st.h"
#include "feature/nodelist/vote_routerstatus_st.h"
+#include "feature/dirparse/authcert_members.h"
#undef log
#include <math.h>
/** List of tokens recognized in the body part of v3 networkstatus
* documents. */
+// clang-format off
static token_rule_t rtrstatus_token_table[] = {
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
T1( "r", K_R, GE(7), NO_OBJ ),
@@ -55,8 +57,10 @@ static token_rule_t rtrstatus_token_table[] = {
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
END_OF_TABLE
};
+// clang-format on
/** List of tokens recognized in V3 networkstatus votes. */
+// clang-format off
static token_rule_t networkstatus_token_table[] = {
T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
GE(1), NO_OBJ ),
@@ -84,7 +88,7 @@ static token_rule_t networkstatus_token_table[] = {
T01("required-relay-protocols", K_REQUIRED_RELAY_PROTOCOLS,
CONCAT_ARGS, NO_OBJ ),
-#include "feature/dirparse/authcert_members.i"
+ AUTHCERT_MEMBERS,
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
@@ -97,8 +101,10 @@ static token_rule_t networkstatus_token_table[] = {
END_OF_TABLE
};
+// clang-format on
/** List of tokens recognized in V3 networkstatus consensuses. */
+// clang-format off
static token_rule_t networkstatus_consensus_token_table[] = {
T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
GE(1), NO_OBJ ),
@@ -135,14 +141,17 @@ static token_rule_t networkstatus_consensus_token_table[] = {
END_OF_TABLE
};
+// clang-format on
/** List of tokens recognized in the footer of v1 directory footers. */
+// clang-format off
static token_rule_t networkstatus_vote_footer_token_table[] = {
T01("directory-footer", K_DIRECTORY_FOOTER, NO_ARGS, NO_OBJ ),
T01("bandwidth-weights", K_BW_WEIGHTS, ARGS, NO_OBJ ),
T( "directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
END_OF_TABLE
};
+// clang-format on
/** Try to find the start and end of the signed portion of a networkstatus
* document in <b>s</b>. On success, set <b>start_out</b> to the first
diff --git a/src/feature/dirparse/ns_parse.h b/src/feature/dirparse/ns_parse.h
index 0cf2cc88d0..6a1ea85c92 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/parsecommon.c b/src/feature/dirparse/parsecommon.c
index c22ed186b8..ab465c4d7f 100644
--- a/src/feature/dirparse/parsecommon.c
+++ b/src/feature/dirparse/parsecommon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/parsecommon.h b/src/feature/dirparse/parsecommon.h
index ef74925b26..4db9a89f13 100644
--- a/src/feature/dirparse/parsecommon.h
+++ b/src/feature/dirparse/parsecommon.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/policy_parse.c b/src/feature/dirparse/policy_parse.c
index 7562ae409b..28cd174686 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,7 +9,7 @@
* \brief Code to parse address policies.
**/
-#define EXPOSE_ROUTERDESC_TOKEN_TABLE
+#define ROUTERDESC_TOKEN_TABLE_PRIVATE
#include "core/or/or.h"
diff --git a/src/feature/dirparse/policy_parse.h b/src/feature/dirparse/policy_parse.h
index e09ee5559f..7764069e66 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c
index f78c46f186..8828a0f97a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -50,7 +50,7 @@
* </ul>
**/
-#define EXPOSE_ROUTERDESC_TOKEN_TABLE
+#define ROUTERDESC_TOKEN_TABLE_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
@@ -81,6 +81,7 @@
/****************************************************************************/
/** List of tokens recognized in router descriptors */
+// clang-format off
const token_rule_t routerdesc_token_table[] = {
T0N("reject", K_REJECT, ARGS, NO_OBJ ),
T0N("accept", K_ACCEPT, ARGS, NO_OBJ ),
@@ -123,8 +124,10 @@ const token_rule_t routerdesc_token_table[] = {
END_OF_TABLE
};
+// clang-format on
/** List of tokens recognized in extra-info documents. */
+// clang-format off
static token_rule_t extrainfo_token_table[] = {
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
@@ -162,6 +165,7 @@ static token_rule_t extrainfo_token_table[] = {
END_OF_TABLE
};
+// clang-format on
#undef T
diff --git a/src/feature/dirparse/routerparse.h b/src/feature/dirparse/routerparse.h
index f9a13f2168..519044e9b0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -40,7 +40,8 @@ int find_single_ipv6_orport(const smartlist_t *list,
void routerparse_init(void);
void routerparse_free_all(void);
-#ifdef EXPOSE_ROUTERDESC_TOKEN_TABLE
+#ifdef ROUTERDESC_TOKEN_TABLE_PRIVATE
+#include "feature/dirparse/parsecommon.h"
extern const struct token_rule_t routerdesc_token_table[];
#endif
diff --git a/src/feature/dirparse/sigcommon.c b/src/feature/dirparse/sigcommon.c
index 2019e09918..8b970d7d1f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/sigcommon.h b/src/feature/dirparse/sigcommon.h
index b6b34e8f62..c2ed9df494 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/signing.c b/src/feature/dirparse/signing.c
index 3ab40c3807..e420e5b6b9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/signing.h b/src/feature/dirparse/signing.h
index 8b119b4eb2..7ca34bb14a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/unparseable.c b/src/feature/dirparse/unparseable.c
index 941b5a1f6d..98b68f90bb 100644
--- a/src/feature/dirparse/unparseable.c
+++ b/src/feature/dirparse/unparseable.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file unparseable.c
+ * @brief Dump unparseable objects to disk.
+ **/
+
#define UNPARSEABLE_PRIVATE
#include "core/or/or.h"
diff --git a/src/feature/dirparse/unparseable.h b/src/feature/dirparse/unparseable.h
index 36c6b5a1ec..cff91c82cc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/feature.md b/src/feature/feature.md
new file mode 100644
index 0000000000..acc3487e55
--- /dev/null
+++ b/src/feature/feature.md
@@ -0,0 +1,7 @@
+@dir /feature
+@brief feature: domain-specific modules
+
+The "feature" directory has modules that Tor uses only for a particular
+role or service, such as maintaining/using an onion service, operating as a
+relay or a client, or being a directory authority.
+
diff --git a/src/feature/hibernate/.may_include b/src/feature/hibernate/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/hibernate/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/hibernate/feature_hibernate.md b/src/feature/hibernate/feature_hibernate.md
new file mode 100644
index 0000000000..0eb5ffea0d
--- /dev/null
+++ b/src/feature/hibernate/feature_hibernate.md
@@ -0,0 +1,14 @@
+@dir /feature/hibernate
+@brief feature/hibernate: Bandwidth accounting and hibernation (!)
+
+This module implements two features that are only somewhat related, and
+should probably be separated in the future. One feature is bandwidth
+accounting (making sure we use no more than so many gigabytes in a day) and
+hibernation (avoiding network activity while we have used up all/most of our
+configured gigabytes). The other feature is clean shutdown, where we stop
+accepting new connections for a while and give the old ones time to close.
+
+The two features are related only in the sense that "soft hibernation" (being
+almost out of ) is very close to the "shutting down" state. But it would be
+better in the long run to make the two completely separate.
+
diff --git a/src/feature/hibernate/hibernate.c b/src/feature/hibernate/hibernate.c
index f7847d9a16..82c33659aa 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hibernate/hibernate.h b/src/feature/hibernate/hibernate.h
index 2e245f6ab1..2383658b20 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hibernate/include.am b/src/feature/hibernate/include.am
new file mode 100644
index 0000000000..355e591392
--- /dev/null
+++ b/src/feature/hibernate/include.am
@@ -0,0 +1,8 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/hibernate/hibernate.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/hibernate/hibernate.h
diff --git a/src/feature/hs/.may_include b/src/feature/hs/.may_include
new file mode 100644
index 0000000000..11c5ffbb14
--- /dev/null
+++ b/src/feature/hs/.may_include
@@ -0,0 +1,2 @@
+*.h
+*.inc
diff --git a/src/feature/hs/feature_hs.md b/src/feature/hs/feature_hs.md
new file mode 100644
index 0000000000..299d07e014
--- /dev/null
+++ b/src/feature/hs/feature_hs.md
@@ -0,0 +1,8 @@
+@dir /feature/hs
+@brief feature/hs: v3 (current) onion service protocol
+
+This directory implements the v3 onion service protocol,
+as specified in
+[rend-spec-v3.txt](https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt).
+
+
diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c
index 9817113b23..44cd2505fd 100644
--- a/src/feature/hs/hs_cache.c
+++ b/src/feature/hs/hs_cache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,12 +27,27 @@
static int cached_client_descriptor_has_expired(time_t now,
const hs_cache_client_descriptor_t *cached_desc);
+/** Helper function: Return true iff the cache entry has a decrypted
+ * descriptor.
+ *
+ * A NULL desc object in the entry means that we were not able to decrypt the
+ * descriptor because we are likely lacking client authorization. It is still
+ * a valid entry but some operations can't be done without the decrypted
+ * descriptor thus this function MUST be used to safe guard access to the
+ * decrypted desc object. */
+static inline bool
+entry_has_decrypted_descriptor(const hs_cache_client_descriptor_t *entry)
+{
+ tor_assert(entry);
+ return (entry->desc != NULL);
+}
+
/********************** Directory HS cache ******************/
-/* Directory descriptor cache. Map indexed by blinded key. */
+/** Directory descriptor cache. Map indexed by blinded key. */
static digest256map_t *hs_cache_v3_dir;
-/* Remove a given descriptor from our cache. */
+/** Remove a given descriptor from our cache. */
static void
remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc)
{
@@ -40,7 +55,7 @@ remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc)
digest256map_remove(hs_cache_v3_dir, desc->key);
}
-/* Store a given descriptor in our cache. */
+/** Store a given descriptor in our cache. */
static void
store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc)
{
@@ -48,7 +63,7 @@ store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc)
digest256map_set(hs_cache_v3_dir, desc->key, desc);
}
-/* Query our cache and return the entry or NULL if not found. */
+/** Query our cache and return the entry or NULL if not found. */
static hs_cache_dir_descriptor_t *
lookup_v3_desc_as_dir(const uint8_t *key)
{
@@ -59,7 +74,7 @@ lookup_v3_desc_as_dir(const uint8_t *key)
#define cache_dir_desc_free(val) \
FREE_AND_NULL(hs_cache_dir_descriptor_t, cache_dir_desc_free_, (val))
-/* Free a directory descriptor object. */
+/** Free a directory descriptor object. */
static void
cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc)
{
@@ -71,7 +86,7 @@ cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc)
tor_free(desc);
}
-/* Helper function: Use by the free all function using the digest256map
+/** Helper function: Use by the free all function using the digest256map
* interface to cache entries. */
static void
cache_dir_desc_free_void(void *ptr)
@@ -79,7 +94,7 @@ cache_dir_desc_free_void(void *ptr)
cache_dir_desc_free_(ptr);
}
-/* Create a new directory cache descriptor object from a encoded descriptor.
+/** Create a new directory cache descriptor object from a encoded descriptor.
* On success, return the heap-allocated cache object, otherwise return NULL if
* we can't decode the descriptor. */
static hs_cache_dir_descriptor_t *
@@ -109,7 +124,7 @@ cache_dir_desc_new(const char *desc)
return NULL;
}
-/* Return the size of a cache entry in bytes. */
+/** Return the size of a cache entry in bytes. */
static size_t
cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry)
{
@@ -117,7 +132,7 @@ cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry)
+ strlen(entry->encoded_desc));
}
-/* Try to store a valid version 3 descriptor in the directory cache. Return 0
+/** Try to store a valid version 3 descriptor in the directory cache. Return 0
* on success else a negative value is returned indicating that we have a
* newer version in our cache. On error, caller is responsible to free the
* given descriptor desc. */
@@ -167,7 +182,7 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
return -1;
}
-/* Using the query which is the base64 encoded blinded key of a version 3
+/** Using the query which is the base64 encoded blinded key of a version 3
* descriptor, lookup in our directory cache the entry. If found, 1 is
* returned and desc_out is populated with a newly allocated string being the
* encoded descriptor. If not found, 0 is returned and desc_out is untouched.
@@ -202,7 +217,7 @@ cache_lookup_v3_as_dir(const char *query, const char **desc_out)
return -1;
}
-/* Clean the v3 cache by removing any entry that has expired using the
+/** Clean the v3 cache by removing any entry that has expired using the
* <b>global_cutoff</b> value. If <b>global_cutoff</b> is 0, the cleaning
* process will use the lifetime found in the plaintext data section. Return
* the number of bytes cleaned. */
@@ -252,7 +267,7 @@ cache_clean_v3_as_dir(time_t now, time_t global_cutoff)
return bytes_removed;
}
-/* Given an encoded descriptor, store it in the directory cache depending on
+/** Given an encoded descriptor, store it in the directory cache depending on
* which version it is. Return a negative value on error. On success, 0 is
* returned. */
int
@@ -287,7 +302,7 @@ hs_cache_store_as_dir(const char *desc)
return -1;
}
-/* Using the query, lookup in our directory cache the entry. If found, 1 is
+/** Using the query, lookup in our directory cache the entry. If found, 1 is
* returned and desc_out is populated with a newly allocated string being
* the encoded descriptor. If not found, 0 is returned and desc_out is
* untouched. On error, a negative value is returned and desc_out is
@@ -312,7 +327,7 @@ hs_cache_lookup_as_dir(uint32_t version, const char *query,
return found;
}
-/* Clean all directory caches using the current time now. */
+/** Clean all directory caches using the current time now. */
void
hs_cache_clean_as_dir(time_t now)
{
@@ -329,23 +344,38 @@ hs_cache_clean_as_dir(time_t now)
/********************** Client-side HS cache ******************/
-/* Client-side HS descriptor cache. Map indexed by service identity key. */
+/** Client-side HS descriptor cache. Map indexed by service identity key. */
static digest256map_t *hs_cache_v3_client;
-/* Client-side introduction point state cache. Map indexed by service public
+/** Client-side introduction point state cache. Map indexed by service public
* identity key (onion address). It contains hs_cache_client_intro_state_t
* objects all related to a specific service. */
static digest256map_t *hs_cache_client_intro_state;
-/* Return the size of a client cache entry in bytes. */
+/** Return the size of a client cache entry in bytes. */
static size_t
cache_get_client_entry_size(const hs_cache_client_descriptor_t *entry)
{
- return sizeof(*entry) +
- strlen(entry->encoded_desc) + hs_desc_obj_size(entry->desc);
+ size_t size = 0;
+
+ if (entry == NULL) {
+ goto end;
+ }
+ size += sizeof(*entry);
+
+ if (entry->encoded_desc) {
+ size += strlen(entry->encoded_desc);
+ }
+
+ if (entry_has_decrypted_descriptor(entry)) {
+ size += hs_desc_obj_size(entry->desc);
+ }
+
+ end:
+ return size;
}
-/* Remove a given descriptor from our cache. */
+/** Remove a given descriptor from our cache. */
static void
remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc)
{
@@ -355,7 +385,7 @@ remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc)
rend_cache_decrement_allocation(cache_get_client_entry_size(desc));
}
-/* Store a given descriptor in our cache. */
+/** Store a given descriptor in our cache. */
static void
store_v3_desc_as_client(hs_cache_client_descriptor_t *desc)
{
@@ -365,7 +395,7 @@ store_v3_desc_as_client(hs_cache_client_descriptor_t *desc)
rend_cache_increment_allocation(cache_get_client_entry_size(desc));
}
-/* Query our cache and return the entry or NULL if not found or if expired. */
+/** Query our cache and return the entry or NULL if not found or if expired. */
STATIC hs_cache_client_descriptor_t *
lookup_v3_desc_as_client(const uint8_t *key)
{
@@ -388,15 +418,17 @@ lookup_v3_desc_as_client(const uint8_t *key)
return cached_desc;
}
-/* Parse the encoded descriptor in <b>desc_str</b> using
- * <b>service_identity_pk<b> to decrypt it first.
+/** Parse the encoded descriptor in <b>desc_str</b> using
+ * <b>service_identity_pk</b> to decrypt it first.
*
* If everything goes well, allocate and return a new
* hs_cache_client_descriptor_t object. In case of error, return NULL. */
static hs_cache_client_descriptor_t *
cache_client_desc_new(const char *desc_str,
- const ed25519_public_key_t *service_identity_pk)
+ const ed25519_public_key_t *service_identity_pk,
+ hs_desc_decode_status_t *decode_status_out)
{
+ hs_desc_decode_status_t ret;
hs_descriptor_t *desc = NULL;
hs_cache_client_descriptor_t *client_desc = NULL;
@@ -404,10 +436,24 @@ cache_client_desc_new(const char *desc_str,
tor_assert(service_identity_pk);
/* Decode the descriptor we just fetched. */
- if (hs_client_decode_descriptor(desc_str, service_identity_pk, &desc) < 0) {
+ ret = hs_client_decode_descriptor(desc_str, service_identity_pk, &desc);
+ if (ret != HS_DESC_DECODE_OK &&
+ ret != HS_DESC_DECODE_NEED_CLIENT_AUTH &&
+ ret != HS_DESC_DECODE_BAD_CLIENT_AUTH) {
+ /* In the case of a missing or bad client authorization, we'll keep the
+ * descriptor in the cache because those credentials can arrive later. */
goto end;
}
- tor_assert(desc);
+ /* Make sure we do have a descriptor if decoding was successful. */
+ if (ret == HS_DESC_DECODE_OK) {
+ tor_assert(desc);
+ } else {
+ if (BUG(desc != NULL)) {
+ /* We are not suppose to have a descriptor if the decoding code is not
+ * indicating success. Just in case, bail early to recover. */
+ goto end;
+ }
+ }
/* All is good: make a cache object for this descriptor */
client_desc = tor_malloc_zero(sizeof(hs_cache_client_descriptor_t));
@@ -420,6 +466,9 @@ cache_client_desc_new(const char *desc_str,
client_desc->encoded_desc = tor_strdup(desc_str);
end:
+ if (decode_status_out) {
+ *decode_status_out = ret;
+ }
return client_desc;
}
@@ -448,7 +497,7 @@ cache_client_desc_free_void(void *ptr)
cache_client_desc_free(desc);
}
-/* Return a newly allocated and initialized hs_cache_intro_state_t object. */
+/** Return a newly allocated and initialized hs_cache_intro_state_t object. */
static hs_cache_intro_state_t *
cache_intro_state_new(void)
{
@@ -460,21 +509,21 @@ cache_intro_state_new(void)
#define cache_intro_state_free(val) \
FREE_AND_NULL(hs_cache_intro_state_t, cache_intro_state_free_, (val))
-/* Free an hs_cache_intro_state_t object. */
+/** Free an hs_cache_intro_state_t object. */
static void
cache_intro_state_free_(hs_cache_intro_state_t *state)
{
tor_free(state);
}
-/* Helper function: used by the free all function. */
+/** Helper function: used by the free all function. */
static void
cache_intro_state_free_void(void *state)
{
cache_intro_state_free_(state);
}
-/* Return a newly allocated and initialized hs_cache_client_intro_state_t
+/** Return a newly allocated and initialized hs_cache_client_intro_state_t
* object. */
static hs_cache_client_intro_state_t *
cache_client_intro_state_new(void)
@@ -488,7 +537,7 @@ cache_client_intro_state_new(void)
FREE_AND_NULL(hs_cache_client_intro_state_t, \
cache_client_intro_state_free_, (val))
-/* Free a cache_client_intro_state object. */
+/** Free a cache_client_intro_state object. */
static void
cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache)
{
@@ -499,14 +548,14 @@ cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache)
tor_free(cache);
}
-/* Helper function: used by the free all function. */
+/** Helper function: used by the free all function. */
static void
cache_client_intro_state_free_void(void *entry)
{
cache_client_intro_state_free_(entry);
}
-/* For the given service identity key service_pk and an introduction
+/** For the given service identity key service_pk and an introduction
* authentication key auth_key, lookup the intro state object. Return 1 if
* found and put it in entry if not NULL. Return 0 if not found and entry is
* untouched. */
@@ -541,7 +590,7 @@ cache_client_intro_state_lookup(const ed25519_public_key_t *service_pk,
return 0;
}
-/* Note the given failure in state. */
+/** Note the given failure in state. */
static void
cache_client_intro_state_note(hs_cache_intro_state_t *state,
rend_intro_point_failure_t failure)
@@ -563,7 +612,7 @@ cache_client_intro_state_note(hs_cache_intro_state_t *state,
}
}
-/* For the given service identity key service_pk and an introduction
+/** For the given service identity key service_pk and an introduction
* authentication key auth_key, add an entry in the client intro state cache
* If no entry exists for the service, it will create one. If state is non
* NULL, it will point to the new intro state entry. */
@@ -597,7 +646,7 @@ cache_client_intro_state_add(const ed25519_public_key_t *service_pk,
}
}
-/* Remove every intro point state entry from cache that has been created
+/** Remove every intro point state entry from cache that has been created
* before or at the cutoff. */
static void
cache_client_intro_state_clean(time_t cutoff,
@@ -614,7 +663,7 @@ cache_client_intro_state_clean(time_t cutoff,
} DIGEST256MAP_FOREACH_END;
}
-/* Return true iff no intro points are in this cache. */
+/** Return true iff no intro points are in this cache. */
static int
cache_client_intro_state_is_empty(const hs_cache_client_intro_state_t *cache)
{
@@ -635,9 +684,25 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
tor_assert(client_desc);
/* Check if we already have a descriptor from this HS in cache. If we do,
- * check if this descriptor is newer than the cached one */
+ * check if this descriptor is newer than the cached one only if we have a
+ * decoded descriptor. We do keep non-decoded descriptor that requires
+ * client authorization. */
cache_entry = lookup_v3_desc_as_client(client_desc->key.pubkey);
if (cache_entry != NULL) {
+ /* If the current or the new cache entry don't have a decrypted descriptor
+ * (missing client authorization), we always replace the current one with
+ * the new one. Reason is that we can't inspect the revision counter
+ * within the plaintext data so we blindly replace. */
+ if (!entry_has_decrypted_descriptor(cache_entry) ||
+ !entry_has_decrypted_descriptor(client_desc)) {
+ remove_v3_desc_as_client(cache_entry);
+ cache_client_desc_free(cache_entry);
+ goto store;
+ }
+
+ /* From this point on, we know that the decrypted descriptor is in the
+ * current entry and new object thus safe to access. */
+
/* If we have an entry in our cache that has a revision counter greater
* than the one we just fetched, discard the one we fetched. */
if (cache_entry->desc->plaintext_data.revision_counter >
@@ -657,6 +722,7 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
cache_client_desc_free(cache_entry);
}
+ store:
/* Store descriptor in cache */
store_v3_desc_as_client(client_desc);
@@ -664,7 +730,7 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
return 0;
}
-/* Return true iff the cached client descriptor at <b>cached_desc</b has
+/** Return true iff the cached client descriptor at <b>cached_desc</b> has
* expired. */
static int
cached_client_descriptor_has_expired(time_t now,
@@ -687,7 +753,7 @@ cached_client_descriptor_has_expired(time_t now,
return 0;
}
-/* clean the client cache using now as the current time. Return the total size
+/** clean the client cache using now as the current time. Return the total size
* of removed bytes from the cache. */
static size_t
cache_clean_v3_as_client(time_t now)
@@ -710,11 +776,15 @@ cache_clean_v3_as_client(time_t now)
MAP_DEL_CURRENT(key);
entry_size = cache_get_client_entry_size(entry);
bytes_removed += entry_size;
+
/* We just removed an old descriptor. We need to close all intro circuits
- * so we don't have leftovers that can be selected while lacking a
- * descriptor. We leave the rendezvous circuits opened because they could
- * be in use. */
- hs_client_close_intro_circuits_from_desc(entry->desc);
+ * if the descriptor is decrypted so we don't have leftovers that can be
+ * selected while lacking a descriptor. Circuits are selected by intro
+ * authentication key thus we need the descriptor. We leave the rendezvous
+ * circuits opened because they could be in use. */
+ if (entry_has_decrypted_descriptor(entry)) {
+ hs_client_close_intro_circuits_from_desc(entry->desc);
+ }
/* Entry is not in the cache anymore, destroy it. */
cache_client_desc_free(entry);
/* Update our OOM. We didn't use the remove() function because we are in
@@ -752,7 +822,9 @@ hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key)
}
/** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
- * its HS descriptor if it's stored in our cache, or NULL if not. */
+ * its HS descriptor if it's stored in our cache, or NULL if not or if the
+ * descriptor was never decrypted. The later can happen if we are waiting for
+ * client authorization to be added. */
const hs_descriptor_t *
hs_cache_lookup_as_client(const ed25519_public_key_t *key)
{
@@ -761,27 +833,41 @@ hs_cache_lookup_as_client(const ed25519_public_key_t *key)
tor_assert(key);
cached_desc = lookup_v3_desc_as_client(key->pubkey);
- if (cached_desc) {
- tor_assert(cached_desc->desc);
+ if (cached_desc && entry_has_decrypted_descriptor(cached_desc)) {
return cached_desc->desc;
}
return NULL;
}
-/** Public API: Given an encoded descriptor, store it in the client HS
- * cache. Return -1 on error, 0 on success .*/
-int
+/** Public API: Given an encoded descriptor, store it in the client HS cache.
+ * Return a decode status which changes how we handle the SOCKS connection
+ * depending on its value:
+ *
+ * HS_DESC_DECODE_OK: Returned on success. Descriptor was properly decoded
+ * and is now stored.
+ *
+ * HS_DESC_DECODE_NEED_CLIENT_AUTH: Client authorization is needed but the
+ * descriptor was still stored.
+ *
+ * HS_DESC_DECODE_BAD_CLIENT_AUTH: Client authorization for this descriptor
+ * was not usable but the descriptor was
+ * still stored.
+ *
+ * Any other codes means indicate where the error occured and the descriptor
+ * was not stored. */
+hs_desc_decode_status_t
hs_cache_store_as_client(const char *desc_str,
const ed25519_public_key_t *identity_pk)
{
+ hs_desc_decode_status_t ret;
hs_cache_client_descriptor_t *client_desc = NULL;
tor_assert(desc_str);
tor_assert(identity_pk);
/* Create client cache descriptor object */
- client_desc = cache_client_desc_new(desc_str, identity_pk);
+ client_desc = cache_client_desc_new(desc_str, identity_pk, &ret);
if (!client_desc) {
log_warn(LD_GENERAL, "HSDesc parsing failed!");
log_debug(LD_GENERAL, "Failed to parse HSDesc: %s.", escaped(desc_str));
@@ -790,17 +876,54 @@ hs_cache_store_as_client(const char *desc_str,
/* Push it to the cache */
if (cache_store_as_client(client_desc) < 0) {
+ ret = HS_DESC_DECODE_GENERIC_ERROR;
goto err;
}
- return 0;
+ return ret;
err:
cache_client_desc_free(client_desc);
- return -1;
+ return ret;
}
-/* Clean all client caches using the current time now. */
+/** Remove and free a client cache descriptor entry for the given onion
+ * service ed25519 public key. If the descriptor is decoded, the intro
+ * circuits are closed if any.
+ *
+ * This does nothing if no descriptor exists for the given key. */
+void
+hs_cache_remove_as_client(const ed25519_public_key_t *key)
+{
+ hs_cache_client_descriptor_t *cached_desc = NULL;
+
+ tor_assert(key);
+
+ cached_desc = lookup_v3_desc_as_client(key->pubkey);
+ if (!cached_desc) {
+ return;
+ }
+ /* If we have a decrypted/decoded descriptor, attempt to close its
+ * introduction circuit(s). We shouldn't have circuit(s) without a
+ * descriptor else it will lead to a failure. */
+ if (entry_has_decrypted_descriptor(cached_desc)) {
+ hs_client_close_intro_circuits_from_desc(cached_desc->desc);
+ }
+ /* Remove and free. */
+ remove_v3_desc_as_client(cached_desc);
+ cache_client_desc_free(cached_desc);
+
+ /* Logging. */
+ {
+ char key_b64[BASE64_DIGEST256_LEN + 1];
+ digest256_to_base64(key_b64, (const char *) key);
+ log_info(LD_REND, "Onion service v3 descriptor '%s' removed "
+ "from client cache",
+ safe_str_client(key_b64));
+ }
+}
+
+/** Clean all client caches using the current time now. */
void
hs_cache_clean_as_client(time_t now)
{
@@ -811,7 +934,7 @@ hs_cache_clean_as_client(time_t now)
cache_clean_v3_as_client(now);
}
-/* Purge the client descriptor cache. */
+/** Purge the client descriptor cache. */
void
hs_cache_purge_as_client(void)
{
@@ -828,7 +951,7 @@ hs_cache_purge_as_client(void)
log_info(LD_REND, "Hidden service client descriptor cache purged.");
}
-/* For a given service identity public key and an introduction authentication
+/** For a given service identity public key and an introduction authentication
* key, note the given failure in the client intro state cache. */
void
hs_cache_client_intro_state_note(const ed25519_public_key_t *service_pk,
@@ -850,7 +973,7 @@ hs_cache_client_intro_state_note(const ed25519_public_key_t *service_pk,
cache_client_intro_state_note(entry, failure);
}
-/* For a given service identity public key and an introduction authentication
+/** For a given service identity public key and an introduction authentication
* key, return true iff it is present in the failure cache. */
const hs_cache_intro_state_t *
hs_cache_client_intro_state_find(const ed25519_public_key_t *service_pk,
@@ -861,7 +984,7 @@ hs_cache_client_intro_state_find(const ed25519_public_key_t *service_pk,
return state;
}
-/* Cleanup the client introduction state cache. */
+/** Cleanup the client introduction state cache. */
void
hs_cache_client_intro_state_clean(time_t now)
{
@@ -881,7 +1004,7 @@ hs_cache_client_intro_state_clean(time_t now)
} DIGEST256MAP_FOREACH_END;
}
-/* Purge the client introduction state cache. */
+/** Purge the client introduction state cache. */
void
hs_cache_client_intro_state_purge(void)
{
@@ -895,9 +1018,41 @@ hs_cache_client_intro_state_purge(void)
"cache purged.");
}
+/* This is called when new client authorization was added to the global state.
+ * It attemps to decode the descriptor of the given service identity key.
+ *
+ * Return true if decoding was successful else false. */
+bool
+hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk)
+{
+ bool ret = false;
+ hs_cache_client_descriptor_t *cached_desc = NULL;
+
+ tor_assert(service_pk);
+
+ if (!hs_cache_v3_client) {
+ return false;
+ }
+
+ cached_desc = lookup_v3_desc_as_client(service_pk->pubkey);
+ if (cached_desc == NULL || entry_has_decrypted_descriptor(cached_desc)) {
+ /* No entry for that service or the descriptor is already decoded. */
+ goto end;
+ }
+
+ /* Attempt a decode. If we are successful, inform the caller. */
+ if (hs_client_decode_descriptor(cached_desc->encoded_desc, service_pk,
+ &cached_desc->desc) == HS_DESC_DECODE_OK) {
+ ret = true;
+ }
+
+ end:
+ return ret;
+}
+
/**************** Generics *********************************/
-/* Do a round of OOM cleanup on all directory caches. Return the amount of
+/** Do a round of OOM cleanup on all directory caches. Return the amount of
* removed bytes. It is possible that the returned value is lower than
* min_remove_bytes if the caches get emptied out so the caller should be
* aware of this. */
@@ -951,7 +1106,7 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
return bytes_removed;
}
-/* Return the maximum size of a v3 HS descriptor. */
+/** Return the maximum size of a v3 HS descriptor. */
unsigned int
hs_cache_get_max_descriptor_size(void)
{
@@ -960,7 +1115,7 @@ hs_cache_get_max_descriptor_size(void)
HS_DESC_MAX_LEN, 1, INT32_MAX);
}
-/* Initialize the hidden service cache subsystem. */
+/** Initialize the hidden service cache subsystem. */
void
hs_cache_init(void)
{
@@ -975,7 +1130,7 @@ hs_cache_init(void)
hs_cache_client_intro_state = digest256map_new();
}
-/* Cleanup the hidden service cache subsystem. */
+/** Cleanup the hidden service cache subsystem. */
void
hs_cache_free_all(void)
{
diff --git a/src/feature/hs/hs_cache.h b/src/feature/hs/hs_cache.h
index 079d31d437..bb3c77f224 100644
--- a/src/feature/hs/hs_cache.h
+++ b/src/feature/hs/hs_cache.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,47 +18,47 @@
struct ed25519_public_key_t;
-/* This is the maximum time an introduction point state object can stay in the
+/** 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)
-/* Introduction point state. */
+/** Introduction point state. */
typedef struct hs_cache_intro_state_t {
- /* When this entry was created and put in the cache. */
+ /** When this entry was created and put in the cache. */
time_t created_ts;
- /* Did it suffered a generic error? */
+ /** Did it suffered a generic error? */
unsigned int error : 1;
- /* Did it timed out? */
+ /** Did it timed out? */
unsigned int timed_out : 1;
- /* How many times we tried to reached it and it was unreachable. */
+ /** How many times we tried to reached it and it was unreachable. */
uint32_t unreachable_count;
} hs_cache_intro_state_t;
typedef struct hs_cache_client_intro_state_t {
- /* Contains hs_cache_intro_state_t object indexed by introduction point
+ /** Contains hs_cache_intro_state_t object indexed by introduction point
* authentication key. */
digest256map_t *intro_points;
} hs_cache_client_intro_state_t;
-/* Descriptor representation on the directory side which is a subset of
+/** Descriptor representation on the directory side which is a subset of
* information that the HSDir can decode and serve it. */
typedef struct hs_cache_dir_descriptor_t {
- /* This object is indexed using the blinded pubkey located in the plaintext
+ /** This object is indexed using the blinded pubkey located in the plaintext
* data which is populated only once the descriptor has been successfully
* decoded and validated. This simply points to that pubkey. */
const uint8_t *key;
- /* When does this entry has been created. Used to expire entries. */
+ /** When does this entry has been created. Used to expire entries. */
time_t created_ts;
- /* Descriptor plaintext information. Obviously, we can't decrypt the
+ /** 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
+ /** Encoded descriptor which is basically in text form. It's a NUL terminated
* string thus safe to strlen(). */
char *encoded_desc;
} hs_cache_dir_descriptor_t;
@@ -83,8 +83,9 @@ const hs_descriptor_t *
hs_cache_lookup_as_client(const struct ed25519_public_key_t *key);
const char *
hs_cache_lookup_encoded_as_client(const struct ed25519_public_key_t *key);
-int hs_cache_store_as_client(const char *desc_str,
- const struct ed25519_public_key_t *identity_pk);
+hs_desc_decode_status_t hs_cache_store_as_client(const char *desc_str,
+ const struct ed25519_public_key_t *identity_pk);
+void hs_cache_remove_as_client(const struct ed25519_public_key_t *key);
void hs_cache_clean_as_client(time_t now);
void hs_cache_purge_as_client(void);
@@ -99,24 +100,28 @@ const hs_cache_intro_state_t *hs_cache_client_intro_state_find(
void hs_cache_client_intro_state_clean(time_t now);
void hs_cache_client_intro_state_purge(void);
+bool hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk);
+
#ifdef HS_CACHE_PRIVATE
#include "lib/crypt_ops/crypto_ed25519.h"
/** Represents a locally cached HS descriptor on a hidden service client. */
typedef struct hs_cache_client_descriptor_t {
- /* This object is indexed using the service identity public key */
+ /** This object is indexed using the service identity public key */
struct ed25519_public_key_t key;
- /* When will this entry expire? We expire cached client descriptors in the
+ /** When will this entry expire? We expire cached client descriptors in the
* start of the next time period, since that's when clients need to start
* using the next blinded key of the service. */
time_t expiration_ts;
- /* The cached descriptor, this object is the owner. It can't be NULL. A
- * cache object without a valid descriptor is not possible. */
+ /** The cached decoded descriptor, this object is the owner. This can be
+ * NULL if the descriptor couldn't be decoded due to missing or bad client
+ * authorization. It can be decoded later from the encoded_desc object if
+ * the proper client authorization is given tor. */
hs_descriptor_t *desc;
- /* Encoded descriptor in string form. Can't be NULL. */
+ /** Encoded descriptor in string form. Can't be NULL. */
char *encoded_desc;
} hs_cache_client_descriptor_t;
diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c
index df59f73c1b..fc9f4a2654 100644
--- a/src/feature/hs/hs_cell.c
+++ b/src/feature/hs/hs_cell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,7 @@
#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/origin_circuit_st.h"
@@ -24,7 +25,7 @@
#include "trunnel/hs/cell_introduce1.h"
#include "trunnel/hs/cell_rendezvous.h"
-/* Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is
+/** Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is
* the cell content up to the ENCRYPTED section of length encoded_cell_len.
* The encrypted param is the start of the ENCRYPTED section of length
* encrypted_len. The mac_key is the key needed for the computation of the MAC
@@ -67,14 +68,17 @@ compute_introduce_mac(const uint8_t *encoded_cell, size_t encoded_cell_len,
memwipe(mac_msg, 0, sizeof(mac_msg));
}
-/* From a set of keys, subcredential and the ENCRYPTED section of an
- * INTRODUCE2 cell, return a newly allocated intro cell keys structure.
- * Finally, the client public key is copied in client_pk. On error, return
- * NULL. */
+/**
+ * From a set of keys, a list of subcredentials, and the ENCRYPTED section of
+ * an INTRODUCE2 cell, return an array of newly allocated intro cell keys
+ * structures. Finally, the client public key is copied in client_pk. On
+ * error, return NULL.
+ **/
static hs_ntor_intro_cell_keys_t *
get_introduce2_key_material(const ed25519_public_key_t *auth_key,
const curve25519_keypair_t *enc_key,
- const uint8_t *subcredential,
+ size_t n_subcredentials,
+ const hs_subcredential_t *subcredentials,
const uint8_t *encrypted_section,
curve25519_public_key_t *client_pk)
{
@@ -82,17 +86,19 @@ get_introduce2_key_material(const ed25519_public_key_t *auth_key,
tor_assert(auth_key);
tor_assert(enc_key);
- tor_assert(subcredential);
+ tor_assert(n_subcredentials > 0);
+ tor_assert(subcredentials);
tor_assert(encrypted_section);
tor_assert(client_pk);
- keys = tor_malloc_zero(sizeof(*keys));
+ keys = tor_calloc(n_subcredentials, sizeof(hs_ntor_intro_cell_keys_t));
/* First bytes of the ENCRYPTED section are the client public key. */
memcpy(client_pk->public_key, encrypted_section, CURVE25519_PUBKEY_LEN);
- if (hs_ntor_service_get_introduce1_keys(auth_key, enc_key, client_pk,
- subcredential, keys) < 0) {
+ if (hs_ntor_service_get_introduce1_keys_multi(auth_key, enc_key, client_pk,
+ n_subcredentials,
+ subcredentials, keys) < 0) {
/* Don't rely on the caller to wipe this on error. */
memwipe(client_pk, 0, sizeof(curve25519_public_key_t));
tor_free(keys);
@@ -101,7 +107,7 @@ get_introduce2_key_material(const ed25519_public_key_t *auth_key,
return keys;
}
-/* Using the given encryption key, decrypt the encrypted_section of length
+/** Using the given encryption key, decrypt the encrypted_section of length
* encrypted_section_len of an INTRODUCE2 cell and return a newly allocated
* buffer containing the decrypted data. On decryption failure, NULL is
* returned. */
@@ -136,7 +142,7 @@ decrypt_introduce2(const uint8_t *enc_key, const uint8_t *encrypted_section,
return decrypted;
}
-/* Given a pointer to the decrypted data of the ENCRYPTED section of an
+/** Given a pointer to the decrypted data of the ENCRYPTED section of an
* INTRODUCE2 cell of length decrypted_len, parse and validate the cell
* content. Return a newly allocated cell structure or NULL on error. The
* circuit and service object are only used for logging purposes. */
@@ -188,7 +194,7 @@ parse_introduce2_encrypted(const uint8_t *decrypted_data,
return NULL;
}
-/* Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA
+/** 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. */
@@ -210,7 +216,7 @@ build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key,
return cell_len;
}
-/* Parse an INTRODUCE2 cell from payload of size payload_len for the given
+/** 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.
*
@@ -249,7 +255,7 @@ parse_introduce2_cell(const hs_service_t *service,
return -1;
}
-/* Set the onion public key onion_pk in cell, the encrypted section of an
+/** Set the onion public key onion_pk in cell, the encrypted section of an
* INTRODUCE1 cell. */
static void
introduce1_set_encrypted_onion_key(trn_cell_introduce_encrypted_t *cell,
@@ -266,7 +272,7 @@ introduce1_set_encrypted_onion_key(trn_cell_introduce_encrypted_t *cell,
trn_cell_introduce_encrypted_getlen_onion_key(cell));
}
-/* Set the link specifiers in lspecs in cell, the encrypted section of an
+/** Set the link specifiers in lspecs in cell, the encrypted section of an
* INTRODUCE1 cell. */
static void
introduce1_set_encrypted_link_spec(trn_cell_introduce_encrypted_t *cell,
@@ -286,7 +292,7 @@ introduce1_set_encrypted_link_spec(trn_cell_introduce_encrypted_t *cell,
trn_cell_introduce_encrypted_add_nspecs(cell, ls));
}
-/* Set padding in the enc_cell only if needed that is the total length of both
+/** Set padding in the enc_cell only if needed that is the total length of both
* sections are below the mininum required for an INTRODUCE1 cell. */
static void
introduce1_set_encrypted_padding(const trn_cell_introduce1_t *cell,
@@ -306,7 +312,7 @@ introduce1_set_encrypted_padding(const trn_cell_introduce1_t *cell,
}
}
-/* Encrypt the ENCRYPTED payload and encode it in the cell using the enc_cell
+/** Encrypt the ENCRYPTED payload and encode it in the cell using the enc_cell
* and the INTRODUCE1 data.
*
* This can't fail but it is very important that the caller sets every field
@@ -394,7 +400,7 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell,
tor_free(encrypted);
}
-/* Using the INTRODUCE1 data, setup the ENCRYPTED section in cell. This means
+/** Using the INTRODUCE1 data, setup the ENCRYPTED section in cell. This means
* set it, encrypt it and encode it. */
static void
introduce1_set_encrypted(trn_cell_introduce1_t *cell,
@@ -435,7 +441,7 @@ introduce1_set_encrypted(trn_cell_introduce1_t *cell,
trn_cell_introduce_encrypted_free(enc_cell);
}
-/* Set the authentication key in the INTRODUCE1 cell from the given data. */
+/** Set the authentication key in the INTRODUCE1 cell from the given data. */
static void
introduce1_set_auth_key(trn_cell_introduce1_t *cell,
const hs_cell_introduce1_data_t *data)
@@ -451,7 +457,7 @@ 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. */
+/** 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)
@@ -473,7 +479,7 @@ introduce1_set_legacy_id(trn_cell_introduce1_t *cell,
}
}
-/* Build and add to the given DoS cell extension the given parameter type and
+/** Build and add to the given DoS cell extension the given parameter type and
* value. */
static void
build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext,
@@ -493,7 +499,7 @@ build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext,
/* Not freeing the trunnel object because it is now owned by dos_ext. */
}
-/* Build the DoS defense cell extension and put it in the given extensions
+/** Build the DoS defense cell extension and put it in the given extensions
* object. Return 0 on success, -1 on failure. (Right now, failure is only
* possible if there is a bug.) */
static int
@@ -568,7 +574,7 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config,
/* Public API */
/* ========== */
-/* Allocate and build all the ESTABLISH_INTRO cell extension. The given
+/** 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 *
build_establish_intro_extensions(const hs_service_config_t *service_config,
@@ -599,7 +605,7 @@ build_establish_intro_extensions(const hs_service_config_t *service_config,
return extensions;
}
-/* Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
+/** 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
@@ -725,7 +731,7 @@ hs_cell_build_establish_intro(const char *circ_nonce,
return cell_len;
}
-/* Parse the INTRO_ESTABLISHED cell in the payload of size payload_len. If we
+/** Parse the INTRO_ESTABLISHED cell in the payload of size payload_len. If we
* are successful at parsing it, return the length of the parsed cell else a
* negative value on error. */
ssize_t
@@ -747,7 +753,75 @@ hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
return ret;
}
-/* Parse the INTRODUCE2 cell using data which contains everything we need to
+/** For the encrypted INTRO2 cell in <b>encrypted_section</b>, use the crypto
+ * material in <b>data</b> to compute the right ntor keys. Also validate the
+ * INTRO2 MAC to ensure that the keys are the right ones.
+ *
+ * Return NULL on failure to either produce the key material or on MAC
+ * validation. Else return a newly allocated intro keys object. */
+static hs_ntor_intro_cell_keys_t *
+get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data,
+ const uint8_t *encrypted_section,
+ size_t encrypted_section_len)
+{
+ hs_ntor_intro_cell_keys_t *intro_keys = NULL;
+ hs_ntor_intro_cell_keys_t *intro_keys_result = NULL;
+
+ /* Build the key material out of the key material found in the cell. */
+ intro_keys = get_introduce2_key_material(data->auth_pk, data->enc_kp,
+ data->n_subcredentials,
+ data->subcredentials,
+ encrypted_section,
+ &data->client_pk);
+ if (intro_keys == NULL) {
+ log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to "
+ "compute key material");
+ return NULL;
+ }
+
+ /* Make sure we are not about to underflow. */
+ if (BUG(encrypted_section_len < DIGEST256_LEN)) {
+ return NULL;
+ }
+
+ /* Validate MAC from the cell and our computed key material. The MAC field
+ * in the cell is at the end of the encrypted section. */
+ intro_keys_result = tor_malloc_zero(sizeof(*intro_keys_result));
+ for (unsigned i = 0; i < data->n_subcredentials; ++i) {
+ uint8_t mac[DIGEST256_LEN];
+
+ /* The MAC field is at the very end of the ENCRYPTED section. */
+ size_t mac_offset = encrypted_section_len - sizeof(mac);
+ /* Compute the MAC. Use the entire encoded payload with a length up to the
+ * ENCRYPTED section. */
+ compute_introduce_mac(data->payload,
+ data->payload_len - encrypted_section_len,
+ encrypted_section, encrypted_section_len,
+ intro_keys[i].mac_key,
+ sizeof(intro_keys[i].mac_key),
+ mac, sizeof(mac));
+ /* Time-invariant conditional copy: if the MAC is what we expected, then
+ * set intro_keys_result to intro_keys[i]. Otherwise, don't: but don't
+ * leak which one it was! */
+ bool equal = tor_memeq(mac, encrypted_section + mac_offset, sizeof(mac));
+ memcpy_if_true_timei(equal, intro_keys_result, &intro_keys[i],
+ sizeof(*intro_keys_result));
+ }
+
+ /* We no longer need intro_keys. */
+ memwipe(intro_keys, 0,
+ sizeof(hs_ntor_intro_cell_keys_t) * data->n_subcredentials);
+ tor_free(intro_keys);
+
+ if (safe_mem_is_zero(intro_keys_result, sizeof(*intro_keys_result))) {
+ log_info(LD_REND, "Invalid MAC validation for INTRODUCE2 cell");
+ tor_free(intro_keys_result); /* sets intro_keys_result to NULL */
+ }
+
+ return intro_keys_result;
+}
+
+/** 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
* service and circ are only used for logging purposes. */
@@ -795,47 +869,29 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
/* Check our replay cache for this introduction point. */
if (replaycache_add_test_and_elapsed(data->replay_cache, encrypted_section,
encrypted_section_len, &elapsed)) {
- log_warn(LD_REND, "Possible replay detected! An INTRODUCE2 cell with the"
+ log_warn(LD_REND, "Possible replay detected! An INTRODUCE2 cell with the "
"same ENCRYPTED section was seen %ld seconds ago. "
"Dropping cell.", (long int) elapsed);
goto done;
}
- /* Build the key material out of the key material found in the cell. */
- intro_keys = get_introduce2_key_material(data->auth_pk, data->enc_kp,
- data->subcredential,
- encrypted_section,
- &data->client_pk);
- if (intro_keys == NULL) {
- log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to "
- "compute key material on circuit %u for service %s",
- TO_CIRCUIT(circ)->n_circ_id,
+ /* First bytes of the ENCRYPTED section are the client public key (they are
+ * guaranteed to exist because of the length check above). We are gonna use
+ * the client public key to compute the ntor keys and decrypt the payload:
+ */
+ memcpy(&data->client_pk.public_key, encrypted_section,
+ CURVE25519_PUBKEY_LEN);
+
+ /* Get the right INTRODUCE2 ntor keys and verify the cell MAC */
+ intro_keys = get_introduce2_keys_and_verify_mac(data, encrypted_section,
+ encrypted_section_len);
+ if (!intro_keys) {
+ log_warn(LD_REND, "Could not get valid INTRO2 keys on circuit %u "
+ "for service %s", TO_CIRCUIT(circ)->n_circ_id,
safe_str_client(service->onion_address));
goto done;
}
- /* Validate MAC from the cell and our computed key material. The MAC field
- * in the cell is at the end of the encrypted section. */
- {
- uint8_t mac[DIGEST256_LEN];
- /* The MAC field is at the very end of the ENCRYPTED section. */
- size_t mac_offset = encrypted_section_len - sizeof(mac);
- /* Compute the MAC. Use the entire encoded payload with a length up to the
- * ENCRYPTED section. */
- compute_introduce_mac(data->payload,
- data->payload_len - encrypted_section_len,
- encrypted_section, encrypted_section_len,
- intro_keys->mac_key, sizeof(intro_keys->mac_key),
- mac, sizeof(mac));
- if (tor_memcmp(mac, encrypted_section + mac_offset, sizeof(mac))) {
- log_info(LD_REND, "Invalid MAC validation for INTRODUCE2 cell on "
- "circuit %u for service %s",
- TO_CIRCUIT(circ)->n_circ_id,
- safe_str_client(service->onion_address));
- goto done;
- }
- }
-
{
/* The ENCRYPTED_DATA section starts just after the CLIENT_PK. */
const uint8_t *encrypted_data =
@@ -908,7 +964,7 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
return ret;
}
-/* Build a RENDEZVOUS1 cell with the given rendezvous cookie and handshake
+/** Build a RENDEZVOUS1 cell with the given rendezvous cookie and handshake
* info. The encoded cell is put in cell_out and the length of the data is
* returned. This can't fail. */
ssize_t
@@ -942,7 +998,7 @@ hs_cell_build_rendezvous1(const uint8_t *rendezvous_cookie,
return cell_len;
}
-/* Build an INTRODUCE1 cell from the given data. The encoded cell is put in
+/** Build an INTRODUCE1 cell from the given data. The encoded cell is put in
* cell_out which must be of at least size RELAY_PAYLOAD_SIZE. On success, the
* encoded length is returned else a negative value and the content of
* cell_out should be ignored. */
@@ -983,7 +1039,7 @@ hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data,
return cell_len;
}
-/* Build an ESTABLISH_RENDEZVOUS cell from the given rendezvous_cookie. The
+/** Build an ESTABLISH_RENDEZVOUS cell from the given rendezvous_cookie. The
* encoded cell is put in cell_out which must be of at least
* RELAY_PAYLOAD_SIZE. On success, the encoded length is returned and the
* caller should clear up the content of the cell.
@@ -1000,7 +1056,7 @@ hs_cell_build_establish_rendezvous(const uint8_t *rendezvous_cookie,
return HS_REND_COOKIE_LEN;
}
-/* Handle an INTRODUCE_ACK cell encoded in payload of length payload_len.
+/** Handle an INTRODUCE_ACK cell encoded in payload of length payload_len.
* Return the status code on success else a negative value if the cell as not
* decodable. */
int
@@ -1035,7 +1091,7 @@ hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len)
return ret;
}
-/* Handle a RENDEZVOUS2 cell encoded in payload of length payload_len. On
+/** Handle a RENDEZVOUS2 cell encoded in payload of length payload_len. On
* success, handshake_info contains the data in the HANDSHAKE_INFO field, and
* 0 is returned. On error, a negative value is returned. */
int
@@ -1067,7 +1123,7 @@ hs_cell_parse_rendezvous2(const uint8_t *payload, size_t payload_len,
return ret;
}
-/* Clear the given INTRODUCE1 data structure data. */
+/** Clear the given INTRODUCE1 data structure data. */
void
hs_cell_introduce1_data_clear(hs_cell_introduce1_data_t *data)
{
diff --git a/src/feature/hs/hs_cell.h b/src/feature/hs/hs_cell.h
index 864b6fda5f..2b28c44c50 100644
--- a/src/feature/hs/hs_cell.h
+++ b/src/feature/hs/hs_cell.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,35 +12,37 @@
#include "core/or/or.h"
#include "feature/hs/hs_service.h"
-/* An INTRODUCE1 cell requires at least this amount of bytes (see section
+/** An INTRODUCE1 cell requires at least this amount of bytes (see section
* 3.2.2 of the specification). Below this value, the cell must be padded. */
#define HS_CELL_INTRODUCE1_MIN_SIZE 246
-/* This data structure contains data that we need to build an INTRODUCE1 cell
+struct hs_subcredential_t;
+
+/** This data structure contains data that we need to build an INTRODUCE1 cell
* used by the INTRODUCE1 build function. */
typedef struct hs_cell_introduce1_data_t {
- /* Is this a legacy introduction point? */
+ /** Is this a legacy introduction point? */
unsigned int is_legacy : 1;
- /* (Legacy only) The encryption key for a legacy intro point. Only set if
+ /** (Legacy only) The encryption key for a legacy intro point. Only set if
* is_legacy is true. */
const crypto_pk_t *legacy_key;
- /* Introduction point authentication public key. */
+ /** Introduction point authentication public key. */
const ed25519_public_key_t *auth_pk;
- /* Introduction point encryption public key. */
+ /** Introduction point encryption public key. */
const curve25519_public_key_t *enc_pk;
- /* Subcredentials of the service. */
- const uint8_t *subcredential;
- /* Onion public key for the ntor handshake. */
+ /** Subcredentials of the service. */
+ const struct hs_subcredential_t *subcredential;
+ /** Onion public key for the ntor handshake. */
const curve25519_public_key_t *onion_pk;
- /* Rendezvous cookie. */
+ /** Rendezvous cookie. */
const uint8_t *rendezvous_cookie;
- /* Public key put before the encrypted data (CLIENT_PK). */
+ /** Public key put before the encrypted data (CLIENT_PK). */
const curve25519_keypair_t *client_kp;
- /* Rendezvous point link specifiers. */
+ /** Rendezvous point link specifiers. */
smartlist_t *link_specifiers;
} hs_cell_introduce1_data_t;
-/* This data structure contains data that we need to parse an INTRODUCE2 cell
+/** This data structure contains data that we need to parse an INTRODUCE2 cell
* which is used by the INTRODUCE2 cell parsing function. On a successful
* parsing, the onion_pk and rendezvous_cookie will be populated with the
* computed key material from the cell data. This structure is only used during
@@ -48,32 +50,37 @@ typedef struct hs_cell_introduce1_data_t {
typedef struct hs_cell_introduce2_data_t {
/*** Immutable Section: Set on structure init. ***/
- /* Introduction point authentication public key. Pointer owned by the
+ /** Introduction point authentication public key. Pointer owned by the
introduction point object through which we received the INTRO2 cell. */
const ed25519_public_key_t *auth_pk;
- /* Introduction point encryption keypair for the ntor handshake. Pointer
+ /** Introduction point encryption keypair for the ntor handshake. Pointer
owned by the introduction point object through which we received the
INTRO2 cell*/
const curve25519_keypair_t *enc_kp;
- /* Subcredentials of the service. Pointer owned by the descriptor that owns
- the introduction point through which we received the INTRO2 cell. */
- const uint8_t *subcredential;
- /* Payload of the received encoded cell. */
+ /**
+ * Length of the subcredentials array below.
+ **/
+ size_t n_subcredentials;
+ /** Array of <b>n_subcredentials</b> subcredentials for the service. Pointer
+ * owned by the descriptor that owns the introduction point through which we
+ * received the INTRO2 cell. */
+ const struct hs_subcredential_t *subcredentials;
+ /** Payload of the received encoded cell. */
const uint8_t *payload;
- /* Size of the payload of the received encoded cell. */
+ /** Size of the payload of the received encoded cell. */
size_t payload_len;
/*** Mutable Section: Set upon parsing INTRODUCE2 cell. ***/
- /* Onion public key computed using the INTRODUCE2 encrypted section. */
+ /** Onion public key computed using the INTRODUCE2 encrypted section. */
curve25519_public_key_t onion_pk;
- /* Rendezvous cookie taken from the INTRODUCE2 encrypted section. */
+ /** Rendezvous cookie taken from the INTRODUCE2 encrypted section. */
uint8_t rendezvous_cookie[REND_COOKIE_LEN];
- /* Client public key from the INTRODUCE2 encrypted section. */
+ /** Client public key from the INTRODUCE2 encrypted section. */
curve25519_public_key_t client_pk;
- /* Link specifiers of the rendezvous point. Contains link_specifier_t. */
+ /** Link specifiers of the rendezvous point. Contains link_specifier_t. */
smartlist_t *link_specifiers;
- /* Replay cache of the introduction point. */
+ /** Replay cache of the introduction point. */
replaycache_t *replay_cache;
} hs_cell_introduce2_data_t;
@@ -117,4 +124,3 @@ build_establish_intro_extensions(const hs_service_config_t *service_config,
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* !defined(TOR_HS_CELL_H) */
-
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index 5e213b5aba..447f664f81 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,12 +19,15 @@
#include "feature/client/circpathbias.h"
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuit.h"
+#include "feature/hs/hs_ob.h"
#include "feature/hs/hs_circuitmap.h"
+#include "feature/hs/hs_client.h"
#include "feature/hs/hs_ident.h"
#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"
@@ -40,7 +43,7 @@
#include "feature/nodelist/node_st.h"
#include "core/or/origin_circuit_st.h"
-/* A circuit is about to become an e2e rendezvous circuit. Check
+/** A circuit is about to become an e2e rendezvous circuit. Check
* <b>circ_purpose</b> and ensure that it's properly set. Return true iff
* circuit purpose is properly set, otherwise return false. */
static int
@@ -67,7 +70,7 @@ circuit_purpose_is_correct_for_rend(unsigned int circ_purpose,
return 1;
}
-/* Create and return a crypt path for the final hop of a v3 prop224 rendezvous
+/** Create and return a crypt path for the final hop of a v3 prop224 rendezvous
* circuit. Initialize the crypt path crypto using the output material from the
* ntor key exchange at <b>ntor_key_seed</b>.
*
@@ -101,7 +104,7 @@ 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
+/** 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
@@ -152,7 +155,7 @@ create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body)
return hop;
}
-/* Append the final <b>hop</b> to the cpath of the rend <b>circ</b>, and mark
+/** 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
finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
@@ -193,7 +196,7 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
}
}
-/* For a given circuit and a service introduction point object, register the
+/** For a given circuit and a service introduction point object, register the
* intro circuit to the circuitmap. This supports legacy intro point. */
static void
register_intro_circ(const hs_service_intro_point_t *ip,
@@ -211,7 +214,7 @@ register_intro_circ(const hs_service_intro_point_t *ip,
}
}
-/* Return the number of opened introduction circuit for the given circuit that
+/** Return the number of opened introduction circuit for the given circuit that
* is matching its identity key. */
static unsigned int
count_opened_desc_intro_point_circuits(const hs_service_t *service,
@@ -243,7 +246,7 @@ count_opened_desc_intro_point_circuits(const hs_service_t *service,
return count;
}
-/* From a given service, rendezvous cookie and handshake info, create a
+/** From a given service, rendezvous cookie and handshake info, create a
* rendezvous point circuit identifier. This can't fail. */
STATIC hs_ident_circuit_t *
create_rp_circuit_identifier(const hs_service_t *service,
@@ -282,7 +285,7 @@ create_rp_circuit_identifier(const hs_service_t *service,
return ident;
}
-/* From a given service and service intro point, create an introduction point
+/** From a given service and service intro point, create an introduction point
* circuit identifier. This can't fail. */
static hs_ident_circuit_t *
create_intro_circuit_identifier(const hs_service_t *service,
@@ -299,7 +302,7 @@ create_intro_circuit_identifier(const hs_service_t *service,
return ident;
}
-/* For a given introduction point and an introduction circuit, send the
+/** For a given introduction point and an introduction circuit, send the
* ESTABLISH_INTRO cell. The service object is used for logging. This can fail
* and if so, the circuit is closed and the intro point object is flagged
* that the circuit is not established anymore which is important for the
@@ -349,7 +352,7 @@ send_establish_intro(const hs_service_t *service,
memwipe(payload, 0, sizeof(payload));
}
-/* Return a string constant describing the anonymity of service. */
+/** Return a string constant describing the anonymity of service. */
static const char *
get_service_anonymity_string(const hs_service_t *service)
{
@@ -360,15 +363,15 @@ get_service_anonymity_string(const hs_service_t *service)
}
}
-/* For a given service, the ntor onion key and a rendezvous cookie, launch a
+/** For a given service, the ntor onion key and a rendezvous cookie, launch a
* circuit to the rendezvous point specified by the link specifiers. On
* success, a circuit identifier is attached to the circuit with the needed
* data. This function will try to open a circuit for a maximum value of
* MAX_REND_FAILURES then it will give up. */
-static void
-launch_rendezvous_point_circuit(const hs_service_t *service,
- const hs_service_intro_point_t *ip,
- const hs_cell_introduce2_data_t *data)
+MOCK_IMPL(STATIC void,
+launch_rendezvous_point_circuit,(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ const hs_cell_introduce2_data_t *data))
{
int circ_needs_uptime;
time_t now = time(NULL);
@@ -469,7 +472,7 @@ launch_rendezvous_point_circuit(const hs_service_t *service,
extend_info_free(info);
}
-/* Return true iff the given service rendezvous circuit circ is allowed for a
+/** Return true iff the given service rendezvous circuit circ is allowed for a
* relaunch to the rendezvous point. */
static int
can_relaunch_service_rendezvous_point(const origin_circuit_t *circ)
@@ -516,7 +519,7 @@ can_relaunch_service_rendezvous_point(const origin_circuit_t *circ)
return 0;
}
-/* Retry the rendezvous point of circ by launching a new circuit to it. */
+/** Retry the rendezvous point of circ by launching a new circuit to it. */
static void
retry_service_rendezvous_point(const origin_circuit_t *circ)
{
@@ -565,7 +568,7 @@ retry_service_rendezvous_point(const origin_circuit_t *circ)
return;
}
-/* Using the given descriptor intro point ip, the node of the
+/** Using the given descriptor intro point ip, the node of the
* rendezvous point rp_node and the service's subcredential, populate the
* already allocated intro1_data object with the needed key material and link
* specifiers.
@@ -576,7 +579,7 @@ retry_service_rendezvous_point(const origin_circuit_t *circ)
static int
setup_introduce1_data(const hs_desc_intro_point_t *ip,
const node_t *rp_node,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_cell_introduce1_data_t *intro1_data)
{
int ret = -1;
@@ -618,11 +621,41 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
return ret;
}
+/** Helper: cleanup function for client circuit. This is for every HS version.
+ * It is called from hs_circ_cleanup_on_close() entry point. */
+static void
+cleanup_on_close_client_circ(circuit_t *circ)
+{
+ tor_assert(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. */
+}
+
+/** Helper: cleanup function for client circuit. This is for every HS version.
+ * It is called from hs_circ_cleanup_on_free() entry point. */
+static void
+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)) {
+ 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. */
+}
+
/* ========== */
/* Public API */
/* ========== */
-/* Return an introduction point circuit matching the given intro point object.
+/** Return an introduction point circuit matching the given intro point object.
* NULL is returned is no such circuit can be found. */
origin_circuit_t *
hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip)
@@ -637,7 +670,29 @@ hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip)
}
}
-/* Called when we fail building a rendezvous circuit at some point other than
+/** Return an introduction point established circuit matching the given intro
+ * point object. The circuit purpose has to be CIRCUIT_PURPOSE_S_INTRO. NULL
+ * is returned is no such circuit can be found. */
+origin_circuit_t *
+hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip)
+{
+ origin_circuit_t *circ;
+
+ 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);
+ }
+
+ /* Only return circuit if it is established. */
+ return (circ && TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO) ?
+ circ : NULL;
+}
+
+/** 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.
*
@@ -677,7 +732,7 @@ hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ)
return;
}
-/* For a given service and a service intro point, launch a circuit to the
+/** For a given service and a service intro point, launch a circuit to the
* extend info ei. If the service is a single onion, and direct_conn is true,
* a one-hop circuit will be requested.
*
@@ -738,7 +793,7 @@ hs_circ_launch_intro_point(hs_service_t *service,
return ret;
}
-/* Called when a service introduction point circuit is done building. Given
+/** Called when a service introduction point circuit is done building. Given
* the service and intro point object, this function will send the
* ESTABLISH_INTRO cell on the circuit. Return 0 on success. Return 1 if the
* circuit has been repurposed to General because we already have too many
@@ -807,7 +862,7 @@ hs_circ_service_intro_has_opened(hs_service_t *service,
return ret;
}
-/* Called when a service rendezvous point circuit is done building. Given the
+/** Called when a service rendezvous point circuit is done building. Given the
* service and the circuit, this function will send a RENDEZVOUS1 cell on the
* circuit using the information in the circuit identifier. If the cell can't
* be sent, the circuit is closed. */
@@ -873,7 +928,7 @@ hs_circ_service_rp_has_opened(const hs_service_t *service,
memwipe(payload, 0, sizeof(payload));
}
-/* Circ has been expecting an INTRO_ESTABLISHED cell that just arrived. Handle
+/** Circ has been expecting an INTRO_ESTABLISHED cell that just arrived. Handle
* the INTRO_ESTABLISHED cell payload of length payload_len arriving on the
* given introduction circuit circ. The service is only used for logging
* purposes. Return 0 on success else a negative value. */
@@ -918,7 +973,43 @@ hs_circ_handle_intro_established(const hs_service_t *service,
return ret;
}
-/* We just received an INTRODUCE2 cell on the established introduction circuit
+/**
+ * Go into <b>data</b> and add the right subcredential to be able to handle
+ * this incoming cell.
+ *
+ * <b>desc_subcred</b> is the subcredential of the descriptor that corresponds
+ * to the intro point that received this intro request. This subcredential
+ * should be used if we are not an onionbalance instance.
+ *
+ * Return 0 if everything went well, or -1 in case of internal error.
+ */
+static int
+get_subcredential_for_handling_intro2_cell(const hs_service_t *service,
+ hs_cell_introduce2_data_t *data,
+ const hs_subcredential_t *desc_subcred)
+{
+ /* Handle the simple case first: We are not an onionbalance instance and we
+ * should just use the regular descriptor subcredential */
+ if (!hs_ob_service_is_instance(service)) {
+ data->n_subcredentials = 1;
+ data->subcredentials = desc_subcred;
+ return 0;
+ }
+
+ /* This should not happen since we should have made onionbalance
+ * subcredentials when we created our descriptors. */
+ if (BUG(!service->state.ob_subcreds)) {
+ return -1;
+ }
+
+ /* We are an onionbalance instance: */
+ data->n_subcredentials = service->state.n_ob_subcreds;
+ data->subcredentials = service->state.ob_subcreds;
+
+ return 0;
+}
+
+/** We just received an INTRODUCE2 cell on the established introduction circuit
* circ. Handle the INTRODUCE2 payload of size payload_len for the given
* circuit and service. This cell is associated with the intro point object ip
* and the subcredential. Return 0 on success else a negative value. */
@@ -926,7 +1017,7 @@ int
hs_circ_handle_introduce2(const hs_service_t *service,
const origin_circuit_t *circ,
hs_service_intro_point_t *ip,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
const uint8_t *payload, size_t payload_len)
{
int ret = -1;
@@ -943,12 +1034,16 @@ hs_circ_handle_introduce2(const hs_service_t *service,
* parsed, decrypted and key material computed correctly. */
data.auth_pk = &ip->auth_key_kp.pubkey;
data.enc_kp = &ip->enc_key_kp;
- data.subcredential = subcredential;
data.payload = payload;
data.payload_len = payload_len;
data.link_specifiers = smartlist_new();
data.replay_cache = ip->replay_cache;
+ if (get_subcredential_for_handling_intro2_cell(service,
+ &data, subcredential)) {
+ goto done;
+ }
+
if (hs_cell_parse_introduce2(&data, circ, service) < 0) {
goto done;
}
@@ -985,7 +1080,7 @@ hs_circ_handle_introduce2(const hs_service_t *service,
return ret;
}
-/* Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key
+/** Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key
* exchange output material at <b>ntor_key_seed</b> and setup <b>circ</b> to
* serve as a rendezvous end-to-end circuit between the client and the
* service. If <b>is_service_side</b> is set, then we are the hidden service
@@ -1015,7 +1110,7 @@ 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
+/** 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. */
@@ -1040,7 +1135,7 @@ hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
return 0;
}
-/* Given the introduction circuit intro_circ, the rendezvous circuit
+/** 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.
*
@@ -1052,7 +1147,7 @@ int
hs_circ_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ,
const hs_desc_intro_point_t *ip,
- const uint8_t *subcredential)
+ const hs_subcredential_t *subcredential)
{
int ret = -1;
ssize_t payload_len;
@@ -1125,7 +1220,7 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ,
return ret;
}
-/* Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On
+/** Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On
* success, 0 is returned else -1 and the circuit is marked for close. */
int
hs_circ_send_establish_rendezvous(origin_circuit_t *circ)
@@ -1176,30 +1271,136 @@ hs_circ_send_establish_rendezvous(origin_circuit_t *circ)
return -1;
}
-/* We are about to close or free this <b>circ</b>. Clean it up from any
- * related HS data structures. This function can be called multiple times
- * safely for the same circuit. */
+/** Circuit cleanup strategy:
+ *
+ * What follows is a series of functions that notifies the HS subsystem of 3
+ * different circuit cleanup phase: close, free and repurpose.
+ *
+ * Tor can call any of those in any orders so they have to be safe between
+ * each other. In other words, the free should never depend on close to be
+ * called before.
+ *
+ * The "on_close()" is called from circuit_mark_for_close() which is
+ * considered the tor fast path and thus as little work as possible should
+ * done in that function. Currently, we only remove the circuit from the HS
+ * circuit map and move on.
+ *
+ * The "on_free()" is called from circuit circuit_free_() and it is very
+ * important that at the end of the function, no state or objects related to
+ * this circuit remains alive.
+ *
+ * The "on_repurpose()" is called from circuit_change_purpose() for which we
+ * simply remove it from the HS circuit map. We do not have other cleanup
+ * requirements after that.
+ *
+ * NOTE: The onion service code, specifically the service code, cleans up
+ * lingering objects or state if any of its circuit disappear which is why
+ * our cleanup strategy doesn't involve any service specific actions. As long
+ * as the circuit is removed from the HS circuit map, it won't be used.
+ */
+
+/** We are about to close this <b>circ</b>. Clean it up from any related HS
+ * data structures. This function can be called multiple times safely for the
+ * same circuit. */
void
-hs_circ_cleanup(circuit_t *circ)
+hs_circ_cleanup_on_close(circuit_t *circ)
{
tor_assert(circ);
- /* If it's a service-side intro circ, notify the HS subsystem for the intro
- * point circuit closing so it can be dealt with cleanly. */
- if (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
- circ->purpose == CIRCUIT_PURPOSE_S_INTRO) {
- hs_service_intro_circ_has_closed(TO_ORIGIN_CIRCUIT(circ));
+ if (circuit_purpose_is_hs_client(circ->purpose)) {
+ cleanup_on_close_client_circ(circ);
}
- /* Clear HS circuitmap token for this circ (if any). Very important to be
- * done after the HS subsystem has been notified of the close else the
- * circuit will not be found.
- *
- * We do this at the close if possible because from that point on, the
- * circuit is good as dead. We can't rely on removing it in the circuit
- * free() function because we open a race window between the close and free
- * where we can't register a new circuit for the same intro point. */
+ /* On close, we simply remove it from the circuit map. It can not be used
+ * anymore. We keep this code path fast and lean. */
+
+ if (circ->hs_token) {
+ hs_circuitmap_remove_circuit(circ);
+ }
+}
+
+/** We are about to free this <b>circ</b>. Clean it up from any related HS
+ * data structures. This function can be called multiple times safely for the
+ * same circuit. */
+void
+hs_circ_cleanup_on_free(circuit_t *circ)
+{
+ tor_assert(circ);
+
+ /* NOTE: Bulk of the work of cleaning up a circuit is done here. */
+
+ if (circuit_purpose_is_hs_client(circ->purpose)) {
+ cleanup_on_free_client_circ(circ);
+ }
+
+ /* We have no assurance that the given HS circuit has been closed before and
+ * thus removed from the HS map. This actually happens in unit tests. */
+ if (circ->hs_token) {
+ hs_circuitmap_remove_circuit(circ);
+ }
+}
+
+/** We are about to repurpose this <b>circ</b>. Clean it up from any related
+ * HS data structures. This function can be called multiple times safely for
+ * the same circuit. */
+void
+hs_circ_cleanup_on_repurpose(circuit_t *circ)
+{
+ tor_assert(circ);
+
+ /* On repurpose, we simply remove it from the circuit map but we do not do
+ * the on_free actions since we don't treat a repurpose as something we need
+ * to report in the client cache failure. */
+
if (circ->hs_token) {
hs_circuitmap_remove_circuit(circ);
}
}
+
+/** Return true iff the given established client rendezvous circuit was sent
+ * into the INTRODUCE1 cell. This is called so we can take a decision on
+ * expiring or not the circuit.
+ *
+ * The caller MUST make sure the circuit is an established client rendezvous
+ * circuit (purpose: CIRCUIT_PURPOSE_C_REND_READY).
+ *
+ * This function supports all onion service versions. */
+bool
+hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ)
+{
+ tor_assert(circ);
+ /* This can only be called for a rendezvous circuit that is an established
+ * confirmed rendezsvous circuit but without an introduction ACK. */
+ tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_REND_READY);
+
+ /* The v2 and v3 circuit are handled differently:
+ *
+ * v2: A circ's pending_final_cpath field is non-NULL iff it is a rend circ
+ * and we have tried to send an INTRODUCE1 cell specifying it. Thus, if the
+ * pending_final_cpath field *is* NULL, then we want to not spare it.
+ *
+ * v3: When the INTRODUCE1 cell is sent, the introduction encryption public
+ * key is copied in the rendezvous circuit hs identifier. If it is a valid
+ * key, we know that this circuit is waiting the ACK on the introduction
+ * circuit. We want to _not_ spare the circuit if the key was never set. */
+
+ if (circ->rend_data) {
+ /* v2. */
+ if (circ->build_state && circ->build_state->pending_final_cpath != NULL) {
+ return true;
+ }
+ } else if (circ->hs_ident) {
+ /* v3. */
+ if (curve25519_public_key_is_ok(&circ->hs_ident->intro_enc_pk)) {
+ return true;
+ }
+ } else {
+ /* A circuit with an HS purpose without an hs_ident or rend_data in theory
+ * can not happen. In case, scream loudly and return false to the caller
+ * that the rendezvous was not sent in the INTRO1 cell. */
+ tor_assert_nonfatal_unreached();
+ }
+
+ /* The rendezvous has not been specified in the INTRODUCE1 cell. */
+ return false;
+}
diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h
index e168b301f1..22e936e685 100644
--- a/src/feature/hs/hs_circuit.h
+++ b/src/feature/hs/hs_circuit.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,8 +14,10 @@
#include "feature/hs/hs_service.h"
-/* Cleanup function when the circuit is closed or/and freed. */
-void hs_circ_cleanup(circuit_t *circ);
+/* Cleanup function when the circuit is closed or freed. */
+void hs_circ_cleanup_on_close(circuit_t *circ);
+void hs_circ_cleanup_on_free(circuit_t *circ);
+void hs_circ_cleanup_on_repurpose(circuit_t *circ);
/* Circuit API. */
int hs_circ_service_intro_has_opened(hs_service_t *service,
@@ -35,6 +37,8 @@ void hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ);
origin_circuit_t *hs_circ_service_get_intro_circ(
const hs_service_intro_point_t *ip);
+origin_circuit_t *hs_circ_service_get_established_intro_circ(
+ const hs_service_intro_point_t *ip);
/* Cell API. */
int hs_circ_handle_intro_established(const hs_service_t *service,
@@ -42,15 +46,16 @@ int hs_circ_handle_intro_established(const hs_service_t *service,
origin_circuit_t *circ,
const uint8_t *payload,
size_t payload_len);
+struct hs_subcredential_t;
int hs_circ_handle_introduce2(const hs_service_t *service,
const origin_circuit_t *circ,
hs_service_intro_point_t *ip,
- const uint8_t *subcredential,
+ const struct hs_subcredential_t *subcredential,
const uint8_t *payload, size_t payload_len);
int hs_circ_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ,
const hs_desc_intro_point_t *ip,
- const uint8_t *subcredential);
+ const struct hs_subcredential_t *subcredential);
int hs_circ_send_establish_rendezvous(origin_circuit_t *circ);
/* e2e circuit API. */
@@ -62,15 +67,24 @@ int hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
const uint8_t *rend_cell_body);
+bool hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ);
+
#ifdef HS_CIRCUIT_PRIVATE
+struct hs_ntor_rend_cell_keys_t;
+
STATIC hs_ident_circuit_t *
create_rp_circuit_identifier(const hs_service_t *service,
const uint8_t *rendezvous_cookie,
const curve25519_public_key_t *server_pk,
- const hs_ntor_rend_cell_keys_t *keys);
+ const struct hs_ntor_rend_cell_keys_t *keys);
+
+struct hs_cell_introduce2_data_t;
+MOCK_DECL(STATIC void,
+launch_rendezvous_point_circuit,(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ const struct hs_cell_introduce2_data_t *data));
#endif /* defined(HS_CIRCUIT_PRIVATE) */
#endif /* !defined(TOR_HS_CIRCUIT_H) */
-
diff --git a/src/feature/hs/hs_circuitmap.c b/src/feature/hs/hs_circuitmap.c
index e34f564fb4..466a02de39 100644
--- a/src/feature/hs/hs_circuitmap.c
+++ b/src/feature/hs/hs_circuitmap.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,13 +23,13 @@
/************************** HS circuitmap code *******************************/
-/* This is the hidden service circuitmap. It's a hash table that maps
+/** This is the hidden service circuitmap. It's a hash table that maps
introduction and rendezvous tokens to specific circuits such that given a
token it's easy to find the corresponding circuit. */
static struct hs_circuitmap_ht *the_hs_circuitmap = NULL;
-/* This is a helper function used by the hash table code (HT_). It returns 1 if
- * two circuits have the same HS token. */
+/** This is a helper function used by the hash table code (HT_). It returns 1
+ * if two circuits have the same HS token. */
static int
hs_circuits_have_same_token(const circuit_t *first_circuit,
const circuit_t *second_circuit)
@@ -60,8 +60,9 @@ hs_circuits_have_same_token(const circuit_t *first_circuit,
first_token->token_len);
}
-/* This is a helper function for the hash table code (HT_). It hashes a circuit
- * HS token into an unsigned int for use as a key by the hash table routines.*/
+/** This is a helper function for the hash table code (HT_). It hashes a
+ * circuit HS token into an unsigned int for use as a key by the hash table
+ * routines.*/
static inline unsigned int
hs_circuit_hash_token(const circuit_t *circuit)
{
@@ -71,19 +72,19 @@ hs_circuit_hash_token(const circuit_t *circuit)
circuit->hs_token->token_len);
}
-/* Register the circuitmap hash table */
+/** Register the circuitmap hash table */
HT_PROTOTYPE(hs_circuitmap_ht, // The name of the hashtable struct
circuit_t, // The name of the element struct,
hs_circuitmap_node, // The name of HT_ENTRY member
- hs_circuit_hash_token, hs_circuits_have_same_token)
+ hs_circuit_hash_token, hs_circuits_have_same_token);
HT_GENERATE2(hs_circuitmap_ht, circuit_t, hs_circuitmap_node,
hs_circuit_hash_token, hs_circuits_have_same_token,
- 0.6, tor_reallocarray, tor_free_)
+ 0.6, tor_reallocarray, tor_free_);
#ifdef TOR_UNIT_TESTS
-/* Return the global HS circuitmap. Used by unittests. */
+/** Return the global HS circuitmap. Used by unittests. */
hs_circuitmap_ht *
get_hs_circuitmap(void)
{
@@ -136,7 +137,7 @@ get_circuit_with_token(hs_token_t *search_token)
return HT_FIND(hs_circuitmap_ht, the_hs_circuitmap, &search_circ);
}
-/* Helper function that registers <b>circ</b> with <b>token</b> on the HS
+/** Helper function that registers <b>circ</b> with <b>token</b> on the HS
circuitmap. This function steals reference of <b>token</b>. */
static void
hs_circuitmap_register_impl(circuit_t *circ, hs_token_t *token)
@@ -186,7 +187,7 @@ hs_circuitmap_register_circuit(circuit_t *circ,
hs_circuitmap_register_impl(circ, hs_token);
}
-/* Helper function for hs_circuitmap_get_origin_circuit() and
+/** Helper function for hs_circuitmap_get_origin_circuit() and
* hs_circuitmap_get_or_circuit(). Because only circuit_t are indexed in the
* circuitmap, this function returns object type so the specialized functions
* using this helper can upcast it to the right type.
@@ -220,7 +221,7 @@ hs_circuitmap_get_circuit_impl(hs_token_type_t type,
return found_circ;
}
-/* Helper function: Query circuitmap for origin circuit with <b>token</b> of
+/** Helper function: Query circuitmap for origin circuit with <b>token</b> of
* size <b>token_len</b> and <b>type</b>. Only returns a circuit with purpose
* equal to the <b>wanted_circ_purpose</b> parameter and if it is NOT marked
* for close. Return NULL if no such circuit is found. */
@@ -244,7 +245,7 @@ hs_circuitmap_get_origin_circuit(hs_token_type_t type,
return TO_ORIGIN_CIRCUIT(circ);
}
-/* Helper function: Query circuitmap for OR circuit with <b>token</b> of size
+/** Helper function: Query circuitmap for OR circuit with <b>token</b> of size
* <b>token_len</b> and <b>type</b>. Only returns a circuit with purpose equal
* to the <b>wanted_circ_purpose</b> parameter and if it is NOT marked for
* close. Return NULL if no such circuit is found. */
@@ -272,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 v2 and v3 introduction circuit to this relay.
* Always return a newly allocated list for which it is the caller's
* responsability to free it. */
smartlist_t *
@@ -299,7 +300,7 @@ hs_circuitmap_get_all_intro_circ_relay_side(void)
return circuit_list;
}
-/* Public function: Return a v3 introduction circuit to this relay with
+/** Public function: Return a v3 introduction circuit to this relay with
* <b>auth_key</b>. Return NULL if no such circuit is found in the
* circuitmap. */
or_circuit_t *
@@ -311,7 +312,7 @@ hs_circuitmap_get_intro_circ_v3_relay_side(
CIRCUIT_PURPOSE_INTRO_POINT);
}
-/* Public function: Return v2 introduction circuit to this relay with
+/** 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)
@@ -321,7 +322,7 @@ hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest)
CIRCUIT_PURPOSE_INTRO_POINT);
}
-/* Public function: Return rendezvous circuit to this relay with rendezvous
+/** 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 *
hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie)
@@ -333,7 +334,7 @@ hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie)
/** Public relay-side setters: */
-/* Public function: Register rendezvous circuit with key <b>cookie</b> to the
+/** Public function: Register rendezvous circuit with key <b>cookie</b> to the
* circuitmap. */
void
hs_circuitmap_register_rend_circ_relay_side(or_circuit_t *circ,
@@ -343,7 +344,7 @@ 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
+/** 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,
@@ -354,7 +355,7 @@ hs_circuitmap_register_intro_circ_v2_relay_side(or_circuit_t *circ,
REND_TOKEN_LEN, digest);
}
-/* Public function: Register v3 intro circuit with key <b>auth_key</b> to the
+/** Public function: Register v3 intro circuit with key <b>auth_key</b> to the
* circuitmap. */
void
hs_circuitmap_register_intro_circ_v3_relay_side(or_circuit_t *circ,
@@ -367,7 +368,7 @@ hs_circuitmap_register_intro_circ_v3_relay_side(or_circuit_t *circ,
/**** Public servide-side getters: */
-/* Public function: Return v3 introduction circuit with <b>auth_key</b>
+/** Public function: Return v3 introduction circuit with <b>auth_key</b>
* originating from this hidden service. Return NULL if no such circuit is
* found in the circuitmap. */
origin_circuit_t *
@@ -392,9 +393,9 @@ 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. */
+/** 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)
{
@@ -416,7 +417,7 @@ hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest)
return circ;
}
-/* Public function: Return rendezvous circuit originating from this hidden
+/** 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. */
origin_circuit_t *
@@ -439,7 +440,7 @@ hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie)
return circ;
}
-/* Public function: Return client-side rendezvous circuit with rendezvous
+/** Public function: Return client-side rendezvous circuit with rendezvous
* <b>cookie</b>. It will look for circuits with the following purposes:
* a) CIRCUIT_PURPOSE_C_REND_READY: Established rend circuit (received
@@ -472,7 +473,7 @@ hs_circuitmap_get_rend_circ_client_side(const uint8_t *cookie)
return circ;
}
-/* Public function: Return client-side established rendezvous circuit with
+/** Public function: Return client-side established rendezvous circuit with
* rendezvous <b>cookie</b>. It will look for circuits with the following
* purposes:
*
@@ -514,7 +515,7 @@ 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
+/** 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,
@@ -525,7 +526,7 @@ hs_circuitmap_register_intro_circ_v2_service_side(origin_circuit_t *circ,
REND_TOKEN_LEN, digest);
}
-/* Public function: Register v3 intro circuit with key <b>auth_key</b> to the
+/** Public function: Register v3 intro circuit with key <b>auth_key</b> to the
* circuitmap. */
void
hs_circuitmap_register_intro_circ_v3_service_side(origin_circuit_t *circ,
@@ -536,7 +537,7 @@ hs_circuitmap_register_intro_circ_v3_service_side(origin_circuit_t *circ,
ED25519_PUBKEY_LEN, auth_key->pubkey);
}
-/* Public function: Register rendezvous circuit with key <b>cookie</b> to the
+/** Public function: Register rendezvous circuit with key <b>cookie</b> to the
* circuitmap. */
void
hs_circuitmap_register_rend_circ_service_side(origin_circuit_t *circ,
@@ -547,7 +548,7 @@ hs_circuitmap_register_rend_circ_service_side(origin_circuit_t *circ,
REND_TOKEN_LEN, cookie);
}
-/* Public function: Register rendezvous circuit with key <b>cookie</b> to the
+/** Public function: Register rendezvous circuit with key <b>cookie</b> to the
* client-side circuitmap. */
void
hs_circuitmap_register_rend_circ_client_side(origin_circuit_t *or_circ,
@@ -591,7 +592,7 @@ hs_circuitmap_remove_circuit(circuit_t *circ)
circ->hs_token = NULL;
}
-/* Public function: Initialize the global HS circuitmap. */
+/** Public function: Initialize the global HS circuitmap. */
void
hs_circuitmap_init(void)
{
@@ -601,7 +602,7 @@ hs_circuitmap_init(void)
HT_INIT(hs_circuitmap_ht, the_hs_circuitmap);
}
-/* Public function: Free all memory allocated by the global HS circuitmap. */
+/** Public function: Free all memory allocated by the global HS circuitmap. */
void
hs_circuitmap_free_all(void)
{
diff --git a/src/feature/hs/hs_circuitmap.h b/src/feature/hs/hs_circuitmap.h
index eac8230bbf..df3e7a6e7e 100644
--- a/src/feature/hs/hs_circuitmap.h
+++ b/src/feature/hs/hs_circuitmap.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@ typedef HT_HEAD(hs_circuitmap_ht, circuit_t) hs_circuitmap_ht;
typedef struct hs_token_t hs_token_t;
struct or_circuit_t;
struct origin_circuit_t;
+struct ed25519_public_key_t;
/** Public HS circuitmap API: */
@@ -21,7 +22,7 @@ struct origin_circuit_t;
struct or_circuit_t *
hs_circuitmap_get_intro_circ_v3_relay_side(const
- ed25519_public_key_t *auth_key);
+ 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 *
@@ -32,7 +33,7 @@ void hs_circuitmap_register_rend_circ_relay_side(struct or_circuit_t *circ,
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 ed25519_public_key_t *auth_key);
+ const struct ed25519_public_key_t *auth_key);
smartlist_t *hs_circuitmap_get_all_intro_circ_relay_side(void);
@@ -40,7 +41,7 @@ smartlist_t *hs_circuitmap_get_all_intro_circ_relay_side(void);
struct origin_circuit_t *
hs_circuitmap_get_intro_circ_v3_service_side(const
- ed25519_public_key_t *auth_key);
+ 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 *
@@ -54,8 +55,8 @@ 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 ed25519_public_key_t *auth_key);
+ struct origin_circuit_t *circ,
+ const struct ed25519_public_key_t *auth_key);
void hs_circuitmap_register_rend_circ_service_side(
struct origin_circuit_t *circ,
const uint8_t *cookie);
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index 8b63375939..d9c5d8ca1d 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -42,14 +42,15 @@
#include "core/or/entry_connection_st.h"
#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
+#include "core/or/socks_request_st.h"
-/* Client-side authorizations for hidden services; map of service identity
+/** Client-side authorizations for hidden services; map of service identity
* public key to hs_client_service_authorization_t *. */
static digest256map_t *client_auths = NULL;
#include "trunnel/hs/cell_introduce1.h"
-/* Return a human-readable string for the client fetch status code. */
+/** Return a human-readable string for the client fetch status code. */
static const char *
fetch_status_to_string(hs_client_fetch_status_t status)
{
@@ -73,7 +74,7 @@ fetch_status_to_string(hs_client_fetch_status_t status)
}
}
-/* Return true iff tor should close the SOCKS request(s) for the descriptor
+/** Return true iff tor should close the SOCKS request(s) for the descriptor
* fetch that ended up with this given status code. */
static int
fetch_status_should_close_socks(hs_client_fetch_status_t status)
@@ -100,12 +101,51 @@ fetch_status_should_close_socks(hs_client_fetch_status_t status)
return 1;
}
+/* Return a newly allocated list of all the entry connections that matches the
+ * given service identity pk. If service_identity_pk is NULL, all entry
+ * connections with an hs_ident are returned.
+ *
+ * Caller must free the returned list but does NOT have ownership of the
+ * object inside thus they have to remain untouched. */
+static smartlist_t *
+find_entry_conns(const ed25519_public_key_t *service_identity_pk)
+{
+ time_t now = time(NULL);
+ smartlist_t *conns = NULL, *entry_conns = NULL;
+
+ entry_conns = smartlist_new();
+
+ conns = connection_list_by_type_state(CONN_TYPE_AP,
+ AP_CONN_STATE_RENDDESC_WAIT);
+ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
+ entry_connection_t *entry_conn = TO_ENTRY_CONN(base_conn);
+ const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn);
+
+ /* Only consider the entry connections that matches the service for which
+ * we just fetched its descriptor. */
+ if (!edge_conn->hs_ident ||
+ (service_identity_pk &&
+ !ed25519_pubkey_eq(service_identity_pk,
+ &edge_conn->hs_ident->identity_pk))) {
+ continue;
+ }
+ assert_connection_ok(base_conn, now);
+
+ /* Validated! Add the entry connection to the list. */
+ smartlist_add(entry_conns, entry_conn);
+ } SMARTLIST_FOREACH_END(base_conn);
+
+ /* We don't have ownership of the objects in this list. */
+ smartlist_free(conns);
+ return entry_conns;
+}
+
/* Cancel all descriptor fetches currently in progress. */
static void
cancel_descriptor_fetches(void)
{
smartlist_t *conns =
- connection_list_by_type_state(CONN_TYPE_DIR, DIR_PURPOSE_FETCH_HSDESC);
+ connection_list_by_type_purpose(CONN_TYPE_DIR, DIR_PURPOSE_FETCH_HSDESC);
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
const hs_ident_dir_conn_t *ident = TO_DIR_CONN(conn)->hs_ident;
if (BUG(ident == NULL)) {
@@ -124,7 +164,7 @@ cancel_descriptor_fetches(void)
log_info(LD_REND, "Hidden service client descriptor fetches cancelled.");
}
-/* Get all connections that are waiting on a circuit and flag them back to
+/** Get all connections that are waiting on a circuit and flag them back to
* waiting for a hidden service descriptor for the given service key
* service_identity_pk. */
static void
@@ -151,7 +191,7 @@ flag_all_conn_wait_desc(const ed25519_public_key_t *service_identity_pk)
smartlist_free(conns);
}
-/* Remove tracked HSDir requests from our history for this hidden service
+/** Remove tracked HSDir requests from our history for this hidden service
* identity public key. */
static void
purge_hid_serv_request(const ed25519_public_key_t *identity_pk)
@@ -172,7 +212,7 @@ purge_hid_serv_request(const ed25519_public_key_t *identity_pk)
hs_purge_hid_serv_from_last_hid_serv_requests(base64_blinded_pk);
}
-/* Return true iff there is at least one pending directory descriptor request
+/** Return true iff there is at least one pending directory descriptor request
* for the service identity_pk. */
static int
directory_request_is_pending(const ed25519_public_key_t *identity_pk)
@@ -200,7 +240,7 @@ directory_request_is_pending(const ed25519_public_key_t *identity_pk)
return ret;
}
-/* Helper function that changes the state of an entry connection to waiting
+/** Helper function that changes the state of an entry connection to waiting
* for a circuit. For this to work properly, the connection timestamps are set
* to now and the connection is then marked as pending for a circuit. */
static void
@@ -220,7 +260,7 @@ mark_conn_as_waiting_for_circuit(connection_t *conn, time_t now)
connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn));
}
-/* We failed to fetch a descriptor for the service with <b>identity_pk</b>
+/** We failed to fetch a descriptor for the service with <b>identity_pk</b>
* because of <b>status</b>. Find all pending SOCKS connections for this
* service that are waiting on the descriptor and close them with
* <b>reason</b>. */
@@ -230,26 +270,13 @@ close_all_socks_conns_waiting_for_desc(const ed25519_public_key_t *identity_pk,
int reason)
{
unsigned int count = 0;
- time_t now = approx_time();
- smartlist_t *conns =
- connection_list_by_type_state(CONN_TYPE_AP, AP_CONN_STATE_RENDDESC_WAIT);
+ smartlist_t *entry_conns = find_entry_conns(identity_pk);
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
- entry_connection_t *entry_conn = TO_ENTRY_CONN(base_conn);
- const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn);
-
- /* Only consider the entry connections that matches the service for which
- * we tried to get the descriptor */
- if (!edge_conn->hs_ident ||
- !ed25519_pubkey_eq(identity_pk,
- &edge_conn->hs_ident->identity_pk)) {
- continue;
- }
- assert_connection_ok(base_conn, now);
+ SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) {
/* Unattach the entry connection which will close for the reason. */
connection_mark_unattached_ap(entry_conn, reason);
count++;
- } SMARTLIST_FOREACH_END(base_conn);
+ } SMARTLIST_FOREACH_END(entry_conn);
if (count > 0) {
char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
@@ -262,26 +289,26 @@ close_all_socks_conns_waiting_for_desc(const ed25519_public_key_t *identity_pk,
}
/* No ownership of the object(s) in this list. */
- smartlist_free(conns);
+ smartlist_free(entry_conns);
}
-/* Find all pending SOCKS connection waiting for a descriptor and retry them
+/** Find all pending SOCKS connection waiting for a descriptor and retry them
* all. This is called when the directory information changed. */
STATIC void
retry_all_socks_conn_waiting_for_desc(void)
{
- smartlist_t *conns =
- connection_list_by_type_state(CONN_TYPE_AP, AP_CONN_STATE_RENDDESC_WAIT);
+ smartlist_t *entry_conns = find_entry_conns(NULL);
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
+ SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) {
hs_client_fetch_status_t status;
- const edge_connection_t *edge_conn =
- ENTRY_TO_EDGE_CONN(TO_ENTRY_CONN(base_conn));
+ edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn);
+ connection_t *base_conn = &edge_conn->base_;
/* Ignore non HS or non v3 connection. */
if (edge_conn->hs_ident == NULL) {
continue;
}
+
/* In this loop, we will possibly try to fetch a descriptor for the
* pending connections because we just got more directory information.
* However, the refetch process can cleanup all SOCKS request to the same
@@ -315,13 +342,13 @@ retry_all_socks_conn_waiting_for_desc(void)
* closed or we are still missing directory information. Leave the
* connection in renddesc wait state so when we get more info, we'll be
* able to try it again. */
- } SMARTLIST_FOREACH_END(base_conn);
+ } SMARTLIST_FOREACH_END(entry_conn);
/* We don't have ownership of those objects. */
- smartlist_free(conns);
+ smartlist_free(entry_conns);
}
-/* A v3 HS circuit successfully connected to the hidden service. Update the
+/** A v3 HS circuit successfully connected to the hidden service. Update the
* stream state at <b>hs_conn_ident</b> appropriately. */
static void
note_connection_attempt_succeeded(const hs_ident_edge_conn_t *hs_conn_ident)
@@ -343,7 +370,7 @@ note_connection_attempt_succeeded(const hs_ident_edge_conn_t *hs_conn_ident)
* will be reset and thus possible to be retried. */
}
-/* Given the pubkey of a hidden service in <b>onion_identity_pk</b>, fetch its
+/** Given the pubkey of a hidden service in <b>onion_identity_pk</b>, fetch its
* descriptor by launching a dir connection to <b>hsdir</b>. Return a
* hs_client_fetch_status_t status code depending on how it went. */
static hs_client_fetch_status_t
@@ -451,7 +478,7 @@ fetch_v3_desc, (const ed25519_public_key_t *onion_identity_pk))
return directory_launch_v3_desc_fetch(onion_identity_pk, hsdir_rs);
}
-/* With a given <b>onion_identity_pk</b>, fetch its descriptor. If
+/** With a given <b>onion_identity_pk</b>, fetch its descriptor. If
* <b>hsdirs</b> is specified, use the directory servers specified in the list.
* Else, use a random server. */
void
@@ -469,7 +496,7 @@ hs_client_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk,
}
}
-/* Make sure that the given v3 origin circuit circ is a valid correct
+/** Make sure that the given v3 origin circuit circ is a valid correct
* introduction circuit. This will BUG() on any problems and hard assert if
* the anonymity of the circuit is not ok. Return 0 on success else -1 where
* the circuit should be mark for closed immediately. */
@@ -498,7 +525,7 @@ intro_circ_is_ok(const origin_circuit_t *circ)
return ret;
}
-/* Find a descriptor intro point object that matches the given ident in the
+/** Find a descriptor intro point object that matches the given ident in the
* given descriptor desc. Return NULL if not found. */
static const hs_desc_intro_point_t *
find_desc_intro_point_by_ident(const hs_ident_circuit_t *ident,
@@ -521,7 +548,7 @@ find_desc_intro_point_by_ident(const hs_ident_circuit_t *ident,
return intro_point;
}
-/* Find a descriptor intro point object from the descriptor object desc that
+/** Find a descriptor intro point object from the descriptor object desc that
* matches the given legacy identity digest in legacy_id. Return NULL if not
* found. */
static hs_desc_intro_point_t *
@@ -559,7 +586,7 @@ find_desc_intro_point_by_legacy_id(const char *legacy_id,
return ret_ip;
}
-/* Send an INTRODUCE1 cell along the intro circuit and populate the rend
+/** Send an INTRODUCE1 cell along the intro circuit and populate the rend
* circuit identifier with the needed key material for the e2e encryption.
* Return 0 on success, -1 if there is a transient error such that an action
* has been taken to recover and -2 if there is a permanent error indicating
@@ -619,7 +646,7 @@ send_introduce1(origin_circuit_t *intro_circ,
/* Send the INTRODUCE1 cell. */
if (hs_circ_send_introduce1(intro_circ, rend_circ, ip,
- desc->subcredential) < 0) {
+ &desc->subcredential) < 0) {
if (TO_CIRCUIT(intro_circ)->marked_for_close) {
/* If the introduction circuit was closed, we were unable to send the
* cell for some reasons. In any case, the intro circuit has to be
@@ -676,9 +703,12 @@ send_introduce1(origin_circuit_t *intro_circ,
return status;
}
-/* Using the introduction circuit circ, setup the authentication key of the
- * intro point this circuit has extended to. */
-static void
+/** Using the introduction circuit circ, setup the authentication key of the
+ * intro point this circuit has extended to.
+ *
+ * Return 0 if everything went well, otherwise return -1 in the case of errors.
+ */
+static int
setup_intro_circ_auth_key(origin_circuit_t *circ)
{
const hs_descriptor_t *desc;
@@ -692,30 +722,31 @@ setup_intro_circ_auth_key(origin_circuit_t *circ)
* and the client descriptor cache that gets purged (NEWNYM) or the
* cleaned up because it expired. Mark the circuit for close so a new
* descriptor fetch can occur. */
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
- goto end;
+ goto err;
}
/* We will go over every intro point and try to find which one is linked to
* that circuit. Those lists are small so it's not that expensive. */
ip = find_desc_intro_point_by_legacy_id(
circ->build_state->chosen_exit->identity_digest, desc);
- if (ip) {
- /* We got it, copy its authentication key to the identifier. */
- ed25519_pubkey_copy(&circ->hs_ident->intro_auth_pk,
- &ip->auth_key_cert->signed_key);
- goto end;
+ if (!ip) {
+ /* Reaching this point means we didn't find any intro point for this
+ * circuit which is not supposed to happen. */
+ log_info(LD_REND,"Could not match opened intro circuit with intro point.");
+ goto err;
}
- /* Reaching this point means we didn't find any intro point for this circuit
- * which is not supposed to happen. */
- tor_assert_nonfatal_unreached();
+ /* We got it, copy its authentication key to the identifier. */
+ ed25519_pubkey_copy(&circ->hs_ident->intro_auth_pk,
+ &ip->auth_key_cert->signed_key);
+ return 0;
- end:
- return;
+ err:
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
+ return -1;
}
-/* Called when an introduction circuit has opened. */
+/** Called when an introduction circuit has opened. */
static void
client_intro_circ_has_opened(origin_circuit_t *circ)
{
@@ -727,12 +758,14 @@ client_intro_circ_has_opened(origin_circuit_t *circ)
/* This is an introduction circuit so we'll attach the correct
* authentication key to the circuit identifier so it can be identified
* properly later on. */
- setup_intro_circ_auth_key(circ);
+ if (setup_intro_circ_auth_key(circ) < 0) {
+ return;
+ }
connection_ap_attach_pending(1);
}
-/* Called when a rendezvous circuit has opened. */
+/** Called when a rendezvous circuit has opened. */
static void
client_rendezvous_circ_has_opened(origin_circuit_t *circ)
{
@@ -745,10 +778,16 @@ client_rendezvous_circ_has_opened(origin_circuit_t *circ)
* the v3 rendezvous protocol */
if (rp_ei) {
const node_t *rp_node = node_get_by_id(rp_ei->identity_digest);
- if (rp_node) {
- if (BUG(!node_supports_v3_rendezvous_point(rp_node))) {
- return;
- }
+ if (rp_node && !node_supports_v3_rendezvous_point(rp_node)) {
+ /* Even tho we checked that this node supported v3 when we created the
+ rendezvous circuit, there is a chance that we might think it does
+ not support v3 anymore. This might happen if we got a new consensus
+ in the meanwhile, where the relay is still listed but its listed
+ descriptor digest has changed and hence we can't access its 'ri' or
+ 'md'. */
+ log_info(LD_REND, "Rendezvous node %s did not support v3 after circuit "
+ "has opened.", safe_str_client(extend_info_describe(rp_ei)));
+ return;
}
}
@@ -766,7 +805,7 @@ client_rendezvous_circ_has_opened(origin_circuit_t *circ)
}
}
-/* This is an helper function that convert a descriptor intro point object ip
+/** This is an helper function that convert a descriptor intro point object ip
* to a newly allocated extend_info_t object fully initialized. Return NULL if
* we can't convert it for which chances are that we are missing or malformed
* link specifiers. */
@@ -784,7 +823,7 @@ desc_intro_point_to_extend_info(const hs_desc_intro_point_t *ip)
return ei;
}
-/* Return true iff the intro point ip for the service service_pk is usable.
+/** Return true iff the intro point ip for the service service_pk is usable.
* This function checks if the intro point is in the client intro state cache
* and checks at the failures. It is considered usable if:
* - No error happened (INTRO_POINT_FAILURE_GENERIC)
@@ -829,7 +868,7 @@ intro_point_is_usable(const ed25519_public_key_t *service_pk,
return 0;
}
-/* Using a descriptor desc, return a newly allocated extend_info_t object of a
+/** Using a descriptor desc, return a newly allocated extend_info_t object of a
* randomly picked introduction point from its list. Return NULL if none are
* usable. */
STATIC extend_info_t *
@@ -934,7 +973,88 @@ client_get_random_intro(const ed25519_public_key_t *service_pk)
return ei;
}
-/* For this introduction circuit, we'll look at if we have any usable
+/** Return true iff all intro points for the given service have timed out. */
+static bool
+intro_points_all_timed_out(const ed25519_public_key_t *service_pk)
+{
+ bool ret = false;
+
+ tor_assert(service_pk);
+
+ const hs_descriptor_t *desc = hs_cache_lookup_as_client(service_pk);
+ if (BUG(!desc)) {
+ /* We can't introduce without a descriptor so ending up here means somehow
+ * between the introduction failure and this, the cache entry was removed
+ * which shouldn't be possible in theory. */
+ goto end;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ const hs_desc_intro_point_t *, ip) {
+ const hs_cache_intro_state_t *state =
+ hs_cache_client_intro_state_find(service_pk,
+ &ip->auth_key_cert->signed_key);
+ if (!state || !state->timed_out) {
+ /* No state or if this intro point has not timed out, we are done since
+ * clearly not all of them have timed out. */
+ goto end;
+ }
+ } SMARTLIST_FOREACH_END(ip);
+
+ /* Exiting the loop here means that all intro points we've looked at have
+ * timed out. Note that we can _not_ have a descriptor without intro points
+ * in the client cache. */
+ ret = true;
+
+ end:
+ return ret;
+}
+
+/** Called when a rendezvous circuit has timed out. Every stream attached to
+ * the circuit will get set with the SOCKS5_HS_REND_FAILED (0xF3) extended
+ * error code so if the connection to the rendezvous point ends up not
+ * working, this code could be sent back as a reason. */
+static void
+socks_mark_rend_circuit_timed_out(const origin_circuit_t *rend_circ)
+{
+ tor_assert(rend_circ);
+
+ /* For each entry connection attached to this rendezvous circuit, report
+ * the error. */
+ for (edge_connection_t *edge = rend_circ->p_streams; edge;
+ edge = edge->next_stream) {
+ entry_connection_t *entry = EDGE_TO_ENTRY_CONN(edge);
+ if (entry->socks_request) {
+ entry->socks_request->socks_extended_error_code =
+ SOCKS5_HS_REND_FAILED;
+ }
+ }
+}
+
+/** Called when introduction has failed meaning there is no more usable
+ * introduction points to be used (either NACKed or failed) for the given
+ * entry connection.
+ *
+ * This function only reports back the SOCKS5_HS_INTRO_FAILED (0xF2) code or
+ * SOCKS5_HS_INTRO_TIMEDOUT (0xF7) if all intros have timed out. The caller
+ * has to make sure to close the entry connections. */
+static void
+socks_mark_introduction_failed(entry_connection_t *conn,
+ const ed25519_public_key_t *identity_pk)
+{
+ socks5_reply_status_t code = SOCKS5_HS_INTRO_FAILED;
+
+ tor_assert(conn);
+ tor_assert(conn->socks_request);
+ tor_assert(identity_pk);
+
+ if (intro_points_all_timed_out(identity_pk)) {
+ code = SOCKS5_HS_INTRO_TIMEDOUT;
+ }
+ conn->socks_request->socks_extended_error_code = code;
+}
+
+/** For this introduction circuit, we'll look at if we have any usable
* introduction point left for this service. If so, we'll use the circuit to
* re-extend to a new intro point. Else, we'll close the circuit and its
* corresponding rendezvous circuit. Return 0 if we are re-extending else -1
@@ -951,8 +1071,10 @@ close_or_reextend_intro_circ(origin_circuit_t *intro_circ)
tor_assert(intro_circ);
desc = hs_cache_lookup_as_client(&intro_circ->hs_ident->identity_pk);
- if (BUG(desc == NULL)) {
- /* We can't continue without a descriptor. */
+ if (desc == NULL) {
+ /* We can't continue without a descriptor. This is possible if the cache
+ * was cleaned up between the intro point established and the reception of
+ * the introduce ack. */
goto close;
}
/* We still have the descriptor, great! Let's try to see if we can
@@ -991,7 +1113,7 @@ close_or_reextend_intro_circ(origin_circuit_t *intro_circ)
return ret;
}
-/* Called when we get an INTRODUCE_ACK success status code. Do the appropriate
+/** Called when we get an INTRODUCE_ACK success status code. Do the appropriate
* actions for the rendezvous point and finally close intro_circ. */
static void
handle_introduce_ack_success(origin_circuit_t *intro_circ)
@@ -1037,7 +1159,7 @@ handle_introduce_ack_success(origin_circuit_t *intro_circ)
return;
}
-/* Called when we get an INTRODUCE_ACK failure status code. Depending on our
+/** Called when we get an INTRODUCE_ACK failure status code. Depending on our
* failure cache status, either close the circuit or re-extend to a new
* introduction point. */
static void
@@ -1059,7 +1181,7 @@ handle_introduce_ack_bad(origin_circuit_t *circ, int status)
INTRO_POINT_FAILURE_GENERIC);
}
-/* Called when we get an INTRODUCE_ACK on the intro circuit circ. The encoded
+/** Called when we get an INTRODUCE_ACK on the intro circuit circ. The encoded
* cell is in payload of length payload_len. Return 0 on success else a
* negative value. The circuit is either close or reuse to re-extend to a new
* introduction point. */
@@ -1098,7 +1220,7 @@ handle_introduce_ack(origin_circuit_t *circ, const uint8_t *payload,
return ret;
}
-/* Called when we get a RENDEZVOUS2 cell on the rendezvous circuit circ. The
+/** Called when we get a RENDEZVOUS2 cell on the rendezvous circuit circ. The
* encoded cell is in payload of length payload_len. Return 0 on success or a
* negative value on error. On error, the circuit is marked for close. */
STATIC int
@@ -1160,7 +1282,7 @@ handle_rendezvous2(origin_circuit_t *circ, const uint8_t *payload,
return ret;
}
-/* Return true iff the client can fetch a descriptor for this service public
+/** Return true iff the client can fetch a descriptor for this service public
* identity key and status_out if not NULL is untouched. If the client can
* _not_ fetch the descriptor and if status_out is not NULL, it is set with
* the fetch status code. */
@@ -1227,7 +1349,27 @@ can_client_refetch_desc(const ed25519_public_key_t *identity_pk,
return 0;
}
-/* Return the client auth in the map using the service identity public key.
+/** Purge the client authorization cache of all ephemeral entries that is the
+ * entries that are not flagged with CLIENT_AUTH_FLAG_IS_PERMANENT.
+ *
+ * This is called from the hs_client_purge_state() used by a SIGNEWNYM. */
+STATIC void
+purge_ephemeral_client_auth(void)
+{
+ DIGEST256MAP_FOREACH_MODIFY(client_auths, key,
+ hs_client_service_authorization_t *, auth) {
+ /* Cleanup every entry that are _NOT_ permanent that is ephemeral. */
+ if (!(auth->flags & CLIENT_AUTH_FLAG_IS_PERMANENT)) {
+ MAP_DEL_CURRENT(key);
+ client_service_authorization_free(auth);
+ }
+ } DIGESTMAP_FOREACH_END;
+
+ log_info(LD_REND, "Client onion service ephemeral authorization "
+ "cache has been purged.");
+}
+
+/** Return the client auth in the map using the service identity public key.
* Return NULL if it does not exist in the map. */
static hs_client_service_authorization_t *
find_client_auth(const ed25519_public_key_t *service_identity_pk)
@@ -1240,10 +1382,565 @@ find_client_auth(const ed25519_public_key_t *service_identity_pk)
return digest256map_get(client_auths, service_identity_pk->pubkey);
}
+/** This is called when a descriptor has arrived following a fetch request and
+ * has been stored in the client cache. The given entry connections, matching
+ * the service identity key, will get attached to the service circuit. */
+static void
+client_desc_has_arrived(const smartlist_t *entry_conns)
+{
+ time_t now = time(NULL);
+
+ tor_assert(entry_conns);
+
+ SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) {
+ const hs_descriptor_t *desc;
+ edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn);
+ const ed25519_public_key_t *identity_pk =
+ &edge_conn->hs_ident->identity_pk;
+
+ /* We were just called because we stored the descriptor for this service
+ * so not finding a descriptor means we have a bigger problem. */
+ desc = hs_cache_lookup_as_client(identity_pk);
+ if (BUG(desc == NULL)) {
+ goto end;
+ }
+
+ if (!hs_client_any_intro_points_usable(identity_pk, desc)) {
+ log_info(LD_REND, "Hidden service descriptor is unusable. "
+ "Closing streams.");
+ /* Report the extended socks error code that we were unable to introduce
+ * to the service. */
+ socks_mark_introduction_failed(entry_conn, identity_pk);
+
+ connection_mark_unattached_ap(entry_conn,
+ END_STREAM_REASON_RESOLVEFAILED);
+ /* We are unable to use the descriptor so remove the directory request
+ * from the cache so the next connection can try again. */
+ note_connection_attempt_succeeded(edge_conn->hs_ident);
+ continue;
+ }
+
+ log_info(LD_REND, "Descriptor has arrived. Launching circuits.");
+
+ /* Mark connection as waiting for a circuit since we do have a usable
+ * descriptor now. */
+ mark_conn_as_waiting_for_circuit(&edge_conn->base_, now);
+ } SMARTLIST_FOREACH_END(entry_conn);
+
+ end:
+ return;
+}
+
+/** This is called when a descriptor fetch was successful but the descriptor
+ * couldn't be decrypted due to missing or bad client authorization. */
+static void
+client_desc_missing_bad_client_auth(const smartlist_t *entry_conns,
+ hs_desc_decode_status_t status)
+{
+ tor_assert(entry_conns);
+
+ SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) {
+ socks5_reply_status_t code;
+ if (status == HS_DESC_DECODE_BAD_CLIENT_AUTH) {
+ code = SOCKS5_HS_BAD_CLIENT_AUTH;
+ } else if (status == HS_DESC_DECODE_NEED_CLIENT_AUTH) {
+ code = SOCKS5_HS_MISSING_CLIENT_AUTH;
+ } else {
+ /* We should not be called with another type of status. Recover by
+ * sending a generic error. */
+ tor_assert_nonfatal_unreached();
+ code = SOCKS5_GENERAL_ERROR;
+ }
+ entry_conn->socks_request->socks_extended_error_code = code;
+ connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_MISC);
+ } SMARTLIST_FOREACH_END(entry_conn);
+}
+
+/** Called when we get a 200 directory fetch status code. */
+static void
+client_dir_fetch_200(dir_connection_t *dir_conn,
+ const smartlist_t *entry_conns, const char *body)
+{
+ hs_desc_decode_status_t decode_status;
+
+ tor_assert(dir_conn);
+ tor_assert(entry_conns);
+ tor_assert(body);
+
+ /* We got something: Try storing it in the cache. */
+ decode_status = hs_cache_store_as_client(body,
+ &dir_conn->hs_ident->identity_pk);
+ switch (decode_status) {
+ case HS_DESC_DECODE_OK:
+ case HS_DESC_DECODE_NEED_CLIENT_AUTH:
+ case HS_DESC_DECODE_BAD_CLIENT_AUTH:
+ log_info(LD_REND, "Stored hidden service descriptor successfully.");
+ TO_CONN(dir_conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC;
+ if (decode_status == HS_DESC_DECODE_OK) {
+ client_desc_has_arrived(entry_conns);
+ } else {
+ /* This handles both client auth decode status. */
+ client_desc_missing_bad_client_auth(entry_conns, decode_status);
+ log_info(LD_REND, "Stored hidden service descriptor requires "
+ "%s client authorization.",
+ decode_status == HS_DESC_DECODE_NEED_CLIENT_AUTH ? "missing"
+ : "new");
+ }
+ /* Fire control port RECEIVED event. */
+ hs_control_desc_event_received(dir_conn->hs_ident,
+ dir_conn->identity_digest);
+ hs_control_desc_event_content(dir_conn->hs_ident,
+ dir_conn->identity_digest, body);
+ break;
+ case HS_DESC_DECODE_ENCRYPTED_ERROR:
+ case HS_DESC_DECODE_SUPERENC_ERROR:
+ case HS_DESC_DECODE_PLAINTEXT_ERROR:
+ case HS_DESC_DECODE_GENERIC_ERROR:
+ default:
+ log_info(LD_REND, "Failed to store hidden service descriptor. "
+ "Descriptor decoding status: %d", decode_status);
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(dir_conn->hs_ident,
+ dir_conn->identity_digest, "BAD_DESC");
+ hs_control_desc_event_content(dir_conn->hs_ident,
+ dir_conn->identity_digest, NULL);
+ break;
+ }
+}
+
+/** Called when we get a 404 directory fetch status code. */
+static void
+client_dir_fetch_404(dir_connection_t *dir_conn,
+ const smartlist_t *entry_conns)
+{
+ tor_assert(entry_conns);
+
+ /* Not there. We'll retry when connection_about_to_close_connection() tries
+ * to clean this conn up. */
+ log_info(LD_REND, "Fetching hidden service v3 descriptor not found: "
+ "Retrying at another directory.");
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(dir_conn->hs_ident, dir_conn->identity_digest,
+ "NOT_FOUND");
+ hs_control_desc_event_content(dir_conn->hs_ident, dir_conn->identity_digest,
+ NULL);
+
+ /* Flag every entry connections that the descriptor was not found. */
+ SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) {
+ entry_conn->socks_request->socks_extended_error_code =
+ SOCKS5_HS_NOT_FOUND;
+ } SMARTLIST_FOREACH_END(entry_conn);
+}
+
+/** Called when we get a 400 directory fetch status code. */
+static void
+client_dir_fetch_400(dir_connection_t *dir_conn, const char *reason)
+{
+ tor_assert(dir_conn);
+
+ log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
+ "http status 400 (%s). Dirserver didn't like our "
+ "query? Retrying at another directory.",
+ escaped(reason));
+
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(dir_conn->hs_ident, dir_conn->identity_digest,
+ "QUERY_REJECTED");
+ hs_control_desc_event_content(dir_conn->hs_ident, dir_conn->identity_digest,
+ NULL);
+}
+
+/** Called when we get an unexpected directory fetch status code. */
+static void
+client_dir_fetch_unexpected(dir_connection_t *dir_conn, const char *reason,
+ const int status_code)
+{
+ tor_assert(dir_conn);
+
+ log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
+ "http status %d (%s) response unexpected from HSDir "
+ "server '%s:%d'. Retrying at another directory.",
+ status_code, escaped(reason), TO_CONN(dir_conn)->address,
+ TO_CONN(dir_conn)->port);
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(dir_conn->hs_ident, dir_conn->identity_digest,
+ "UNEXPECTED");
+ hs_control_desc_event_content(dir_conn->hs_ident, dir_conn->identity_digest,
+ NULL);
+}
+
+/** Get the full filename for storing the client auth credentials for the
+ * service in <b>onion_address</b>. The base directory is <b>dir</b>.
+ * This function never returns NULL. */
+static char *
+get_client_auth_creds_filename(const char *onion_address,
+ const char *dir)
+{
+ char *full_fname = NULL;
+ char *fname;
+
+ tor_asprintf(&fname, "%s.auth_private", onion_address);
+ full_fname = hs_path_from_filename(dir, fname);
+ tor_free(fname);
+
+ return full_fname;
+}
+
+/** Permanently store the credentials in <b>creds</b> to disk.
+ *
+ * Return -1 if there was an error while storing the credentials, otherwise
+ * return 0.
+ */
+static int
+store_permanent_client_auth_credentials(
+ const hs_client_service_authorization_t *creds)
+{
+ const or_options_t *options = get_options();
+ char *full_fname = NULL;
+ char *file_contents = NULL;
+ char priv_key_b32[BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)+1];
+ int retval = -1;
+
+ tor_assert(creds->flags & CLIENT_AUTH_FLAG_IS_PERMANENT);
+
+ /* We need ClientOnionAuthDir to be set, otherwise we can't proceed */
+ if (!options->ClientOnionAuthDir) {
+ log_warn(LD_GENERAL, "Can't register permanent client auth credentials "
+ "for %s without ClientOnionAuthDir option. Discarding.",
+ creds->onion_address);
+ goto err;
+ }
+
+ /* Make sure the directory exists and is private enough. */
+ if (check_private_dir(options->ClientOnionAuthDir, 0, options->User) < 0) {
+ goto err;
+ }
+
+ /* Get filename that we should store the credentials */
+ full_fname = get_client_auth_creds_filename(creds->onion_address,
+ options->ClientOnionAuthDir);
+
+ /* Encode client private key */
+ base32_encode(priv_key_b32, sizeof(priv_key_b32),
+ (char*)creds->enc_seckey.secret_key,
+ sizeof(creds->enc_seckey.secret_key));
+
+ /* Get the full file contents and write it to disk! */
+ tor_asprintf(&file_contents, "%s:descriptor:x25519:%s",
+ creds->onion_address, priv_key_b32);
+ if (write_str_to_file(full_fname, file_contents, 0) < 0) {
+ log_warn(LD_GENERAL, "Failed to write client auth creds file for %s!",
+ creds->onion_address);
+ goto err;
+ }
+
+ retval = 0;
+
+ err:
+ tor_free(file_contents);
+ tor_free(full_fname);
+
+ return retval;
+}
+
+/** Register the credential <b>creds</b> as part of the client auth subsystem.
+ *
+ * Takes ownership of <b>creds</b>.
+ **/
+hs_client_register_auth_status_t
+hs_client_register_auth_credentials(hs_client_service_authorization_t *creds)
+{
+ ed25519_public_key_t service_identity_pk;
+ hs_client_service_authorization_t *old_creds = NULL;
+ hs_client_register_auth_status_t retval = REGISTER_SUCCESS;
+
+ tor_assert(creds);
+
+ if (!client_auths) {
+ client_auths = digest256map_new();
+ }
+
+ if (hs_parse_address(creds->onion_address, &service_identity_pk,
+ NULL, NULL) < 0) {
+ client_service_authorization_free(creds);
+ return REGISTER_FAIL_BAD_ADDRESS;
+ }
+
+ /* If we reach this point, the credentials will be stored one way or another:
+ * Make them permanent if the user asked us to. */
+ if (creds->flags & CLIENT_AUTH_FLAG_IS_PERMANENT) {
+ if (store_permanent_client_auth_credentials(creds) < 0) {
+ client_service_authorization_free(creds);
+ return REGISTER_FAIL_PERMANENT_STORAGE;
+ }
+ }
+
+ old_creds = digest256map_get(client_auths, service_identity_pk.pubkey);
+ if (old_creds) {
+ digest256map_remove(client_auths, service_identity_pk.pubkey);
+ client_service_authorization_free(old_creds);
+ retval = REGISTER_SUCCESS_ALREADY_EXISTS;
+ }
+
+ digest256map_set(client_auths, service_identity_pk.pubkey, creds);
+
+ /** Now that we set the new credentials, also try to decrypt any cached
+ * descriptors. */
+ if (hs_cache_client_new_auth_parse(&service_identity_pk)) {
+ retval = REGISTER_SUCCESS_AND_DECRYPTED;
+ }
+
+ return retval;
+}
+
+/** Load a client authorization file with <b>filename</b> that is stored under
+ * the global client auth directory, and return a newly-allocated credentials
+ * object if it parsed well. Otherwise, return NULL.
+ */
+static hs_client_service_authorization_t *
+get_creds_from_client_auth_filename(const char *filename,
+ const or_options_t *options)
+{
+ hs_client_service_authorization_t *auth = NULL;
+ char *client_key_file_path = NULL;
+ char *client_key_str = NULL;
+
+ log_info(LD_REND, "Loading a client authorization key file %s...",
+ filename);
+
+ if (!auth_key_filename_is_valid(filename)) {
+ log_notice(LD_REND, "Client authorization unrecognized filename %s. "
+ "File must end in .auth_private. Ignoring.",
+ filename);
+ goto err;
+ }
+
+ /* Create a full path for a file. */
+ client_key_file_path = hs_path_from_filename(options->ClientOnionAuthDir,
+ filename);
+
+ client_key_str = read_file_to_str(client_key_file_path, 0, NULL);
+ if (!client_key_str) {
+ log_warn(LD_REND, "The file %s cannot be read.", filename);
+ goto err;
+ }
+
+ auth = parse_auth_file_content(client_key_str);
+ if (!auth) {
+ goto err;
+ }
+
+ err:
+ tor_free(client_key_str);
+ tor_free(client_key_file_path);
+
+ return auth;
+}
+
+/*
+ * Remove the file in <b>filename</b> under the global client auth credential
+ * storage.
+ */
+static void
+remove_client_auth_creds_file(const char *filename)
+{
+ char *creds_file_path = NULL;
+ const or_options_t *options = get_options();
+
+ creds_file_path = hs_path_from_filename(options->ClientOnionAuthDir,
+ filename);
+ if (tor_unlink(creds_file_path) != 0) {
+ log_warn(LD_REND, "Failed to remove client auth file (%s).",
+ creds_file_path);
+ goto end;
+ }
+
+ log_warn(LD_REND, "Successfuly removed client auth file (%s).",
+ creds_file_path);
+
+ end:
+ tor_free(creds_file_path);
+}
+
+/**
+ * Find the filesystem file corresponding to the permanent client auth
+ * credentials in <b>cred</b> and remove it.
+ */
+static void
+find_and_remove_client_auth_creds_file(
+ const hs_client_service_authorization_t *cred)
+{
+ smartlist_t *file_list = NULL;
+ const or_options_t *options = get_options();
+
+ tor_assert(cred->flags & CLIENT_AUTH_FLAG_IS_PERMANENT);
+
+ if (!options->ClientOnionAuthDir) {
+ log_warn(LD_REND, "Found permanent credential but no ClientOnionAuthDir "
+ "configured. There is no file to be removed.");
+ goto end;
+ }
+
+ file_list = tor_listdir(options->ClientOnionAuthDir);
+ if (file_list == NULL) {
+ log_warn(LD_REND, "Client authorization key directory %s can't be listed.",
+ options->ClientOnionAuthDir);
+ goto end;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(file_list, const char *, filename) {
+ hs_client_service_authorization_t *tmp_cred = NULL;
+
+ tmp_cred = get_creds_from_client_auth_filename(filename, options);
+ if (!tmp_cred) {
+ continue;
+ }
+
+ /* Find the right file for this credential */
+ if (!strcmp(tmp_cred->onion_address, cred->onion_address)) {
+ /* Found it! Remove the file! */
+ remove_client_auth_creds_file(filename);
+ /* cleanup and get out of here */
+ client_service_authorization_free(tmp_cred);
+ break;
+ }
+
+ client_service_authorization_free(tmp_cred);
+ } SMARTLIST_FOREACH_END(filename);
+
+ end:
+ if (file_list) {
+ SMARTLIST_FOREACH(file_list, char *, s, tor_free(s));
+ smartlist_free(file_list);
+ }
+}
+
+/** Remove client auth credentials for the service <b>hs_address</b>. */
+hs_client_removal_auth_status_t
+hs_client_remove_auth_credentials(const char *hsaddress)
+{
+ ed25519_public_key_t service_identity_pk;
+
+ if (!client_auths) {
+ return REMOVAL_SUCCESS_NOT_FOUND;
+ }
+
+ if (hs_parse_address(hsaddress, &service_identity_pk, NULL, NULL) < 0) {
+ return REMOVAL_BAD_ADDRESS;
+ }
+
+ hs_client_service_authorization_t *cred = NULL;
+ cred = digest256map_remove(client_auths, service_identity_pk.pubkey);
+
+ /* digestmap_remove() returns the previously stored data if there were any */
+ if (cred) {
+ if (cred->flags & CLIENT_AUTH_FLAG_IS_PERMANENT) {
+ /* These creds are stored on disk: remove the corresponding file. */
+ find_and_remove_client_auth_creds_file(cred);
+ }
+
+ /* Remove associated descriptor if any. */
+ hs_cache_remove_as_client(&service_identity_pk);
+
+ client_service_authorization_free(cred);
+ return REMOVAL_SUCCESS;
+ }
+
+ return REMOVAL_SUCCESS_NOT_FOUND;
+}
+
+/** Get the HS client auth map. */
+digest256map_t *
+get_hs_client_auths_map(void)
+{
+ return client_auths;
+}
+
/* ========== */
/* Public API */
/* ========== */
+/** Called when a circuit was just cleaned up. This is done right before the
+ * circuit is marked for close. */
+void
+hs_client_circuit_cleanup_on_close(const circuit_t *circ)
+{
+ bool has_timed_out;
+
+ tor_assert(circ);
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+
+ has_timed_out =
+ (circ->marked_for_close_orig_reason == END_CIRC_REASON_TIMEOUT);
+
+ switch (circ->purpose) {
+ case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
+ case CIRCUIT_PURPOSE_C_REND_READY:
+ case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
+ case CIRCUIT_PURPOSE_C_REND_JOINED:
+ /* Report extended SOCKS error code when a rendezvous circuit times out.
+ * This MUST be done on_close() because it is possible the entry
+ * connection would get closed before the circuit is freed and thus
+ * would fail to report the error code. */
+ if (has_timed_out) {
+ socks_mark_rend_circuit_timed_out(CONST_TO_ORIGIN_CIRCUIT(circ));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/** Called when a circuit was just cleaned up. This is done right before the
+ * circuit is freed. */
+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;
+ const origin_circuit_t *orig_circ = NULL;
+
+ tor_assert(circ);
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+
+ orig_circ = CONST_TO_ORIGIN_CIRCUIT(circ);
+ tor_assert(orig_circ->hs_ident);
+
+ has_timed_out =
+ (circ->marked_for_close_orig_reason == END_CIRC_REASON_TIMEOUT);
+ if (has_timed_out) {
+ failure = INTRO_POINT_FAILURE_TIMEOUT;
+ }
+
+ switch (circ->purpose) {
+ case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
+ log_info(LD_REND, "Failed v3 intro circ for service %s to intro point %s "
+ "(awaiting ACK). Failure code: %d",
+ safe_str_client(ed25519_fmt(&orig_circ->hs_ident->identity_pk)),
+ safe_str_client(build_state_get_exit_nickname(orig_circ->build_state)),
+ failure);
+ hs_cache_client_intro_state_note(&orig_circ->hs_ident->identity_pk,
+ &orig_circ->hs_ident->intro_auth_pk,
+ failure);
+ break;
+ case CIRCUIT_PURPOSE_C_INTRODUCING:
+ if (has_timed_out || !orig_circ->build_state) {
+ break;
+ }
+ failure = INTRO_POINT_FAILURE_UNREACHABLE;
+ log_info(LD_REND, "Failed v3 intro circ for service %s to intro point %s "
+ "(while building circuit). Marking as unreachable.",
+ safe_str_client(ed25519_fmt(&orig_circ->hs_ident->identity_pk)),
+ safe_str_client(build_state_get_exit_nickname(orig_circ->build_state)));
+ hs_cache_client_intro_state_note(&orig_circ->hs_ident->identity_pk,
+ &orig_circ->hs_ident->intro_auth_pk,
+ failure);
+ break;
+ default:
+ break;
+ }
+}
+
/** A circuit just finished connecting to a hidden service that the stream
* <b>conn</b> has been waiting for. Let the HS subsystem know about this. */
void
@@ -1265,18 +1962,20 @@ hs_client_note_connection_attempt_succeeded(const edge_connection_t *conn)
}
}
-/* With the given encoded descriptor in desc_str and the service key in
+/** With the given encoded descriptor in desc_str and the service key in
* service_identity_pk, decode the descriptor and set the desc pointer with a
* newly allocated descriptor object.
*
- * Return 0 on success else a negative value and desc is set to NULL. */
-int
+ * On success, HS_DESC_DECODE_OK is returned and desc is set to the decoded
+ * descriptor. On error, desc is set to NULL and a decoding error status is
+ * returned depending on what was the issue. */
+hs_desc_decode_status_t
hs_client_decode_descriptor(const char *desc_str,
const ed25519_public_key_t *service_identity_pk,
hs_descriptor_t **desc)
{
- int ret;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_desc_decode_status_t ret;
+ hs_subcredential_t subcredential;
ed25519_public_key_t blinded_pubkey;
hs_client_service_authorization_t *client_auth = NULL;
curve25519_secret_key_t *client_auth_sk = NULL;
@@ -1296,14 +1995,14 @@ hs_client_decode_descriptor(const char *desc_str,
uint64_t current_time_period = hs_get_time_period_num(0);
hs_build_blinded_pubkey(service_identity_pk, NULL, 0, current_time_period,
&blinded_pubkey);
- hs_get_subcredential(service_identity_pk, &blinded_pubkey, subcredential);
+ hs_get_subcredential(service_identity_pk, &blinded_pubkey, &subcredential);
}
/* Parse descriptor */
- ret = hs_desc_decode_descriptor(desc_str, subcredential,
+ ret = hs_desc_decode_descriptor(desc_str, &subcredential,
client_auth_sk, desc);
- memwipe(subcredential, 0, sizeof(subcredential));
- if (ret < 0) {
+ memwipe(&subcredential, 0, sizeof(subcredential));
+ if (ret != HS_DESC_DECODE_OK) {
goto err;
}
@@ -1316,15 +2015,16 @@ hs_client_decode_descriptor(const char *desc_str,
log_warn(LD_GENERAL, "Descriptor signing key certificate signature "
"doesn't validate with computed blinded key: %s",
tor_cert_describe_signature_status(cert));
+ ret = HS_DESC_DECODE_GENERIC_ERROR;
goto err;
}
- return 0;
+ return HS_DESC_DECODE_OK;
err:
- return -1;
+ return ret;
}
-/* Return true iff there are at least one usable intro point in the service
+/** Return true iff there are at least one usable intro point in the service
* descriptor desc. */
int
hs_client_any_intro_points_usable(const ed25519_public_key_t *service_pk,
@@ -1373,7 +2073,7 @@ hs_client_refetch_hsdesc(const ed25519_public_key_t *identity_pk)
return status;
}
-/* This is called when we are trying to attach an AP connection to these
+/** This is called when we are trying to attach an AP connection to these
* hidden service circuits from connection_ap_handshake_attach_circuit().
* Return 0 on success, -1 for a transient error that is actions were
* triggered to recover or -2 for a permenent error where both circuits will
@@ -1389,7 +2089,7 @@ hs_client_send_introduce1(origin_circuit_t *intro_circ,
rend_circ);
}
-/* Called when the client circuit circ has been established. It can be either
+/** Called when the client circuit circ has been established. It can be either
* an introduction or rendezvous circuit. This function handles all hidden
* service versions. */
void
@@ -1419,7 +2119,7 @@ hs_client_circuit_has_opened(origin_circuit_t *circ)
}
}
-/* Called when we receive a RENDEZVOUS_ESTABLISHED cell. Change the state of
+/** Called when we receive a RENDEZVOUS_ESTABLISHED cell. Change the state of
* the circuit to CIRCUIT_PURPOSE_C_REND_READY. Return 0 on success else a
* negative value and the circuit marked for close. */
int
@@ -1461,16 +2161,14 @@ hs_client_receive_rendezvous_acked(origin_circuit_t *circ,
return -1;
}
-#define client_service_authorization_free(auth) \
- FREE_AND_NULL(hs_client_service_authorization_t, \
- client_service_authorization_free_, (auth))
-
-static void
+void
client_service_authorization_free_(hs_client_service_authorization_t *auth)
{
- if (auth) {
- memwipe(auth, 0, sizeof(*auth));
+ if (!auth) {
+ return;
}
+
+ memwipe(auth, 0, sizeof(*auth));
tor_free(auth);
}
@@ -1490,7 +2188,7 @@ client_service_authorization_free_all(void)
digest256map_free(client_auths, client_service_authorization_free_void);
}
-/* Check if the auth key file name is valid or not. Return 1 if valid,
+/** Check if the auth key file name is valid or not. Return 1 if valid,
* otherwise return 0. */
STATIC int
auth_key_filename_is_valid(const char *filename)
@@ -1512,6 +2210,13 @@ auth_key_filename_is_valid(const char *filename)
return ret;
}
+/** Parse the client auth credentials off a string in <b>client_key_str</b>
+ * based on the file format documented in the "Client side configuration"
+ * section of rend-spec-v3.txt.
+ *
+ * Return NULL if there was an error, otherwise return a newly allocated
+ * hs_client_service_authorization_t structure.
+ */
STATIC hs_client_service_authorization_t *
parse_auth_file_content(const char *client_key_str)
{
@@ -1542,7 +2247,7 @@ parse_auth_file_content(const char *client_key_str)
goto err;
}
- if (strlen(seckey_b32) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) {
+ if (strlen(seckey_b32) != BASE32_NOPAD_LEN(CURVE25519_SECKEY_LEN)) {
log_warn(LD_REND, "Client authorization encoded base32 private key "
"length is invalid: %s", seckey_b32);
goto err;
@@ -1557,8 +2262,18 @@ parse_auth_file_content(const char *client_key_str)
"can't be decoded: %s", seckey_b32);
goto err;
}
+
+ if (fast_mem_is_zero((const char*)auth->enc_seckey.secret_key,
+ sizeof(auth->enc_seckey.secret_key))) {
+ log_warn(LD_REND, "Client authorization private key can't be all-zeroes");
+ goto err;
+ }
+
strncpy(auth->onion_address, onion_address, HS_SERVICE_ADDR_LEN_BASE32);
+ /* We are reading this from the disk, so set the permanent flag anyway. */
+ auth->flags |= CLIENT_AUTH_FLAG_IS_PERMANENT;
+
/* Success. */
goto done;
@@ -1575,7 +2290,7 @@ parse_auth_file_content(const char *client_key_str)
return auth;
}
-/* From a set of <b>options</b>, setup every client authorization detail
+/** From a set of <b>options</b>, setup every client authorization detail
* found. Return 0 on success or -1 on failure. If <b>validate_only</b>
* is set, parse, warn and return as normal, but don't actually change
* the configuration. */
@@ -1585,10 +2300,7 @@ hs_config_client_authorization(const or_options_t *options,
{
int ret = -1;
digest256map_t *auths = digest256map_new();
- char *key_dir = NULL;
smartlist_t *file_list = NULL;
- char *client_key_str = NULL;
- char *client_key_file_path = NULL;
tor_assert(options);
@@ -1599,82 +2311,54 @@ hs_config_client_authorization(const or_options_t *options,
goto end;
}
- key_dir = tor_strdup(options->ClientOnionAuthDir);
-
/* Make sure the directory exists and is private enough. */
- if (check_private_dir(key_dir, 0, options->User) < 0) {
+ if (check_private_dir(options->ClientOnionAuthDir, 0, options->User) < 0) {
goto end;
}
- file_list = tor_listdir(key_dir);
+ file_list = tor_listdir(options->ClientOnionAuthDir);
if (file_list == NULL) {
log_warn(LD_REND, "Client authorization key directory %s can't be listed.",
- key_dir);
+ options->ClientOnionAuthDir);
goto end;
}
- SMARTLIST_FOREACH_BEGIN(file_list, char *, filename) {
-
+ SMARTLIST_FOREACH_BEGIN(file_list, const char *, filename) {
hs_client_service_authorization_t *auth = NULL;
ed25519_public_key_t identity_pk;
- log_info(LD_REND, "Loading a client authorization key file %s...",
- filename);
- if (!auth_key_filename_is_valid(filename)) {
- log_notice(LD_REND, "Client authorization unrecognized filename %s. "
- "File must end in .auth_private. Ignoring.",
- filename);
+ auth = get_creds_from_client_auth_filename(filename, options);
+ if (!auth) {
continue;
}
- /* Create a full path for a file. */
- client_key_file_path = hs_path_from_filename(key_dir, filename);
- client_key_str = read_file_to_str(client_key_file_path, 0, NULL);
- /* Free the file path immediately after using it. */
- tor_free(client_key_file_path);
-
- /* If we cannot read the file, continue with the next file. */
- if (!client_key_str) {
- log_warn(LD_REND, "The file %s cannot be read.", filename);
+ /* Parse the onion address to get an identity public key and use it
+ * as a key of global map in the future. */
+ if (hs_parse_address(auth->onion_address, &identity_pk,
+ NULL, NULL) < 0) {
+ log_warn(LD_REND, "The onion address \"%s\" is invalid in "
+ "file %s", filename, auth->onion_address);
+ client_service_authorization_free(auth);
continue;
}
- auth = parse_auth_file_content(client_key_str);
- /* Free immediately after using it. */
- tor_free(client_key_str);
-
- if (auth) {
- /* Parse the onion address to get an identity public key and use it
- * as a key of global map in the future. */
- if (hs_parse_address(auth->onion_address, &identity_pk,
- NULL, NULL) < 0) {
- log_warn(LD_REND, "The onion address \"%s\" is invalid in "
- "file %s", filename, auth->onion_address);
- client_service_authorization_free(auth);
- continue;
- }
-
- if (digest256map_get(auths, identity_pk.pubkey)) {
+ if (digest256map_get(auths, identity_pk.pubkey)) {
log_warn(LD_REND, "Duplicate authorization for the same hidden "
- "service address %s.",
+ "service address %s.",
safe_str_client_opts(options, auth->onion_address));
client_service_authorization_free(auth);
goto end;
- }
-
- digest256map_set(auths, identity_pk.pubkey, auth);
- log_info(LD_REND, "Loaded a client authorization key file %s.",
- filename);
}
+
+ digest256map_set(auths, identity_pk.pubkey, auth);
+ log_info(LD_REND, "Loaded a client authorization key file %s.",
+ filename);
} SMARTLIST_FOREACH_END(filename);
/* Success. */
ret = 0;
end:
- tor_free(key_dir);
- tor_free(client_key_str);
- tor_free(client_key_file_path);
if (file_list) {
SMARTLIST_FOREACH(file_list, char *, s, tor_free(s));
smartlist_free(file_list);
@@ -1690,65 +2374,48 @@ hs_config_client_authorization(const or_options_t *options,
return ret;
}
-/* This is called when a descriptor has arrived following a fetch request and
- * has been stored in the client cache. Every entry connection that matches
- * the service identity key in the ident will get attached to the hidden
- * service circuit. */
+/** Called when a descriptor directory fetch is done.
+ *
+ * Act accordingly on all entry connections depending on the HTTP status code
+ * we got. In case of an error, the SOCKS error is set (if ExtendedErrors is
+ * set).
+ *
+ * The reason is a human readable string returned by the directory server
+ * which can describe the status of the request. The body is the response
+ * content, on 200 code it is the descriptor itself. Finally, the status_code
+ * is the HTTP code returned by the directory server. */
void
-hs_client_desc_has_arrived(const hs_ident_dir_conn_t *ident)
+hs_client_dir_fetch_done(dir_connection_t *dir_conn, const char *reason,
+ const char *body, const int status_code)
{
- time_t now = time(NULL);
- smartlist_t *conns = NULL;
-
- tor_assert(ident);
-
- conns = connection_list_by_type_state(CONN_TYPE_AP,
- AP_CONN_STATE_RENDDESC_WAIT);
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
- const hs_descriptor_t *desc;
- entry_connection_t *entry_conn = TO_ENTRY_CONN(base_conn);
- const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn);
+ smartlist_t *entry_conns;
- /* Only consider the entry connections that matches the service for which
- * we just fetched its descriptor. */
- if (!edge_conn->hs_ident ||
- !ed25519_pubkey_eq(&ident->identity_pk,
- &edge_conn->hs_ident->identity_pk)) {
- continue;
- }
- assert_connection_ok(base_conn, now);
+ tor_assert(dir_conn);
+ tor_assert(body);
- /* We were just called because we stored the descriptor for this service
- * so not finding a descriptor means we have a bigger problem. */
- desc = hs_cache_lookup_as_client(&ident->identity_pk);
- if (BUG(desc == NULL)) {
- goto end;
- }
+ /* Get all related entry connections. */
+ entry_conns = find_entry_conns(&dir_conn->hs_ident->identity_pk);
- if (!hs_client_any_intro_points_usable(&ident->identity_pk, desc)) {
- log_info(LD_REND, "Hidden service descriptor is unusable. "
- "Closing streams.");
- connection_mark_unattached_ap(entry_conn,
- END_STREAM_REASON_RESOLVEFAILED);
- /* We are unable to use the descriptor so remove the directory request
- * from the cache so the next connection can try again. */
- note_connection_attempt_succeeded(edge_conn->hs_ident);
- continue;
- }
-
- log_info(LD_REND, "Descriptor has arrived. Launching circuits.");
-
- /* Mark connection as waiting for a circuit since we do have a usable
- * descriptor now. */
- mark_conn_as_waiting_for_circuit(base_conn, now);
- } SMARTLIST_FOREACH_END(base_conn);
+ switch (status_code) {
+ case 200:
+ client_dir_fetch_200(dir_conn, entry_conns, body);
+ break;
+ case 404:
+ client_dir_fetch_404(dir_conn, entry_conns);
+ break;
+ case 400:
+ client_dir_fetch_400(dir_conn, reason);
+ break;
+ default:
+ client_dir_fetch_unexpected(dir_conn, reason, status_code);
+ break;
+ }
- end:
/* We don't have ownership of the objects in this list. */
- smartlist_free(conns);
+ smartlist_free(entry_conns);
}
-/* Return a newly allocated extend_info_t for a randomly chosen introduction
+/** Return a newly allocated extend_info_t for a randomly chosen introduction
* point for the given edge connection identifier ident. Return NULL if we
* can't pick any usable introduction points. */
extend_info_t *
@@ -1761,7 +2428,7 @@ hs_client_get_random_intro_from_edge(const edge_connection_t *edge_conn)
rend_client_get_random_intro(edge_conn->rend_data);
}
-/* Called when get an INTRODUCE_ACK cell on the introduction circuit circ.
+/** Called when get an INTRODUCE_ACK cell on the introduction circuit circ.
* Return 0 on success else a negative value is returned. The circuit will be
* closed or reuse to extend again to another intro point. */
int
@@ -1790,7 +2457,7 @@ hs_client_receive_introduce_ack(origin_circuit_t *circ,
return ret;
}
-/* Called when get a RENDEZVOUS2 cell on the rendezvous circuit circ. Return
+/** Called when get a RENDEZVOUS2 cell on the rendezvous circuit circ. Return
* 0 on success else a negative value is returned. The circuit will be closed
* on error. */
int
@@ -1823,7 +2490,7 @@ hs_client_receive_rendezvous2(origin_circuit_t *circ,
return ret;
}
-/* Extend the introduction circuit circ to another valid introduction point
+/** Extend the introduction circuit circ to another valid introduction point
* for the hidden service it is trying to connect to, or mark it and launch a
* new circuit if we can't extend it. Return 0 on success or possible
* success. Return -1 and mark the introduction circuit for close on permanent
@@ -1873,7 +2540,7 @@ hs_client_reextend_intro_circuit(origin_circuit_t *circ)
return ret;
}
-/* Close all client introduction circuits related to the given descriptor.
+/** Close all client introduction circuits related to the given descriptor.
* This is called with a descriptor that is about to get replaced in the
* client cache.
*
@@ -1905,7 +2572,7 @@ hs_client_close_intro_circuits_from_desc(const hs_descriptor_t *desc)
}
}
-/* Release all the storage held by the client subsystem. */
+/** Release all the storage held by the client subsystem. */
void
hs_client_free_all(void)
{
@@ -1914,7 +2581,7 @@ hs_client_free_all(void)
client_service_authorization_free_all();
}
-/* Purge all potentially remotely-detectable state held in the hidden
+/** Purge all potentially remotely-detectable state held in the hidden
* service client code. Called on SIGNAL NEWNYM. */
void
hs_client_purge_state(void)
@@ -1931,11 +2598,13 @@ hs_client_purge_state(void)
hs_cache_purge_as_client();
/* Purge the last hidden service request cache. */
hs_purge_last_hid_serv_requests();
+ /* Purge ephemeral client authorization. */
+ purge_ephemeral_client_auth();
log_info(LD_REND, "Hidden service client state has been purged.");
}
-/* Called when our directory information has changed. */
+/** Called when our directory information has changed. */
void
hs_client_dir_info_changed(void)
{
@@ -1947,10 +2616,10 @@ hs_client_dir_info_changed(void)
#ifdef TOR_UNIT_TESTS
-STATIC digest256map_t *
-get_hs_client_auths_map(void)
+STATIC void
+set_hs_client_auths_map(digest256map_t *map)
{
- return client_auths;
+ client_auths = map;
}
#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h
index 96a96755fd..a11caa309f 100644
--- a/src/feature/hs/hs_client.h
+++ b/src/feature/hs/hs_client.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,37 +10,86 @@
#define TOR_HS_CLIENT_H
#include "lib/crypt_ops/crypto_ed25519.h"
+
+#include "feature/hs/hs_circuit.h"
#include "feature/hs/hs_descriptor.h"
#include "feature/hs/hs_ident.h"
-/* Status code of a descriptor fetch request. */
+/** Status code of a descriptor fetch request. */
typedef enum {
- /* Something internally went wrong. */
+ /** Something internally went wrong. */
HS_CLIENT_FETCH_ERROR = -1,
- /* The fetch request has been launched successfully. */
+ /** The fetch request has been launched successfully. */
HS_CLIENT_FETCH_LAUNCHED = 0,
- /* We already have a usable descriptor. No fetch. */
+ /** We already have a usable descriptor. No fetch. */
HS_CLIENT_FETCH_HAVE_DESC = 1,
- /* No more HSDir available to query. */
+ /** No more HSDir available to query. */
HS_CLIENT_FETCH_NO_HSDIRS = 2,
- /* The fetch request is not allowed. */
+ /** The fetch request is not allowed. */
HS_CLIENT_FETCH_NOT_ALLOWED = 3,
- /* We are missing information to be able to launch a request. */
+ /** We are missing information to be able to launch a request. */
HS_CLIENT_FETCH_MISSING_INFO = 4,
- /* There is a pending fetch for the requested service. */
+ /** There is a pending fetch for the requested service. */
HS_CLIENT_FETCH_PENDING = 5,
} hs_client_fetch_status_t;
-/** Client-side configuration of authorization for a service. */
+/* Status code of client auth credential registration */
+typedef enum {
+ /* We successfuly registered these credentials */
+ REGISTER_SUCCESS,
+ /* We successfully registered these credentials, but had to replace some
+ * existing ones. */
+ REGISTER_SUCCESS_ALREADY_EXISTS,
+ /* We successfuly registered these credentials, and also decrypted a cached
+ * descriptor. */
+ REGISTER_SUCCESS_AND_DECRYPTED,
+ /* We failed to register these credentials, because of a bad HS address. */
+ REGISTER_FAIL_BAD_ADDRESS,
+ /* We failed to store these credentials in a persistent file on disk. */
+ REGISTER_FAIL_PERMANENT_STORAGE,
+} hs_client_register_auth_status_t;
+
+/* Status code of client auth credential removal */
+typedef enum {
+ /* We successfuly removed these credentials */
+ REMOVAL_SUCCESS,
+ /* No need to remove those credentials, because they were not there. */
+ REMOVAL_SUCCESS_NOT_FOUND,
+ /* We failed to register these credentials, because of a bad HS address. */
+ REMOVAL_BAD_ADDRESS,
+} hs_client_removal_auth_status_t;
+
+/** Flag to set when a client auth is permanent (saved on disk). */
+#define CLIENT_AUTH_FLAG_IS_PERMANENT (1<<0)
+
+/** Client-side configuration of client authorization */
typedef struct hs_client_service_authorization_t {
- /* An curve25519 secret key used to compute decryption keys that
+ /** An curve25519 secret key used to compute decryption keys that
* allow the client to decrypt the hidden service descriptor. */
curve25519_secret_key_t enc_seckey;
- /* An onion address that is used to connect to the onion service. */
+ /** An onion address that is used to connect to the onion service. */
char onion_address[HS_SERVICE_ADDR_LEN_BASE32+1];
+
+ /* Optional flags for this client. */
+ int flags;
} hs_client_service_authorization_t;
+hs_client_register_auth_status_t
+hs_client_register_auth_credentials(hs_client_service_authorization_t *creds);
+
+hs_client_removal_auth_status_t
+hs_client_remove_auth_credentials(const char *hsaddress);
+
+digest256map_t *get_hs_client_auths_map(void);
+
+#define client_service_authorization_free(auth) \
+ FREE_AND_NULL(hs_client_service_authorization_t, \
+ client_service_authorization_free_, (auth))
+
+void
+client_service_authorization_free_(hs_client_service_authorization_t *auth);
+
void hs_client_note_connection_attempt_succeeded(
const edge_connection_t *conn);
@@ -48,7 +97,7 @@ void hs_client_launch_v3_desc_fetch(
const ed25519_public_key_t *onion_identity_pk,
const smartlist_t *hsdirs);
-int hs_client_decode_descriptor(
+hs_desc_decode_status_t hs_client_decode_descriptor(
const char *desc_str,
const ed25519_public_key_t *service_identity_pk,
hs_descriptor_t **desc);
@@ -61,6 +110,8 @@ int hs_client_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ);
void hs_client_circuit_has_opened(origin_circuit_t *circ);
+void hs_client_circuit_cleanup_on_close(const circuit_t *circ);
+void hs_client_circuit_cleanup_on_free(const circuit_t *circ);
int hs_client_receive_rendezvous_acked(origin_circuit_t *circ,
const uint8_t *payload,
@@ -72,7 +123,8 @@ int hs_client_receive_rendezvous2(origin_circuit_t *circ,
const uint8_t *payload,
size_t payload_len);
-void hs_client_desc_has_arrived(const hs_ident_dir_conn_t *ident);
+void hs_client_dir_fetch_done(dir_connection_t *dir_conn, const char *reason,
+ const char *body, const int status_code);
extend_info_t *hs_client_get_random_intro_from_edge(
const edge_connection_t *edge_conn);
@@ -111,13 +163,14 @@ MOCK_DECL(STATIC hs_client_fetch_status_t,
STATIC void retry_all_socks_conn_waiting_for_desc(void);
+STATIC void purge_ephemeral_client_auth(void);
+
#ifdef TOR_UNIT_TESTS
-STATIC digest256map_t *get_hs_client_auths_map(void);
+STATIC void set_hs_client_auths_map(digest256map_t *map);
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(HS_CLIENT_PRIVATE) */
#endif /* !defined(TOR_HS_CLIENT_H) */
-
diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c
index 036d23a6b0..4639cdb68a 100644
--- a/src/feature/hs/hs_common.c
+++ b/src/feature/hs/hs_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,6 +22,7 @@
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_dos.h"
+#include "feature/hs/hs_ob.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_service.h"
#include "feature/hs_common/shared_random_client.h"
@@ -44,7 +45,7 @@
/* Trunnel */
#include "trunnel/ed25519_cert.h"
-/* Ed25519 Basepoint value. Taken from section 5 of
+/** Ed25519 Basepoint value. Taken from section 5 of
* https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03 */
static const char *str_ed25519_basepoint =
"(15112221349535400772501151409588531511"
@@ -106,7 +107,7 @@ add_unix_port(smartlist_t *ports, rend_service_port_config_t *p)
#endif /* defined(HAVE_SYS_UN_H) */
-/* Helper function: The key is a digest that we compare to a node_t object
+/** Helper function: The key is a digest that we compare to a node_t object
* current hsdir_index. */
static int
compare_digest_to_fetch_hsdir_index(const void *_key, const void **_member)
@@ -116,7 +117,7 @@ compare_digest_to_fetch_hsdir_index(const void *_key, const void **_member)
return tor_memcmp(key, node->hsdir_index.fetch, DIGEST256_LEN);
}
-/* Helper function: The key is a digest that we compare to a node_t object
+/** Helper function: The key is a digest that we compare to a node_t object
* next hsdir_index. */
static int
compare_digest_to_store_first_hsdir_index(const void *_key,
@@ -127,7 +128,7 @@ compare_digest_to_store_first_hsdir_index(const void *_key,
return tor_memcmp(key, node->hsdir_index.store_first, DIGEST256_LEN);
}
-/* Helper function: The key is a digest that we compare to a node_t object
+/** Helper function: The key is a digest that we compare to a node_t object
* next hsdir_index. */
static int
compare_digest_to_store_second_hsdir_index(const void *_key,
@@ -138,7 +139,7 @@ compare_digest_to_store_second_hsdir_index(const void *_key,
return tor_memcmp(key, node->hsdir_index.store_second, DIGEST256_LEN);
}
-/* Helper function: Compare two node_t objects current hsdir_index. */
+/** Helper function: Compare two node_t objects current hsdir_index. */
static int
compare_node_fetch_hsdir_index(const void **a, const void **b)
{
@@ -149,7 +150,7 @@ compare_node_fetch_hsdir_index(const void **a, const void **b)
DIGEST256_LEN);
}
-/* Helper function: Compare two node_t objects next hsdir_index. */
+/** Helper function: Compare two node_t objects next hsdir_index. */
static int
compare_node_store_first_hsdir_index(const void **a, const void **b)
{
@@ -160,7 +161,7 @@ compare_node_store_first_hsdir_index(const void **a, const void **b)
DIGEST256_LEN);
}
-/* Helper function: Compare two node_t objects next hsdir_index. */
+/** Helper function: Compare two node_t objects next hsdir_index. */
static int
compare_node_store_second_hsdir_index(const void **a, const void **b)
{
@@ -171,7 +172,7 @@ compare_node_store_second_hsdir_index(const void **a, const void **b)
DIGEST256_LEN);
}
-/* Allocate and return a string containing the path to filename in directory.
+/** Allocate and return a string containing the path to filename in directory.
* This function will never return NULL. The caller must free this path. */
char *
hs_path_from_filename(const char *directory, const char *filename)
@@ -185,8 +186,9 @@ hs_path_from_filename(const char *directory, const char *filename)
return file_path;
}
-/* Make sure that the directory for <b>service</b> is private, using the config
- * <b>username</b>.
+/** Make sure that the directory for <b>service</b> is private, using the
+ * config <b>username</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.
@@ -304,18 +306,18 @@ hs_get_next_time_period_num(time_t now)
return hs_get_time_period_num(now) + 1;
}
-/* Get the number of the _previous_ HS time period, given that the current time
- * is <b>now</b>. If <b>now</b> is not set, we try to get the time from a live
- * consensus. */
+/** Get the number of the _previous_ HS time period, given that the current
+ * time is <b>now</b>. If <b>now</b> is not set, we try to get the time from a
+ * live consensus. */
uint64_t
hs_get_previous_time_period_num(time_t now)
{
return hs_get_time_period_num(now) - 1;
}
-/* Return the start time of the upcoming time period based on <b>now</b>. If
- <b>now</b> is not set, we try to get the time ourselves from a live
- consensus. */
+/** Return the start time of the upcoming time period based on <b>now</b>. If
+ * <b>now</b> is not set, we try to get the time ourselves from a live
+ * consensus. */
time_t
hs_get_start_time_of_next_time_period(time_t now)
{
@@ -330,7 +332,7 @@ 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>.
+/** 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)
@@ -379,7 +381,7 @@ rend_data_free_(rend_data_t *data)
}
}
-/* Allocate and return a deep copy of <b>data</b>. */
+/** Allocate and return a deep copy of <b>data</b>. */
rend_data_t *
rend_data_dup(const rend_data_t *data)
{
@@ -409,7 +411,7 @@ rend_data_dup(const rend_data_t *data)
return data_dup;
}
-/* Compute the descriptor ID for each HS descriptor replica and save them. A
+/** 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. */
@@ -447,7 +449,7 @@ compute_desc_id(rend_data_t *rend_data)
return ret;
}
-/* Allocate and initialize a rend_data_t object for a service using the
+/** 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
@@ -479,7 +481,7 @@ rend_data_service_create(const char *onion_address, const char *pk_digest,
return rend_data;
}
-/* Allocate and initialize a rend_data_t object for a client request using the
+/** 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
@@ -520,7 +522,7 @@ rend_data_client_create(const char *onion_address, const char *desc_id,
return NULL;
}
-/* Return the onion address from the rend data. Depending on the version,
+/** 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)
@@ -536,7 +538,7 @@ rend_data_get_address(const rend_data_t *rend_data)
}
}
-/* Return the descriptor ID for a specific replica number from the rend
+/** 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. */
@@ -559,7 +561,7 @@ rend_data_get_desc_id(const rend_data_t *rend_data, uint8_t replica,
}
}
-/* Return the public key digest using the given <b>rend_data</b>. The size of
+/** 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 *
@@ -582,7 +584,7 @@ rend_data_get_pk_digest(const rend_data_t *rend_data, size_t *len_out)
}
}
-/* Using the given time period number, compute the disaster shared random
+/** 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
compute_disaster_srv(uint64_t time_period_num, uint8_t *srv_out)
@@ -670,7 +672,7 @@ get_second_cached_disaster_srv(void)
#endif /* defined(TOR_UNIT_TESTS) */
-/* When creating a blinded key, we need a parameter which construction is as
+/** When creating a blinded key, we need a parameter which construction is as
* follow: H(pubkey | [secret] | ed25519-basepoint | nonce).
*
* The nonce has a pre-defined format which uses the time period number
@@ -724,7 +726,7 @@ build_blinded_key_param(const ed25519_public_key_t *pubkey,
memwipe(nonce, 0, sizeof(nonce));
}
-/* Using an ed25519 public key and version to build the checksum of an
+/** Using an ed25519 public key and version to build the checksum of an
* address. Put in checksum_out. Format is:
* SHA3-256(".onion checksum" || PUBKEY || VERSION)
*
@@ -751,7 +753,7 @@ build_hs_checksum(const ed25519_public_key_t *key, uint8_t version,
DIGEST_SHA3_256);
}
-/* Using an ed25519 public key, checksum and version to build the binary
+/** Using an ed25519 public key, checksum and version to build the binary
* representation of a service address. Put in addr_out. Format is:
* addr_out = PUBKEY || CHECKSUM || VERSION
*
@@ -774,7 +776,7 @@ build_hs_address(const ed25519_public_key_t *key, const uint8_t *checksum,
tor_assert(offset == HS_SERVICE_ADDR_LEN);
}
-/* Helper for hs_parse_address(): Using a binary representation of a service
+/** Helper for hs_parse_address(): Using a binary 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 bytes long. address must be at least
@@ -806,13 +808,13 @@ hs_parse_address_impl(const char *address, ed25519_public_key_t *key_out,
tor_assert(offset == HS_SERVICE_ADDR_LEN);
}
-/* Using the given identity public key and a blinded public key, compute the
- * subcredential and put it in subcred_out (must be of size DIGEST256_LEN).
+/** Using the given identity public key and a blinded public key, compute the
+ * subcredential and put it in subcred_out.
* This can't fail. */
void
hs_get_subcredential(const ed25519_public_key_t *identity_pk,
const ed25519_public_key_t *blinded_pk,
- uint8_t *subcred_out)
+ hs_subcredential_t *subcred_out)
{
uint8_t credential[DIGEST256_LEN];
crypto_digest_t *digest;
@@ -840,13 +842,14 @@ hs_get_subcredential(const ed25519_public_key_t *identity_pk,
sizeof(credential));
crypto_digest_add_bytes(digest, (const char *) blinded_pk->pubkey,
ED25519_PUBKEY_LEN);
- crypto_digest_get_digest(digest, (char *) subcred_out, DIGEST256_LEN);
+ crypto_digest_get_digest(digest, (char *) subcred_out->subcred,
+ SUBCRED_LEN);
crypto_digest_free(digest);
memwipe(credential, 0, sizeof(credential));
}
-/* From the given list of hidden service ports, find the ones that match the
+/** From the given list of hidden service ports, find the ones that match the
* given edge connection conn, pick one at random and use it to set the
* connection address. Return 0 on success or -1 if none. */
int
@@ -903,35 +906,40 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn)
return (chosen_port) ? 0 : -1;
}
-/* Using a base32 representation of a service address, parse its content into
+/** 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
* bytes long.
*
- * Return 0 if parsing went well; return -1 in case of error. */
+ * Return 0 if parsing went well; return -1 in case of error and if errmsg is
+ * non NULL, a human readable string message is set. */
int
-hs_parse_address(const char *address, ed25519_public_key_t *key_out,
- uint8_t *checksum_out, uint8_t *version_out)
+hs_parse_address_no_log(const char *address, ed25519_public_key_t *key_out,
+ uint8_t *checksum_out, uint8_t *version_out,
+ const char **errmsg)
{
char decoded[HS_SERVICE_ADDR_LEN];
tor_assert(address);
+ if (errmsg) {
+ *errmsg = NULL;
+ }
+
/* Obvious length check. */
if (strlen(address) != HS_SERVICE_ADDR_LEN_BASE32) {
- log_warn(LD_REND, "Service address %s has an invalid length. "
- "Expected %lu but got %lu.",
- escaped_safe_str(address),
- (unsigned long) HS_SERVICE_ADDR_LEN_BASE32,
- (unsigned long) strlen(address));
+ if (errmsg) {
+ *errmsg = "Invalid length";
+ }
goto invalid;
}
/* Decode address so we can extract needed fields. */
if (base32_decode(decoded, sizeof(decoded), address, strlen(address))
!= sizeof(decoded)) {
- log_warn(LD_REND, "Service address %s can't be decoded.",
- escaped_safe_str(address));
+ if (errmsg) {
+ *errmsg = "Unable to base32 decode";
+ }
goto invalid;
}
@@ -943,7 +951,23 @@ hs_parse_address(const char *address, ed25519_public_key_t *key_out,
return -1;
}
-/* Validate a given onion address. The length, the base32 decoding, and
+/** Same has hs_parse_address_no_log() but emits a log warning on parsing
+ * failure. */
+int
+hs_parse_address(const char *address, ed25519_public_key_t *key_out,
+ uint8_t *checksum_out, uint8_t *version_out)
+{
+ const char *errmsg = NULL;
+ int ret = hs_parse_address_no_log(address, key_out, checksum_out,
+ version_out, &errmsg);
+ if (ret < 0) {
+ log_warn(LD_REND, "Service address %s failed to be parsed: %s",
+ escaped_safe_str(address), errmsg);
+ }
+ return ret;
+}
+
+/** Validate a given onion address. The length, the base32 decoding, and
* checksum are validated. Return 1 if valid else 0. */
int
hs_address_is_valid(const char *address)
@@ -982,7 +1006,7 @@ hs_address_is_valid(const char *address)
return 0;
}
-/* Build a service address using an ed25519 public key and a given version.
+/** Build a service address using an ed25519 public key and a given version.
* The returned address is base32 encoded and put in addr_out. The caller MUST
* make sure the addr_out is at least HS_SERVICE_ADDR_LEN_BASE32 + 1 long.
*
@@ -1012,7 +1036,7 @@ hs_build_address(const ed25519_public_key_t *key, uint8_t version,
tor_assert(hs_address_is_valid(addr_out));
}
-/* From a given ed25519 public key pk and an optional secret, compute a
+/** From a given ed25519 public key pk and an optional secret, compute a
* blinded public key and put it in blinded_pk_out. This is only useful to
* the client side because the client only has access to the identity public
* key of the service. */
@@ -1036,7 +1060,7 @@ hs_build_blinded_pubkey(const ed25519_public_key_t *pk,
memwipe(param, 0, sizeof(param));
}
-/* From a given ed25519 keypair kp and an optional secret, compute a blinded
+/** From a given ed25519 keypair kp and an optional secret, compute a blinded
* keypair for the current time period and put it in blinded_kp_out. This is
* only useful by the service side because the client doesn't have access to
* the identity secret key. */
@@ -1062,7 +1086,7 @@ hs_build_blinded_keypair(const ed25519_keypair_t *kp,
memwipe(param, 0, sizeof(param));
}
-/* Return true if we are currently in the time segment between a new time
+/** Return true if we are currently in the time segment between a new time
* period and a new SRV (in the real network that happens between 12:00 and
* 00:00 UTC). Here is a diagram showing exactly when this returns true:
*
@@ -1102,7 +1126,7 @@ hs_in_period_between_tp_and_srv,(const networkstatus_t *consensus, time_t now))
return 1;
}
-/* Return 1 if any virtual port in ports needs a circuit with good uptime.
+/** Return 1 if any virtual port in ports needs a circuit with good uptime.
* Else return 0. */
int
hs_service_requires_uptime_circ(const smartlist_t *ports)
@@ -1118,7 +1142,7 @@ hs_service_requires_uptime_circ(const smartlist_t *ports)
return 0;
}
-/* Build hs_index which is used to find the responsible hsdirs. This index
+/** Build hs_index which is used to find the responsible hsdirs. This index
* value is used to select the responsible HSDir where their hsdir_index is
* closest to this value.
* SHA3-256("store-at-idx" | blinded_public_key |
@@ -1160,7 +1184,7 @@ hs_build_hs_index(uint64_t replica, const ed25519_public_key_t *blinded_pk,
crypto_digest_free(digest);
}
-/* Build hsdir_index which is used to find the responsible hsdirs. This is the
+/** Build hsdir_index which is used to find the responsible hsdirs. This is the
* index value that is compare to the hs_index when selecting an HSDir.
* SHA3-256("node-idx" | node_identity |
* shared_random_value | INT_8(period_length) | INT_8(period_num) )
@@ -1201,7 +1225,7 @@ hs_build_hsdir_index(const ed25519_public_key_t *identity_pk,
crypto_digest_free(digest);
}
-/* Return a newly allocated buffer containing the current shared random value
+/** Return a newly allocated buffer containing the current shared random value
* or if not present, a disaster value is computed using the given time period
* number. If a consensus is provided in <b>ns</b>, use it to get the SRV
* value. This function can't fail. */
@@ -1220,7 +1244,7 @@ hs_get_current_srv(uint64_t time_period_num, const networkstatus_t *ns)
return sr_value;
}
-/* Return a newly allocated buffer containing the previous shared random
+/** Return a newly allocated buffer containing the previous shared random
* value or if not present, a disaster value is computed using the given time
* period number. This function can't fail. */
uint8_t *
@@ -1238,7 +1262,7 @@ hs_get_previous_srv(uint64_t time_period_num, const networkstatus_t *ns)
return sr_value;
}
-/* Return the number of replicas defined by a consensus parameter or the
+/** Return the number of replicas defined by a consensus parameter or the
* default value. */
int32_t
hs_get_hsdir_n_replicas(void)
@@ -1248,7 +1272,7 @@ hs_get_hsdir_n_replicas(void)
HS_DEFAULT_HSDIR_N_REPLICAS, 1, 16);
}
-/* Return the spread fetch value defined by a consensus parameter or the
+/** Return the spread fetch value defined by a consensus parameter or the
* default value. */
int32_t
hs_get_hsdir_spread_fetch(void)
@@ -1258,7 +1282,7 @@ hs_get_hsdir_spread_fetch(void)
HS_DEFAULT_HSDIR_SPREAD_FETCH, 1, 128);
}
-/* Return the spread store value defined by a consensus parameter or the
+/** Return the spread store value defined by a consensus parameter or the
* default value. */
int32_t
hs_get_hsdir_spread_store(void)
@@ -1301,7 +1325,7 @@ node_has_hsdir_index(const node_t *node)
return 1;
}
-/* For a given blinded key and time period number, get the responsible HSDir
+/** For a given blinded key and time period number, get the responsible HSDir
* and put their routerstatus_t object in the responsible_dirs list. If
* 'use_second_hsdir_index' is true, use the second hsdir_index of the node_t
* is used. If 'for_fetching' is true, the spread fetch consensus parameter is
@@ -1674,7 +1698,7 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str,
return hs_dir;
}
-/* Given a list of link specifiers lspecs, a curve 25519 onion_key, and
+/** Given a list of link specifiers lspecs, a curve 25519 onion_key, and
* a direct connection boolean direct_conn (true for single onion services),
* return a newly allocated extend_info_t object.
*
@@ -1787,7 +1811,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs,
/***********************************************************************/
-/* Initialize the entire HS subsytem. This is called in tor_init() before any
+/** Initialize the entire HS subsytem. This is called in tor_init() before any
* torrc options are loaded. Only for >= v3. */
void
hs_init(void)
@@ -1797,7 +1821,7 @@ hs_init(void)
hs_cache_init();
}
-/* Release and cleanup all memory of the HS subsystem (all version). This is
+/** Release and cleanup all memory of the HS subsystem (all version). This is
* called by tor_free_all(). */
void
hs_free_all(void)
@@ -1806,9 +1830,10 @@ hs_free_all(void)
hs_service_free_all();
hs_cache_free_all();
hs_client_free_all();
+ hs_ob_free_all();
}
-/* For the given origin circuit circ, decrement the number of rendezvous
+/** For the given origin circuit circ, decrement the number of rendezvous
* stream counter. This handles every hidden service version. */
void
hs_dec_rdv_stream_counter(origin_circuit_t *circ)
@@ -1825,7 +1850,7 @@ hs_dec_rdv_stream_counter(origin_circuit_t *circ)
}
}
-/* For the given origin circuit circ, increment the number of rendezvous
+/** For the given origin circuit circ, increment the number of rendezvous
* stream counter. This handles every hidden service version. */
void
hs_inc_rdv_stream_counter(origin_circuit_t *circ)
@@ -1842,7 +1867,7 @@ hs_inc_rdv_stream_counter(origin_circuit_t *circ)
}
}
-/* Return a newly allocated link specifier object that is a copy of dst. */
+/** Return a newly allocated link specifier object that is a copy of dst. */
link_specifier_t *
link_specifier_dup(const link_specifier_t *src)
{
diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h
index 3009780d90..997b7298a6 100644
--- a/src/feature/hs/hs_common.h
+++ b/src/feature/hs/hs_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,13 +19,14 @@ struct ed25519_keypair_t;
/* Trunnel */
#include "trunnel/ed25519_cert.h"
-/* Protocol version 2. Use this instead of hardcoding "2" in the code base,
+/** 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). */
+/** Version 3 of the protocol (prop224). */
#define HS_VERSION_THREE 3
-/* Earliest and latest version we support. */
+/** Earliest version we support. */
#define HS_VERSION_MIN HS_VERSION_TWO
+/** Latest version we support. */
#define HS_VERSION_MAX HS_VERSION_THREE
/** Try to maintain this many intro points per service by default. */
@@ -48,94 +49,95 @@ struct ed25519_keypair_t;
* rendezvous point before giving up? */
#define MAX_REND_TIMEOUT 30
-/* String prefix for the signature of ESTABLISH_INTRO */
+/** String prefix for the signature of ESTABLISH_INTRO */
#define ESTABLISH_INTRO_SIG_PREFIX "Tor establish-intro cell v1"
-/* The default HS time period length */
+/** The default HS time period length */
#define HS_TIME_PERIOD_LENGTH_DEFAULT 1440 /* 1440 minutes == one day */
-/* The minimum time period length as seen in prop224 section [TIME-PERIODS] */
+/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */
#define HS_TIME_PERIOD_LENGTH_MIN 30 /* minutes */
-/* The minimum time period length as seen in prop224 section [TIME-PERIODS] */
+/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */
#define HS_TIME_PERIOD_LENGTH_MAX (60 * 24 * 10) /* 10 days or 14400 minutes */
-/* Prefix of the onion address checksum. */
+/** Prefix of the onion address checksum. */
#define HS_SERVICE_ADDR_CHECKSUM_PREFIX ".onion checksum"
-/* Length of the checksum prefix minus the NUL terminated byte. */
+/** Length of the checksum prefix minus the NUL terminated byte. */
#define HS_SERVICE_ADDR_CHECKSUM_PREFIX_LEN \
(sizeof(HS_SERVICE_ADDR_CHECKSUM_PREFIX) - 1)
-/* Length of the resulting checksum of the address. The construction of this
+/** Length of the resulting checksum of the address. The construction of this
* checksum looks like:
* CHECKSUM = ".onion checksum" || PUBKEY || VERSION
* where VERSION is 1 byte. This is pre-hashing. */
#define HS_SERVICE_ADDR_CHECKSUM_INPUT_LEN \
(HS_SERVICE_ADDR_CHECKSUM_PREFIX_LEN + ED25519_PUBKEY_LEN + sizeof(uint8_t))
-/* The amount of bytes we use from the address checksum. */
+/** The amount of bytes we use from the address checksum. */
#define HS_SERVICE_ADDR_CHECKSUM_LEN_USED 2
-/* Length of the binary encoded service address which is of course before the
+/** Length of the binary encoded service address which is of course before the
* base32 encoding. Construction is:
* PUBKEY || CHECKSUM || VERSION
* with 1 byte VERSION and 2 bytes CHECKSUM. The following is 35 bytes. */
#define HS_SERVICE_ADDR_LEN \
(ED25519_PUBKEY_LEN + HS_SERVICE_ADDR_CHECKSUM_LEN_USED + sizeof(uint8_t))
-/* Length of 'y' portion of 'y.onion' URL. This is base32 encoded and the
+/** Length of 'y' portion of 'y.onion' URL. This is base32 encoded and the
* length ends up to 56 bytes (not counting the terminated NUL byte.) */
#define HS_SERVICE_ADDR_LEN_BASE32 \
(CEIL_DIV(HS_SERVICE_ADDR_LEN * 8, 5))
-/* The default HS time period length */
+/** The default HS time period length */
#define HS_TIME_PERIOD_LENGTH_DEFAULT 1440 /* 1440 minutes == one day */
-/* The minimum time period length as seen in prop224 section [TIME-PERIODS] */
+/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */
#define HS_TIME_PERIOD_LENGTH_MIN 30 /* minutes */
-/* The minimum time period length as seen in prop224 section [TIME-PERIODS] */
+/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */
#define HS_TIME_PERIOD_LENGTH_MAX (60 * 24 * 10) /* 10 days or 14400 minutes */
-/* The time period rotation offset as seen in prop224 section [TIME-PERIODS] */
+/** The time period rotation offset as seen in prop224 section
+ * [TIME-PERIODS] */
#define HS_TIME_PERIOD_ROTATION_OFFSET (12 * 60) /* minutes */
-/* Keyblinding parameter construction is as follow:
+/** Keyblinding parameter construction is as follow:
* "key-blind" || INT_8(period_num) || INT_8(start_period_sec) */
#define HS_KEYBLIND_NONCE_PREFIX "key-blind"
#define HS_KEYBLIND_NONCE_PREFIX_LEN (sizeof(HS_KEYBLIND_NONCE_PREFIX) - 1)
#define HS_KEYBLIND_NONCE_LEN \
(HS_KEYBLIND_NONCE_PREFIX_LEN + sizeof(uint64_t) + sizeof(uint64_t))
-/* Credential and subcredential prefix value. */
+/** Credential and subcredential prefix value. */
#define HS_CREDENTIAL_PREFIX "credential"
#define HS_CREDENTIAL_PREFIX_LEN (sizeof(HS_CREDENTIAL_PREFIX) - 1)
#define HS_SUBCREDENTIAL_PREFIX "subcredential"
#define HS_SUBCREDENTIAL_PREFIX_LEN (sizeof(HS_SUBCREDENTIAL_PREFIX) - 1)
-/* Node hidden service stored at index prefix value. */
+/** Node hidden service stored at index prefix value. */
#define HS_INDEX_PREFIX "store-at-idx"
#define HS_INDEX_PREFIX_LEN (sizeof(HS_INDEX_PREFIX) - 1)
-/* Node hidden service directory index prefix value. */
+/** Node hidden service directory index prefix value. */
#define HSDIR_INDEX_PREFIX "node-idx"
#define HSDIR_INDEX_PREFIX_LEN (sizeof(HSDIR_INDEX_PREFIX) - 1)
-/* Prefix of the shared random value disaster mode. */
+/** Prefix of the shared random value disaster mode. */
#define HS_SRV_DISASTER_PREFIX "shared-random-disaster"
#define HS_SRV_DISASTER_PREFIX_LEN (sizeof(HS_SRV_DISASTER_PREFIX) - 1)
-/* Default value of number of hsdir replicas (hsdir_n_replicas). */
+/** Default value of number of hsdir replicas (hsdir_n_replicas). */
#define HS_DEFAULT_HSDIR_N_REPLICAS 2
-/* Default value of hsdir spread store (hsdir_spread_store). */
+/** Default value of hsdir spread store (hsdir_spread_store). */
#define HS_DEFAULT_HSDIR_SPREAD_STORE 4
-/* Default value of hsdir spread fetch (hsdir_spread_fetch). */
+/** Default value of hsdir spread fetch (hsdir_spread_fetch). */
#define HS_DEFAULT_HSDIR_SPREAD_FETCH 3
-/* The size of a legacy RENDEZVOUS1 cell which adds up to 168 bytes. It is
+/** The size of a legacy RENDEZVOUS1 cell which adds up to 168 bytes. It is
* bigger than the 84 bytes needed for version 3 so we need to pad up to that
* length so it is indistinguishable between versions. */
#define HS_LEGACY_RENDEZVOUS_CELL_SIZE \
(REND_COOKIE_LEN + DH1024_KEY_LEN + DIGEST_LEN)
-/* Type of authentication key used by an introduction point. */
+/** Type of authentication key used by an introduction point. */
typedef enum {
HS_AUTH_KEY_TYPE_LEGACY = 1,
HS_AUTH_KEY_TYPE_ED25519 = 2,
} hs_auth_key_type_t;
-/* Return value when adding an ephemeral service through the ADD_ONION
+/** Return value when adding an ephemeral service through the ADD_ONION
* control port command. Both v2 and v3 share these. */
typedef enum {
RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */
@@ -146,18 +148,18 @@ typedef enum {
RSAE_OKAY = 0 /**< Service added as expected */
} hs_service_add_ephemeral_status_t;
-/* Represents the mapping from a virtual port of a rendezvous service to a
+/** 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 {
- /* The incoming HS virtual port we're mapping */
+ /** The incoming HS virtual port we're mapping */
uint16_t virtual_port;
- /* Is this an AF_UNIX port? */
+ /** Is this an AF_UNIX port? */
unsigned int is_unix_addr:1;
- /* The outgoing TCP port to use, if !is_unix_addr */
+ /** The outgoing TCP port to use, if !is_unix_addr */
uint16_t real_port;
- /* The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */
+ /** The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */
tor_addr_t real_addr;
- /* The socket path to connect to, if is_unix_addr */
+ /** The socket path to connect to, if is_unix_addr */
char unix_addr[FLEXIBLE_ARRAY_MEMBER];
} rend_service_port_config_t;
@@ -177,6 +179,10 @@ void hs_build_address(const struct ed25519_public_key_t *key, uint8_t version,
int hs_address_is_valid(const char *address);
int hs_parse_address(const char *address, struct ed25519_public_key_t *key_out,
uint8_t *checksum_out, uint8_t *version_out);
+int hs_parse_address_no_log(const char *address,
+ struct ed25519_public_key_t *key_out,
+ uint8_t *checksum_out, uint8_t *version_out,
+ const char **errmsg);
void hs_build_blinded_pubkey(const struct ed25519_public_key_t *pubkey,
const uint8_t *secret, size_t secret_len,
@@ -208,9 +214,10 @@ const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data,
routerstatus_t *pick_hsdir(const char *desc_id, const char *desc_id_base32);
+struct hs_subcredential_t;
void hs_get_subcredential(const struct ed25519_public_key_t *identity_pk,
const struct ed25519_public_key_t *blinded_pk,
- uint8_t *subcred_out);
+ struct hs_subcredential_t *subcred_out);
uint64_t hs_get_previous_time_period_num(time_t now);
uint64_t hs_get_time_period_num(time_t now);
diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c
index 3b6caaec6a..0dad8dd6d8 100644
--- a/src/feature/hs/hs_config.c
+++ b/src/feature/hs/hs_config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,18 +23,72 @@
* every option that is common to all version (config_generic_service).
**/
-#define HS_CONFIG_PRIVATE
-
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_config.h"
#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"
+
+#include "feature/hs/hs_opts_st.h"
#include "app/config/or_options_st.h"
-/* Using the given list of services, stage them into our global state. Every
+/* Declare the table mapping hs options to hs_opts_t */
+#define CONF_CONTEXT TABLE
+#include "feature/hs/hs_options.inc"
+#undef CONF_CONTEXT
+
+/** Magic number for hs_opts_t. */
+#define HS_OPTS_MAGIC 0x6f6e796e
+
+static const config_format_t hs_opts_fmt = {
+ .size = sizeof(hs_opts_t),
+ .magic = { "hs_opts_t",
+ HS_OPTS_MAGIC,
+ offsetof(hs_opts_t, magic) },
+ .vars = hs_opts_t_vars,
+};
+
+/** Global configuration manager to handle HS sections*/
+static config_mgr_t *hs_opts_mgr = NULL;
+
+/**
+ * Return a configuration manager for the hs_opts_t configuration type.
+ **/
+static const config_mgr_t *
+get_hs_opts_mgr(void)
+{
+ if (PREDICT_UNLIKELY(hs_opts_mgr == NULL)) {
+ hs_opts_mgr = config_mgr_new(&hs_opts_fmt);
+ config_mgr_freeze(hs_opts_mgr);
+ }
+ return hs_opts_mgr;
+}
+
+/**
+ * Allocate, initialize, and return a new hs_opts_t.
+ **/
+static hs_opts_t *
+hs_opts_new(void)
+{
+ const config_mgr_t *mgr = get_hs_opts_mgr();
+ hs_opts_t *r = config_new(mgr);
+ tor_assert(r);
+ config_init(mgr, r);
+ return r;
+}
+
+/**
+ * Free an hs_opts_t.
+ **/
+#define hs_opts_free(opts) \
+ config_free(get_hs_opts_mgr(), (opts))
+
+/** Using the given list of services, stage them into our global state. Every
* service version are handled. This function can remove entries in the given
* service_list.
*
@@ -70,7 +124,7 @@ stage_services(smartlist_t *service_list)
hs_service_stage_services(service_list);
}
-/* Validate the given service against all service in the given list. If the
+/** Validate the given service against all service in the given list. If the
* service is ephemeral, this function ignores it. Services with the same
* directory path aren't allowed and will return an error. If a duplicate is
* found, 1 is returned else 0 if none found. */
@@ -118,33 +172,27 @@ service_is_duplicate_in_list(const smartlist_t *service_list,
return ret;
}
-/* Helper function: Given an configuration option name, its value, a minimum
- * min and a maxium max, parse the value as a uint64_t. On success, ok is set
- * to 1 and ret is the parsed value. On error, ok is set to 0 and ret must be
- * ignored. This function logs both on error and success. */
-static uint64_t
-helper_parse_uint64(const char *opt, const char *value, uint64_t min,
- uint64_t max, int *ok)
+/** Check whether an integer <b>i</b> is out of bounds (not between <b>low</b>
+ * and <b>high</b> incusive). If it is, then log a warning about the option
+ * <b>name</b>, and return true. Otherwise return false. */
+static bool
+check_value_oob(int i, const char *name, int low, int high)
{
- uint64_t ret = 0;
-
- tor_assert(opt);
- tor_assert(value);
- tor_assert(ok);
-
- *ok = 0;
- ret = tor_parse_uint64(value, 10, min, max, ok, NULL);
- if (!*ok) {
- log_warn(LD_CONFIG, "%s must be between %" PRIu64 " and %"PRIu64
- ", not %s.",
- opt, min, max, value);
- goto err;
+ if (i < low || i > high) {
+ log_warn(LD_CONFIG, "%s must be between %d and %d, not %d.",
+ name, low, high, i);
+ return true;
}
- log_info(LD_CONFIG, "%s was parsed to %" PRIu64, opt, ret);
- err:
- return ret;
+ return false;
}
+/**
+ * Helper: check whether the integer value called <b>name</b> in <b>opts</b>
+ * is out-of-bounds.
+ **/
+#define CHECK_OOB(opts, name, low, high) \
+ check_value_oob((opts)->name, #name, (low), (high))
+
/** Helper function: Given a configuration option and its value, parse the
* value as a hs_circuit_id_protocol_t. On success, ok is set to 1 and ret is
* the parse value. On error, ok is set to 0 and the "none"
@@ -173,7 +221,7 @@ helper_parse_circuit_id_protocol(const char *key, const char *value, int *ok)
return ret;
}
-/* Return the service version by trying to learn it from the key on disk if
+/** Return the service version by trying to learn it from the key on disk if
* any. If nothing is found, the current service configured version is
* returned. */
static int
@@ -191,7 +239,13 @@ config_learn_service_version(hs_service_t *service)
return version;
}
-/* Return true iff the given options starting at line_ for a hidden service
+/**
+ * Header key indicating the start of a new hidden service configuration
+ * block.
+ **/
+static const char SECTION_HEADER[] = "HiddenServiceDir";
+
+/** Return true iff the given options starting at line_ for a hidden service
* contains at least one invalid option. Each hidden service option don't
* apply to all versions so this function can find out. The line_ MUST start
* right after the HiddenServiceDir line of this service.
@@ -221,6 +275,7 @@ config_has_invalid_options(const config_line_t *line_,
"HiddenServiceEnableIntroDoSDefense",
"HiddenServiceEnableIntroDoSRatePerSec",
"HiddenServiceEnableIntroDoSBurstPerSec",
+ "HiddenServiceOnionBalanceInstance",
NULL /* End marker. */
};
@@ -244,8 +299,11 @@ config_has_invalid_options(const config_line_t *line_,
for (int i = 0; optlist[i]; i++) {
const char *opt = optlist[i];
for (line = line_; line; line = line->next) {
- if (!strcasecmp(line->key, "HiddenServiceDir")) {
- /* We just hit the next hidden service, stop right now. */
+ if (!strcasecmp(line->key, SECTION_HEADER)) {
+ /* We just hit the next hidden service, stop right now.
+ * (This shouldn't be possible, now that we have partitioned the list
+ * into sections.) */
+ tor_assert_nonfatal_unreached();
goto end;
}
if (!strcasecmp(line->key, opt)) {
@@ -273,7 +331,7 @@ config_has_invalid_options(const config_line_t *line_,
return ret;
}
-/* Validate service configuration. This is used when loading the configuration
+/** Validate service configuration. This is used when loading the configuration
* and once we've setup a service object, it's config object is passed to this
* function for further validation. This does not validate service key
* material. Return 0 if valid else -1 if invalid. */
@@ -304,105 +362,68 @@ config_validate_service(const hs_service_config_t *config)
return -1;
}
-/* Configuration funcion for a version 3 service. The line_ must be pointing
- * to the directive directly after a HiddenServiceDir. That way, when hitting
- * the next HiddenServiceDir line or reaching the end of the list of lines, we
- * know that we have to stop looking for more options. The given service
+/** Configuration funcion for a version 3 service. The given service
* object must be already allocated and passed through
* config_generic_service() prior to calling this function.
*
* Return 0 on success else a negative value. */
static int
-config_service_v3(const config_line_t *line_,
+config_service_v3(const hs_opts_t *hs_opts,
hs_service_config_t *config)
{
- int have_num_ip = 0;
- bool export_circuit_id = false; /* just to detect duplicate options */
- bool dos_enabled = false, dos_rate_per_sec = false;
- bool dos_burst_per_sec = false;
- const char *dup_opt_seen = NULL;
- const config_line_t *line;
-
tor_assert(config);
+ tor_assert(hs_opts);
- for (line = line_; line; line = line->next) {
- int ok = 0;
- if (!strcasecmp(line->key, "HiddenServiceDir")) {
- /* We just hit the next hidden service, stop right now. */
- break;
- }
- /* Number of introduction points. */
- if (!strcasecmp(line->key, "HiddenServiceNumIntroductionPoints")) {
- config->num_intro_points =
- (unsigned int) helper_parse_uint64(line->key, line->value,
- NUM_INTRO_POINTS_DEFAULT,
- HS_CONFIG_V3_MAX_INTRO_POINTS,
- &ok);
- if (!ok || have_num_ip) {
- if (have_num_ip)
- dup_opt_seen = line->key;
- goto err;
- }
- have_num_ip = 1;
- continue;
- }
- if (!strcasecmp(line->key, "HiddenServiceExportCircuitID")) {
- config->circuit_id_protocol =
- helper_parse_circuit_id_protocol(line->key, line->value, &ok);
- if (!ok || export_circuit_id) {
- if (export_circuit_id) {
- dup_opt_seen = line->key;
- }
- goto err;
- }
- export_circuit_id = true;
- continue;
- }
- if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSDefense")) {
- config->has_dos_defense_enabled =
- (unsigned int) helper_parse_uint64(line->key, line->value,
- HS_CONFIG_V3_DOS_DEFENSE_DEFAULT,
- 1, &ok);
- if (!ok || dos_enabled) {
- if (dos_enabled) {
- dup_opt_seen = line->key;
- }
- goto err;
- }
- dos_enabled = true;
- continue;
- }
- if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSRatePerSec")) {
- config->intro_dos_rate_per_sec =
- (unsigned int) helper_parse_uint64(line->key, line->value,
- HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN,
- HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX, &ok);
- if (!ok || dos_rate_per_sec) {
- if (dos_rate_per_sec) {
- dup_opt_seen = line->key;
- }
- goto err;
- }
- dos_rate_per_sec = true;
- log_info(LD_REND, "Service INTRO2 DoS defenses rate set to: %" PRIu32,
- config->intro_dos_rate_per_sec);
- continue;
+ /* Number of introduction points. */
+ if (CHECK_OOB(hs_opts, HiddenServiceNumIntroductionPoints,
+ NUM_INTRO_POINTS_DEFAULT,
+ HS_CONFIG_V3_MAX_INTRO_POINTS)) {
+ goto err;
+ }
+ config->num_intro_points = hs_opts->HiddenServiceNumIntroductionPoints;
+
+ /* Circuit ID export setting. */
+ if (hs_opts->HiddenServiceExportCircuitID) {
+ int ok;
+ config->circuit_id_protocol =
+ helper_parse_circuit_id_protocol("HiddenServcieExportCircuitID",
+ hs_opts->HiddenServiceExportCircuitID,
+ &ok);
+ if (!ok) {
+ goto err;
}
- if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSBurstPerSec")) {
- config->intro_dos_burst_per_sec =
- (unsigned int) helper_parse_uint64(line->key, line->value,
- HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN,
- HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX, &ok);
- if (!ok || dos_burst_per_sec) {
- if (dos_burst_per_sec) {
- dup_opt_seen = line->key;
- }
- goto err;
- }
- dos_burst_per_sec = true;
- log_info(LD_REND, "Service INTRO2 DoS defenses burst set to: %" PRIu32,
- config->intro_dos_burst_per_sec);
- continue;
+ }
+
+ /* Is the DoS defense enabled? */
+ config->has_dos_defense_enabled =
+ hs_opts->HiddenServiceEnableIntroDoSDefense;
+
+ /* Rate for DoS defense */
+ if (CHECK_OOB(hs_opts, HiddenServiceEnableIntroDoSRatePerSec,
+ HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN,
+ HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX)) {
+ goto err;
+ }
+ config->intro_dos_rate_per_sec =
+ hs_opts->HiddenServiceEnableIntroDoSRatePerSec;
+ log_info(LD_REND, "Service INTRO2 DoS defenses rate set to: %" PRIu32,
+ config->intro_dos_rate_per_sec);
+
+ if (CHECK_OOB(hs_opts, HiddenServiceEnableIntroDoSBurstPerSec,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX)) {
+ goto err;
+ }
+ config->intro_dos_burst_per_sec =
+ hs_opts->HiddenServiceEnableIntroDoSBurstPerSec;
+ log_info(LD_REND, "Service INTRO2 DoS defenses burst set to: %" PRIu32,
+ config->intro_dos_burst_per_sec);
+
+ /* Is this an onionbalance instance? */
+ if (hs_opts->HiddenServiceOnionBalanceInstance) {
+ /* Option is enabled, parse config file. */
+ if (! hs_ob_parse_config_file(config)) {
+ goto err;
}
}
@@ -417,13 +438,10 @@ config_service_v3(const config_line_t *line_,
return 0;
err:
- if (dup_opt_seen) {
- log_warn(LD_CONFIG, "Duplicate directive %s.", dup_opt_seen);
- }
return -1;
}
-/* Configure a service using the given options in line_ and options. This is
+/** Configure a service using the given options in hs_opts and options. This is
* called for any service regardless of its version which means that all
* directives in this function are generic to any service version. This
* function will also check the validity of the service directory path.
@@ -435,133 +453,73 @@ config_service_v3(const config_line_t *line_,
*
* Return 0 on success else -1. */
static int
-config_generic_service(const config_line_t *line_,
+config_generic_service(const hs_opts_t *hs_opts,
const or_options_t *options,
hs_service_t *service)
{
- int dir_seen = 0;
- const config_line_t *line;
hs_service_config_t *config;
- /* If this is set, we've seen a duplicate of this option. Keep the string
- * so we can log the directive. */
- const char *dup_opt_seen = NULL;
- /* These variables will tell us if we ever have duplicate. */
- int have_version = 0, have_allow_unknown_ports = 0;
- int have_dir_group_read = 0, have_max_streams = 0;
- int have_max_streams_close = 0;
-
- tor_assert(line_);
+
+ tor_assert(hs_opts);
tor_assert(options);
tor_assert(service);
/* Makes thing easier. */
config = &service->config;
- /* The first line starts with HiddenServiceDir so we consider what's next is
- * the configuration of the service. */
- for (line = line_; line ; line = line->next) {
- int ok = 0;
-
- /* This indicate that we have a new service to configure. */
- if (!strcasecmp(line->key, "HiddenServiceDir")) {
- /* This function only configures one service at a time so if we've
- * already seen one, stop right now. */
- if (dir_seen) {
- break;
+ /* Directory where the service's keys are stored. */
+ tor_assert(hs_opts->HiddenServiceDir);
+ config->directory_path = tor_strdup(hs_opts->HiddenServiceDir);
+ log_info(LD_CONFIG, "%s=%s. Configuring...",
+ SECTION_HEADER, escaped(config->directory_path));
+
+ /* Protocol version for the service. */
+ if (hs_opts->HiddenServiceVersion == -1) {
+ /* No value was set; stay with the default. */
+ } else if (CHECK_OOB(hs_opts, HiddenServiceVersion,
+ HS_VERSION_MIN, HS_VERSION_MAX)) {
+ goto err;
+ } else {
+ config->hs_version_explicitly_set = 1;
+ config->version = hs_opts->HiddenServiceVersion;
+ }
+
+ /* Virtual port. */
+ for (const config_line_t *portline = hs_opts->HiddenServicePort;
+ 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);
+ if (!portcfg) {
+ if (err_msg) {
+ log_warn(LD_CONFIG, "%s", err_msg);
}
- /* Ok, we've seen one and we are about to configure it. */
- dir_seen = 1;
- config->directory_path = tor_strdup(line->value);
- log_info(LD_CONFIG, "HiddenServiceDir=%s. Configuring...",
- escaped(config->directory_path));
- continue;
- }
- if (BUG(!dir_seen)) {
+ tor_free(err_msg);
goto err;
}
- /* Version of the service. */
- if (!strcasecmp(line->key, "HiddenServiceVersion")) {
- service->config.version =
- (uint32_t) helper_parse_uint64(line->key, line->value, HS_VERSION_MIN,
- HS_VERSION_MAX, &ok);
- if (!ok || have_version) {
- if (have_version)
- dup_opt_seen = line->key;
- goto err;
- }
- have_version = service->config.hs_version_explicitly_set = 1;
- continue;
- }
- /* Virtual port. */
- if (!strcasecmp(line->key, "HiddenServicePort")) {
- char *err_msg = NULL;
- /* XXX: Can we rename this? */
- rend_service_port_config_t *portcfg =
- rend_service_parse_port_config(line->value, " ", &err_msg);
- if (!portcfg) {
- if (err_msg) {
- log_warn(LD_CONFIG, "%s", err_msg);
- }
- tor_free(err_msg);
- goto err;
- }
- tor_assert(!err_msg);
- smartlist_add(config->ports, portcfg);
- log_info(LD_CONFIG, "HiddenServicePort=%s for %s",
- line->value, escaped(config->directory_path));
- continue;
- }
- /* Do we allow unknown ports. */
- if (!strcasecmp(line->key, "HiddenServiceAllowUnknownPorts")) {
- config->allow_unknown_ports =
- (unsigned int) helper_parse_uint64(line->key, line->value, 0, 1, &ok);
- if (!ok || have_allow_unknown_ports) {
- if (have_allow_unknown_ports)
- dup_opt_seen = line->key;
- goto err;
- }
- have_allow_unknown_ports = 1;
- continue;
- }
- /* Directory group readable. */
- if (!strcasecmp(line->key, "HiddenServiceDirGroupReadable")) {
- config->dir_group_readable =
- (unsigned int) helper_parse_uint64(line->key, line->value, 0, 1, &ok);
- if (!ok || have_dir_group_read) {
- if (have_dir_group_read)
- dup_opt_seen = line->key;
- goto err;
- }
- have_dir_group_read = 1;
- continue;
- }
- /* Maximum streams per circuit. */
- if (!strcasecmp(line->key, "HiddenServiceMaxStreams")) {
- config->max_streams_per_rdv_circuit =
- helper_parse_uint64(line->key, line->value, 0,
- HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT, &ok);
- if (!ok || have_max_streams) {
- if (have_max_streams)
- dup_opt_seen = line->key;
- goto err;
- }
- have_max_streams = 1;
- continue;
- }
- /* Maximum amount of streams before we close the circuit. */
- if (!strcasecmp(line->key, "HiddenServiceMaxStreamsCloseCircuit")) {
- config->max_streams_close_circuit =
- (unsigned int) helper_parse_uint64(line->key, line->value, 0, 1, &ok);
- if (!ok || have_max_streams_close) {
- if (have_max_streams_close)
- dup_opt_seen = line->key;
- goto err;
- }
- have_max_streams_close = 1;
- continue;
- }
+ tor_assert(!err_msg);
+ smartlist_add(config->ports, portcfg);
+ log_info(LD_CONFIG, "HiddenServicePort=%s for %s",
+ portline->value, escaped(config->directory_path));
}
+ /* Do we allow unknown ports? */
+ config->allow_unknown_ports = hs_opts->HiddenServiceAllowUnknownPorts;
+
+ /* Directory group readable. */
+ config->dir_group_readable = hs_opts->HiddenServiceDirGroupReadable;
+
+ /* Maximum streams per circuit. */
+ if (CHECK_OOB(hs_opts, HiddenServiceMaxStreams,
+ 0, HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT)) {
+ goto err;
+ }
+ config->max_streams_per_rdv_circuit = hs_opts->HiddenServiceMaxStreams;
+
+ /* Maximum amount of streams before we close the circuit. */
+ config->max_streams_close_circuit =
+ hs_opts->HiddenServiceMaxStreamsCloseCircuit;
+
/* 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)) {
@@ -571,23 +529,22 @@ config_generic_service(const config_line_t *line_,
/* Success */
return 0;
err:
- if (dup_opt_seen) {
- log_warn(LD_CONFIG, "Duplicate directive %s.", dup_opt_seen);
- }
return -1;
}
-/* Configure a service using the given line and options. This function will
+/** Configure a service using the given line and options. This function will
* call the corresponding configuration function for a specific service
* version and validate the service against the other ones. On success, add
* the service to the given list and return 0. On error, nothing is added to
* the list and a negative value is returned. */
static int
-config_service(const config_line_t *line, const or_options_t *options,
+config_service(config_line_t *line, const or_options_t *options,
smartlist_t *service_list)
{
int ret;
hs_service_t *service = NULL;
+ hs_opts_t *hs_opts = NULL;
+ char *msg = NULL;
tor_assert(line);
tor_assert(options);
@@ -596,9 +553,25 @@ config_service(const config_line_t *line, const or_options_t *options,
/* We have a new hidden service. */
service = hs_service_new(options);
+ /* Try to validate and parse the configuration lines into 'hs_opts' */
+ hs_opts = hs_opts_new();
+ ret = config_assign(get_hs_opts_mgr(), hs_opts, line, 0, &msg);
+ if (ret < 0) {
+ log_warn(LD_REND, "Can't parse configuration for onion service: %s", msg);
+ goto err;
+ }
+ tor_assert_nonfatal(msg == NULL);
+ validation_status_t vs = config_validate(get_hs_opts_mgr(), NULL,
+ hs_opts, &msg);
+ if (vs < 0) {
+ log_warn(LD_REND, "Bad configuration for onion service: %s", msg);
+ goto err;
+ }
+ tor_assert_nonfatal(msg == NULL);
+
/* We'll configure that service as a generic one and then pass it to a
* specific function according to the configured version number. */
- if (config_generic_service(line, options, service) < 0) {
+ if (config_generic_service(hs_opts, options, service) < 0) {
goto err;
}
@@ -633,10 +606,10 @@ config_service(const config_line_t *line, const or_options_t *options,
* directory line, the function knows that it has to stop parsing. */
switch (service->config.version) {
case HS_VERSION_TWO:
- ret = rend_config_service(line->next, options, &service->config);
+ ret = rend_config_service(hs_opts, options, &service->config);
break;
case HS_VERSION_THREE:
- ret = config_service_v3(line->next, &service->config);
+ ret = config_service_v3(hs_opts, &service->config);
break;
default:
/* We do validate before if we support the parsed version. */
@@ -655,22 +628,25 @@ config_service(const config_line_t *line, const or_options_t *options,
/* Passes, add it to the given list. */
smartlist_add(service_list, service);
+ hs_opts_free(hs_opts);
return 0;
err:
hs_service_free(service);
+ hs_opts_free(hs_opts);
+ tor_free(msg);
return -1;
}
-/* From a set of <b>options</b>, setup every hidden service found. Return 0 on
+/** From a set of <b>options</b>, setup every hidden service found. Return 0 on
* success or -1 on failure. If <b>validate_only</b> is set, parse, warn and
* return as normal, but don't actually change the configured services. */
int
hs_config_service_all(const or_options_t *options, int validate_only)
{
- int dir_option_seen = 0, ret = -1;
- const config_line_t *line;
+ int ret = -1;
+ config_line_t *remaining = NULL;
smartlist_t *new_service_list = NULL;
tor_assert(options);
@@ -679,23 +655,24 @@ hs_config_service_all(const or_options_t *options, int validate_only)
* validation and staging for >= v3. */
new_service_list = smartlist_new();
- for (line = options->RendConfigLines; line; line = line->next) {
- /* Ignore all directives that aren't the start of a service. */
- if (strcasecmp(line->key, "HiddenServiceDir")) {
- if (!dir_option_seen) {
- log_warn(LD_CONFIG, "%s with no preceding HiddenServiceDir directive",
- line->key);
- goto err;
- }
- continue;
- }
- /* Flag that we've seen a directory directive and we'll use it to make
- * sure that the torrc options ordering is actually valid. */
- dir_option_seen = 1;
+ /* We need to start with a HiddenServiceDir line */
+ if (options->RendConfigLines &&
+ strcasecmp(options->RendConfigLines->key, SECTION_HEADER)) {
+ log_warn(LD_CONFIG, "%s with no preceding %s directive",
+ options->RendConfigLines->key, SECTION_HEADER);
+ goto err;
+ }
+
+ remaining = config_lines_dup(options->RendConfigLines);
+ while (remaining) {
+ config_line_t *section = remaining;
+ remaining = config_lines_partition(section, SECTION_HEADER);
/* Try to configure this service now. On success, it will be added to the
* list and validated against the service in that same list. */
- if (config_service(line, options, new_service_list) < 0) {
+ int rv = config_service(section, options, new_service_list);
+ config_free_lines(section);
+ if (rv < 0) {
goto err;
}
}
@@ -731,7 +708,7 @@ hs_config_service_all(const or_options_t *options, int validate_only)
return ret;
}
-/* From a set of <b>options</b>, setup every client authorization found.
+/** From a set of <b>options</b>, setup every client authorization found.
* Return 0 on success or -1 on failure. If <b>validate_only</b> is set,
* parse, warn and return as normal, but don't actually change the
* configured state. */
@@ -755,3 +732,12 @@ hs_config_client_auth_all(const or_options_t *options, int validate_only)
done:
return ret;
}
+
+/**
+ * Free all resources held by the hs_config.c module.
+ **/
+void
+hs_config_free_all(void)
+{
+ config_mgr_free(hs_opts_mgr);
+}
diff --git a/src/feature/hs/hs_config.h b/src/feature/hs/hs_config.h
index beefc7a613..c60b4fbb5d 100644
--- a/src/feature/hs/hs_config.h
+++ b/src/feature/hs/hs_config.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -30,5 +30,6 @@
int hs_config_service_all(const or_options_t *options, int validate_only);
int hs_config_client_auth_all(const or_options_t *options, int validate_only);
-#endif /* !defined(TOR_HS_CONFIG_H) */
+void hs_config_free_all(void);
+#endif /* !defined(TOR_HS_CONFIG_H) */
diff --git a/src/feature/hs/hs_control.c b/src/feature/hs/hs_control.c
index abb421345c..78b0735c29 100644
--- a/src/feature/hs/hs_control.c
+++ b/src/feature/hs/hs_control.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,7 +20,7 @@
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerstatus_st.h"
-/* Send on the control port the "HS_DESC REQUESTED [...]" event.
+/** Send on the control port the "HS_DESC REQUESTED [...]" event.
*
* The onion_pk is the onion service public key, base64_blinded_pk is the
* base64 encoded blinded key for the service and hsdir_rs is the routerstatus
@@ -57,7 +57,7 @@ hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk,
memwipe(onion_address, 0, sizeof(onion_address));
}
-/* Send on the control port the "HS_DESC FAILED [...]" event.
+/** Send on the control port the "HS_DESC FAILED [...]" event.
*
* Using a directory connection identifier, the HSDir identity digest and a
* reason for the failure. None can be NULL. */
@@ -81,7 +81,7 @@ hs_control_desc_event_failed(const hs_ident_dir_conn_t *ident,
hsdir_id_digest, reason);
}
-/* Send on the control port the "HS_DESC RECEIVED [...]" event.
+/** Send on the control port the "HS_DESC RECEIVED [...]" event.
*
* Using a directory connection identifier and the HSDir identity digest.
* None can be NULL. */
@@ -103,7 +103,7 @@ hs_control_desc_event_received(const hs_ident_dir_conn_t *ident,
hsdir_id_digest);
}
-/* Send on the control port the "HS_DESC CREATED [...]" event.
+/** Send on the control port the "HS_DESC CREATED [...]" event.
*
* Using the onion address of the descriptor's service and the blinded public
* key of the descriptor as a descriptor ID. None can be NULL. */
@@ -124,7 +124,7 @@ hs_control_desc_event_created(const char *onion_address,
control_event_hs_descriptor_created(onion_address, base64_blinded_pk, -1);
}
-/* Send on the control port the "HS_DESC UPLOAD [...]" event.
+/** Send on the control port the "HS_DESC UPLOAD [...]" event.
*
* Using the onion address of the descriptor's service, the HSDir identity
* digest, the blinded public key of the descriptor as a descriptor ID and the
@@ -151,7 +151,7 @@ hs_control_desc_event_upload(const char *onion_address,
DIGEST256_LEN));
}
-/* Send on the control port the "HS_DESC UPLOADED [...]" event.
+/** Send on the control port the "HS_DESC UPLOADED [...]" event.
*
* Using the directory connection identifier and the HSDir identity digest.
* None can be NULL. */
@@ -169,7 +169,7 @@ hs_control_desc_event_uploaded(const hs_ident_dir_conn_t *ident,
control_event_hs_descriptor_uploaded(hsdir_id_digest, onion_address);
}
-/* Send on the control port the "HS_DESC_CONTENT [...]" event.
+/** Send on the control port the "HS_DESC_CONTENT [...]" event.
*
* Using the directory connection identifier, the HSDir identity digest and
* the body of the descriptor (as it was received from the directory). None
@@ -193,7 +193,7 @@ hs_control_desc_event_content(const hs_ident_dir_conn_t *ident,
hsdir_id_digest, body);
}
-/* Handle the "HSPOST [...]" command. The body is an encoded descriptor for
+/** Handle the "HSPOST [...]" command. The body is an encoded descriptor for
* the given onion_address. The descriptor will be uploaded to each directory
* in hsdirs_rs. If NULL, the responsible directories for the current time
* period will be selected.
@@ -248,7 +248,7 @@ hs_control_hspost_command(const char *body, const char *onion_address,
return ret;
}
-/* With a given <b>onion_identity_pk</b>, fetch its descriptor, optionally
+/** With a given <b>onion_identity_pk</b>, fetch its descriptor, optionally
* using the list of directory servers given in <b>hsdirs</b>, or a random
* server if it is NULL. This function calls hs_client_launch_v3_desc_fetch().
*/
diff --git a/src/feature/hs/hs_control.h b/src/feature/hs/hs_control.h
index b55e4c53c9..947b0ebf1c 100644
--- a/src/feature/hs/hs_control.h
+++ b/src/feature/hs/hs_control.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, 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 924ab3115e..50a46fb40f 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -56,6 +56,7 @@
#define HS_DESCRIPTOR_PRIVATE
#include "core/or/or.h"
+#include "app/config/config.h"
#include "trunnel/ed25519_cert.h" /* Trunnel interface. */
#include "feature/hs/hs_descriptor.h"
#include "core/or/circuitbuild.h"
@@ -102,7 +103,7 @@
#define str_desc_auth_client "auth-client"
#define str_encrypted "encrypted"
-/* Authentication supported types. */
+/** Authentication supported types. */
static const struct {
hs_desc_auth_type_t type;
const char *identifier;
@@ -112,7 +113,7 @@ static const struct {
{ 0, NULL }
};
-/* Descriptor ruleset. */
+/** Descriptor ruleset. */
static token_rule_t hs_desc_v3_token_table[] = {
T1_START(str_hs_desc, R_HS_DESCRIPTOR, EQ(1), NO_OBJ),
T1(str_lifetime, R3_DESC_LIFETIME, EQ(1), NO_OBJ),
@@ -123,7 +124,7 @@ static token_rule_t hs_desc_v3_token_table[] = {
END_OF_TABLE
};
-/* Descriptor ruleset for the superencrypted section. */
+/** Descriptor ruleset for the superencrypted section. */
static token_rule_t hs_desc_superencrypted_v3_token_table[] = {
T1_START(str_desc_auth_type, R3_DESC_AUTH_TYPE, GE(1), NO_OBJ),
T1(str_desc_auth_key, R3_DESC_AUTH_KEY, GE(1), NO_OBJ),
@@ -132,7 +133,7 @@ static token_rule_t hs_desc_superencrypted_v3_token_table[] = {
END_OF_TABLE
};
-/* Descriptor ruleset for the encrypted section. */
+/** Descriptor ruleset for the encrypted section. */
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, ARGS, NO_OBJ),
@@ -140,7 +141,7 @@ static token_rule_t hs_desc_encrypted_v3_token_table[] = {
END_OF_TABLE
};
-/* Descriptor ruleset for the introduction points section. */
+/** Descriptor ruleset for the introduction points section. */
static token_rule_t hs_desc_intro_point_v3_token_table[] = {
T1_START(str_intro_point, R3_INTRODUCTION_POINT, EQ(1), NO_OBJ),
T1N(str_ip_onion_key, R3_INTRO_ONION_KEY, GE(2), OBJ_OK),
@@ -152,7 +153,7 @@ static token_rule_t hs_desc_intro_point_v3_token_table[] = {
END_OF_TABLE
};
-/* Using a key, salt and encrypted payload, build a MAC and put it in mac_out.
+/** Using a key, salt and encrypted payload, build a MAC and put it in mac_out.
* We use SHA3-256 for the MAC computation.
* This function can't fail. */
static void
@@ -184,7 +185,7 @@ build_mac(const uint8_t *mac_key, size_t mac_key_len,
crypto_digest_free(digest);
}
-/* Using a secret data and a given decriptor object, build the secret
+/** Using a secret data and a given decriptor object, build the secret
* input needed for the KDF.
*
* secret_input = SECRET_DATA | subcredential | INT_8(revision_counter)
@@ -211,7 +212,7 @@ build_secret_input(const hs_descriptor_t *desc,
memcpy(secret_input, secret_data, secret_data_len);
offset += secret_data_len;
/* Copy subcredential. */
- memcpy(secret_input + offset, desc->subcredential, DIGEST256_LEN);
+ memcpy(secret_input + offset, desc->subcredential.subcred, DIGEST256_LEN);
offset += DIGEST256_LEN;
/* Copy revision counter value. */
set_uint64(secret_input + offset,
@@ -224,7 +225,7 @@ build_secret_input(const hs_descriptor_t *desc,
return secret_input_len;
}
-/* Do the KDF construction and put the resulting data in key_out which is of
+/** Do the KDF construction and put the resulting data in key_out which is of
* key_out_len length. It uses SHAKE-256 as specified in the spec. */
static void
build_kdf_key(const hs_descriptor_t *desc,
@@ -269,7 +270,7 @@ build_kdf_key(const hs_descriptor_t *desc,
tor_free(secret_input);
}
-/* Using the given descriptor, secret data, and salt, run it through our
+/** Using the given descriptor, secret data, and salt, run it through our
* KDF function and then extract a secret key in key_out, the IV in iv_out
* and MAC in mac_out. This function can't fail. */
static void
@@ -308,7 +309,7 @@ build_secret_key_iv_mac(const hs_descriptor_t *desc,
/* === ENCODING === */
-/* Encode the given link specifier objects into a newly allocated string.
+/** Encode the given link specifier objects into a newly allocated string.
* This can't fail so caller can always assume a valid string being
* returned. */
STATIC char *
@@ -355,7 +356,7 @@ encode_link_specifiers(const smartlist_t *specs)
return encoded_b64;
}
-/* Encode an introduction point legacy key and certificate. Return a newly
+/** Encode an introduction point legacy key and certificate. Return a newly
* allocated string with it. On failure, return NULL. */
static char *
encode_legacy_key(const hs_desc_intro_point_t *ip)
@@ -392,7 +393,7 @@ encode_legacy_key(const hs_desc_intro_point_t *ip)
return encoded;
}
-/* Encode an introduction point encryption key and certificate. Return a newly
+/** Encode an introduction point encryption key and certificate. Return a newly
* allocated string with it. On failure, return NULL. */
static char *
encode_enc_key(const hs_desc_intro_point_t *ip)
@@ -418,7 +419,7 @@ encode_enc_key(const hs_desc_intro_point_t *ip)
return encoded;
}
-/* Encode an introduction point onion key. Return a newly allocated string
+/** Encode an introduction point onion key. Return a newly allocated string
* with it. Can not fail. */
static char *
encode_onion_key(const hs_desc_intro_point_t *ip)
@@ -435,7 +436,7 @@ encode_onion_key(const hs_desc_intro_point_t *ip)
return encoded;
}
-/* Encode an introduction point object and return a newly allocated string
+/** Encode an introduction point object and return a newly allocated string
* with it. On failure, return NULL. */
static char *
encode_intro_point(const ed25519_public_key_t *sig_key,
@@ -505,7 +506,7 @@ encode_intro_point(const ed25519_public_key_t *sig_key,
return encoded_ip;
}
-/* Given a source length, return the new size including padding for the
+/** Given a source length, return the new size including padding for the
* plaintext encryption. */
static size_t
compute_padded_plaintext_length(size_t plaintext_len)
@@ -525,7 +526,7 @@ compute_padded_plaintext_length(size_t plaintext_len)
return plaintext_padded_len;
}
-/* Given a buffer, pad it up to the encrypted section padding requirement. Set
+/** Given a buffer, pad it up to the encrypted section padding requirement. Set
* the newly allocated string in padded_out and return the length of the
* padded buffer. */
STATIC size_t
@@ -548,7 +549,7 @@ build_plaintext_padding(const char *plaintext, size_t plaintext_len,
return padded_len;
}
-/* Using a key, IV and plaintext data of length plaintext_len, create the
+/** Using a key, IV and plaintext data of length plaintext_len, create the
* encrypted section by encrypting it and setting encrypted_out with the
* data. Return size of the encrypted data buffer. */
static size_t
@@ -593,7 +594,7 @@ build_encrypted(const uint8_t *key, const uint8_t *iv, const char *plaintext,
return encrypted_len;
}
-/* Encrypt the given <b>plaintext</b> buffer using <b>desc</b> and
+/** Encrypt the given <b>plaintext</b> buffer using <b>desc</b> and
* <b>secret_data</b> to get the keys. Set encrypted_out with the encrypted
* data and return the length of it. <b>is_superencrypted_layer</b> is set
* if this is the outer encrypted layer of the descriptor. */
@@ -663,7 +664,7 @@ encrypt_descriptor_data(const hs_descriptor_t *desc,
return final_blob_len;
}
-/* Create and return a string containing a client-auth entry. It's the
+/** Create and return a string containing a client-auth entry. It's the
* responsibility of the caller to free the returned string. This function
* will never fail. */
static char *
@@ -733,7 +734,7 @@ get_all_auth_client_lines(const hs_descriptor_t *desc)
return auth_client_lines_str;
}
-/* Create the inner layer of the descriptor (which includes the intro points,
+/** Create the inner layer of the descriptor (which includes the intro points,
* etc.). Return a newly-allocated string with the layer plaintext, or NULL if
* an error occurred. It's the responsibility of the caller to free the
* returned string. */
@@ -789,7 +790,7 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc)
return encoded_str;
}
-/* Create the middle layer of the descriptor, which includes the client auth
+/** Create the middle layer of the descriptor, which includes the client auth
* data and the encrypted inner layer (provided as a base64 string at
* <b>layer2_b64_ciphertext</b>). Return a newly-allocated string with the
* layer plaintext. It's the responsibility of the caller to free the returned
@@ -845,7 +846,7 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc,
return layer1_str;
}
-/* Encrypt <b>encoded_str</b> into an encrypted blob and then base64 it before
+/** Encrypt <b>encoded_str</b> into an encrypted blob and then base64 it before
* returning it. <b>desc</b> is provided to derive the encryption
* keys. <b>secret_data</b> is also proved to derive the encryption keys.
* <b>is_superencrypted_layer</b> is set if <b>encoded_str</b> is the
@@ -878,7 +879,7 @@ encrypt_desc_data_and_base64(const hs_descriptor_t *desc,
return enc_b64;
}
-/* Generate the secret data which is used to encrypt/decrypt the descriptor.
+/** Generate the secret data which is used to encrypt/decrypt the descriptor.
*
* SECRET_DATA = blinded-public-key
* SECRET_DATA = blinded-public-key | descriptor_cookie
@@ -925,7 +926,7 @@ build_secret_data(const ed25519_public_key_t *blinded_pubkey,
return secret_data_len;
}
-/* Generate and encode the superencrypted portion of <b>desc</b>. This also
+/** Generate and encode the superencrypted portion of <b>desc</b>. This also
* involves generating the encrypted portion of the descriptor, and performing
* the superencryption. A newly allocated NUL-terminated string pointer
* containing the encrypted encoded blob is put in encrypted_blob_out. Return 0
@@ -999,7 +1000,7 @@ encode_superencrypted_data(const hs_descriptor_t *desc,
return ret;
}
-/* Encode a v3 HS descriptor. Return 0 on success and set encoded_out to the
+/** Encode a v3 HS descriptor. Return 0 on success and set encoded_out to the
* newly allocated string of the encoded descriptor. On error, -1 is returned
* and encoded_out is untouched. */
static int
@@ -1018,10 +1019,6 @@ desc_encode_v3(const hs_descriptor_t *desc,
tor_assert(encoded_out);
tor_assert(desc->plaintext_data.version == 3);
- if (BUG(desc->subcredential == NULL)) {
- goto err;
- }
-
/* Build the non-encrypted values. */
{
char *encoded_cert;
@@ -1111,7 +1108,7 @@ desc_encode_v3(const hs_descriptor_t *desc,
/* === DECODING === */
-/* Given the token tok for an auth client, decode it as
+/** Given the token tok for an auth client, decode it as
* hs_desc_authorized_client_t. tok->args MUST contain at least 3 elements
* Return 0 on success else -1 on failure. */
static int
@@ -1147,7 +1144,7 @@ decode_auth_client(const directory_token_t *tok,
return ret;
}
-/* Given an encoded string of the link specifiers, return a newly allocated
+/** Given an encoded string of the link specifiers, return a newly allocated
* list of decoded link specifiers. Return NULL on error. */
STATIC smartlist_t *
decode_link_specifiers(const char *encoded)
@@ -1201,7 +1198,7 @@ decode_link_specifiers(const char *encoded)
return results;
}
-/* Given a list of authentication types, decode it and put it in the encrypted
+/** Given a list of authentication types, decode it and put it in the encrypted
* data section. Return 1 if we at least know one of the type or 0 if we know
* none of them. */
static int
@@ -1229,7 +1226,7 @@ decode_auth_type(hs_desc_encrypted_data_t *desc, const char *list)
return match;
}
-/* Parse a space-delimited list of integers representing CREATE2 formats into
+/** Parse a space-delimited list of integers representing CREATE2 formats into
* the bitfield in hs_desc_encrypted_data_t. Ignore unrecognized values. */
static void
decode_create2_list(hs_desc_encrypted_data_t *desc, const char *list)
@@ -1263,7 +1260,7 @@ decode_create2_list(hs_desc_encrypted_data_t *desc, const char *list)
smartlist_free(tokens);
}
-/* Given a certificate, validate the certificate for certain conditions which
+/** Given a certificate, validate the certificate for certain conditions which
* are if the given type matches the cert's one, if the signing key is
* included and if the that key was actually used to sign the certificate.
*
@@ -1287,11 +1284,20 @@ cert_is_valid(tor_cert_t *cert, uint8_t type, const char *log_obj_type)
log_warn(LD_REND, "Signing key is NOT included for %s.", log_obj_type);
goto err;
}
+
/* The following will not only check if the signature matches but also the
* expiration date and overall validity. */
if (tor_cert_checksig(cert, &cert->signing_key, approx_time()) < 0) {
- log_warn(LD_REND, "Invalid signature for %s: %s", log_obj_type,
- tor_cert_describe_signature_status(cert));
+ if (cert->cert_expired) {
+ char expiration_str[ISO_TIME_LEN+1];
+ format_iso_time(expiration_str, cert->valid_until);
+ log_fn(LOG_PROTOCOL_WARN, LD_REND, "Invalid signature for %s: %s (%s)",
+ log_obj_type, tor_cert_describe_signature_status(cert),
+ expiration_str);
+ } else {
+ log_warn(LD_REND, "Invalid signature for %s: %s",
+ log_obj_type, tor_cert_describe_signature_status(cert));
+ }
goto err;
}
@@ -1300,7 +1306,7 @@ cert_is_valid(tor_cert_t *cert, uint8_t type, const char *log_obj_type)
return 0;
}
-/* Given some binary data, try to parse it to get a certificate object. If we
+/** Given some binary data, try to parse it to get a certificate object. If we
* have a valid cert, validate it using the given wanted type. On error, print
* a log using the err_msg has the certificate identifier adding semantic to
* the log and cert_out is set to NULL. On success, 0 is returned and cert_out
@@ -1337,7 +1343,7 @@ cert_parse_and_validate(tor_cert_t **cert_out, const char *data,
return -1;
}
-/* Return true iff the given length of the encrypted data of a descriptor
+/** Return true iff the given length of the encrypted data of a descriptor
* passes validation. */
STATIC int
encrypted_data_length_is_valid(size_t len)
@@ -1356,7 +1362,7 @@ encrypted_data_length_is_valid(size_t len)
return 0;
}
-/* Build the KEYS component for the authorized client computation. The format
+/** Build the KEYS component for the authorized client computation. The format
* of the construction is:
*
* SECRET_SEED = x25519(sk, pk)
@@ -1366,8 +1372,7 @@ encrypted_data_length_is_valid(size_t len)
* and return the buffer's length. The caller should wipe and free its content
* once done with it. This function can't fail. */
static size_t
-build_descriptor_cookie_keys(const uint8_t *subcredential,
- size_t subcredential_len,
+build_descriptor_cookie_keys(const hs_subcredential_t *subcredential,
const curve25519_secret_key_t *sk,
const curve25519_public_key_t *pk,
uint8_t **keys_out)
@@ -1389,7 +1394,7 @@ build_descriptor_cookie_keys(const uint8_t *subcredential,
/* Calculate KEYS = KDF(subcredential | SECRET_SEED, 40) */
xof = crypto_xof_new();
- crypto_xof_add_bytes(xof, subcredential, subcredential_len);
+ crypto_xof_add_bytes(xof, subcredential->subcred, SUBCRED_LEN);
crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed));
crypto_xof_squeeze_bytes(xof, keystream, keystream_len);
crypto_xof_free(xof);
@@ -1400,7 +1405,7 @@ build_descriptor_cookie_keys(const uint8_t *subcredential,
return keystream_len;
}
-/* Decrypt the descriptor cookie given the descriptor, the auth client,
+/** Decrypt the descriptor cookie given the descriptor, the auth client,
* and the client secret key. On sucess, return 0 and a newly allocated
* descriptor cookie descriptor_cookie_out. On error or if the client id
* is invalid, return -1 and descriptor_cookie_out is set to
@@ -1424,13 +1429,18 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc,
tor_assert(!fast_mem_is_zero(
(char *) &desc->superencrypted_data.auth_ephemeral_pubkey,
sizeof(desc->superencrypted_data.auth_ephemeral_pubkey)));
- tor_assert(!fast_mem_is_zero((char *) client_auth_sk,
- sizeof(*client_auth_sk)));
- tor_assert(!fast_mem_is_zero((char *) desc->subcredential, DIGEST256_LEN));
+ tor_assert(!fast_mem_is_zero((char *) desc->subcredential.subcred,
+ DIGEST256_LEN));
+
+ /* Catch potential code-flow cases of an unitialized private key sneaking
+ * into this function. */
+ if (BUG(fast_mem_is_zero((char *)client_auth_sk, sizeof(*client_auth_sk)))) {
+ goto done;
+ }
/* Get the KEYS component to derive the CLIENT-ID and COOKIE-KEY. */
keystream_length =
- build_descriptor_cookie_keys(desc->subcredential, DIGEST256_LEN,
+ build_descriptor_cookie_keys(&desc->subcredential,
client_auth_sk,
&desc->superencrypted_data.auth_ephemeral_pubkey,
&keystream);
@@ -1592,7 +1602,7 @@ decrypt_desc_layer,(const hs_descriptor_t *desc,
return result_len;
}
-/* Decrypt the superencrypted section of the descriptor using the given
+/** Decrypt the superencrypted section of the descriptor using the given
* descriptor object <b>desc</b>. A newly allocated NUL terminated string is
* put in decrypted_out which contains the superencrypted layer of the
* descriptor. Return the length of decrypted_out on success else 0 is
@@ -1624,7 +1634,7 @@ desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out)
return superencrypted_len;
}
-/* Decrypt the encrypted section of the descriptor using the given descriptor
+/** Decrypt the encrypted section of the descriptor using the given descriptor
* object <b>desc</b>. A newly allocated NUL terminated string is put in
* decrypted_out which contains the encrypted layer of the descriptor.
* Return the length of decrypted_out on success else 0 is returned and
@@ -1677,7 +1687,7 @@ desc_decrypt_encrypted(const hs_descriptor_t *desc,
return encrypted_len;
}
-/* Given the token tok for an intro point legacy key, the list of tokens, the
+/** Given the token tok for an intro point legacy key, the list of tokens, the
* introduction point ip being decoded and the descriptor desc from which it
* comes from, decode the legacy key and set the intro point object. Return 0
* on success else -1 on failure. */
@@ -1735,7 +1745,7 @@ decode_intro_legacy_key(const directory_token_t *tok,
return -1;
}
-/* Dig into the descriptor <b>tokens</b> to find the onion key we should use
+/** Dig into the descriptor <b>tokens</b> to find the onion key we should use
* for this intro point, and set it into <b>onion_key_out</b>. Return 0 if it
* was found and well-formed, otherwise return -1 in case of errors. */
static int
@@ -1779,7 +1789,7 @@ set_intro_point_onion_key(curve25519_public_key_t *onion_key_out,
return retval;
}
-/* Given the start of a section and the end of it, decode a single
+/** Given the start of a section and the end of it, decode a single
* introduction point from that section. Return a newly allocated introduction
* point object containing the decoded data. Return NULL if the section can't
* be decoded. */
@@ -1908,7 +1918,7 @@ decode_introduction_point(const hs_descriptor_t *desc, const char *start)
return ip;
}
-/* Given a descriptor string at <b>data</b>, decode all possible introduction
+/** Given a descriptor string at <b>data</b>, decode all possible introduction
* points that we can find. Add the introduction point object to desc_enc as we
* find them. This function can't fail and it is possible that zero
* introduction points can be decoded. */
@@ -1972,7 +1982,7 @@ decode_intro_points(const hs_descriptor_t *desc,
smartlist_free(intro_points);
}
-/* Return 1 iff the given base64 encoded signature in b64_sig from the encoded
+/** Return 1 iff the given base64 encoded signature in b64_sig from the encoded
* descriptor in encoded_desc validates the descriptor content. */
STATIC int
desc_sig_is_valid(const char *b64_sig,
@@ -2031,14 +2041,14 @@ desc_sig_is_valid(const char *b64_sig,
return ret;
}
-/* Decode descriptor plaintext data for version 3. Given a list of tokens, an
+/** Decode descriptor plaintext data for version 3. Given a list of tokens, an
* allocated plaintext object that will be populated and the encoded
* descriptor with its length. The last one is needed for signature
* verification. Unknown tokens are simply ignored so this won't error on
* unknowns but requires that all v3 token be present and valid.
*
* Return 0 on success else a negative value. */
-static int
+static hs_desc_decode_status_t
desc_decode_plaintext_v3(smartlist_t *tokens,
hs_desc_plaintext_data_t *desc,
const char *encoded_desc, size_t encoded_len)
@@ -2128,21 +2138,19 @@ desc_decode_plaintext_v3(smartlist_t *tokens,
goto err;
}
- return 0;
-
+ return HS_DESC_DECODE_OK;
err:
- return -1;
+ return HS_DESC_DECODE_PLAINTEXT_ERROR;
}
-/* Decode the version 3 superencrypted section of the given descriptor desc.
- * The desc_superencrypted_out will be populated with the decoded data.
- * Return 0 on success else -1. */
-static int
+/** 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
desc_decode_superencrypted_v3(const hs_descriptor_t *desc,
hs_desc_superencrypted_data_t *
desc_superencrypted_out)
{
- int ret = -1;
+ int ret = HS_DESC_DECODE_SUPERENC_ERROR;
char *message = NULL;
size_t message_len;
memarea_t *area = NULL;
@@ -2228,11 +2236,11 @@ desc_decode_superencrypted_v3(const hs_descriptor_t *desc,
tok->object_size);
superencrypted->encrypted_blob_size = tok->object_size;
- ret = 0;
+ ret = HS_DESC_DECODE_OK;
goto done;
err:
- tor_assert(ret < 0);
+ tor_assert(ret < HS_DESC_DECODE_OK);
hs_desc_superencrypted_data_free_contents(desc_superencrypted_out);
done:
@@ -2249,15 +2257,14 @@ desc_decode_superencrypted_v3(const hs_descriptor_t *desc,
return ret;
}
-/* Decode the version 3 encrypted section of the given descriptor desc. The
- * desc_encrypted_out will be populated with the decoded data. Return 0 on
- * success else -1. */
-static int
+/** 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
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)
{
- int ret = -1;
+ int ret = HS_DESC_DECODE_ENCRYPTED_ERROR;
char *message = NULL;
size_t message_len;
memarea_t *area = NULL;
@@ -2280,12 +2287,14 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc,
* authorization is failing. */
log_warn(LD_REND, "Client authorization for requested onion address "
"is invalid. Can't decrypt the descriptor.");
+ ret = HS_DESC_DECODE_BAD_CLIENT_AUTH;
} else {
/* Inform at notice level that the onion address requested can't be
* reached without client authorization most likely. */
log_notice(LD_REND, "Fail to decrypt descriptor for requested onion "
"address. It is likely requiring client "
"authorization.");
+ ret = HS_DESC_DECODE_NEED_CLIENT_AUTH;
}
goto err;
}
@@ -2343,11 +2352,11 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc,
/* NOTE: Unknown fields are allowed because this function could be used to
* decode other descriptor version. */
- ret = 0;
+ ret = HS_DESC_DECODE_OK;
goto done;
err:
- tor_assert(ret < 0);
+ tor_assert(ret < HS_DESC_DECODE_OK);
hs_desc_encrypted_data_free_contents(desc_encrypted_out);
done:
@@ -2364,9 +2373,9 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc,
return ret;
}
-/* Table of encrypted decode function version specific. The function are
+/** Table of encrypted decode function version specific. The function are
* indexed by the version number so v3 callback is at index 3 in the array. */
-static int
+static hs_desc_decode_status_t
(*decode_encrypted_handlers[])(
const hs_descriptor_t *desc,
const curve25519_secret_key_t *client_auth_sk,
@@ -2376,15 +2385,15 @@ static int
desc_decode_encrypted_v3,
};
-/* Decode the encrypted data section of the given descriptor and store the
+/** Decode the encrypted data section of the given descriptor and store the
* data in the given encrypted data object. Return 0 on success else a
* negative value on error. */
-int
+hs_desc_decode_status_t
hs_desc_decode_encrypted(const hs_descriptor_t *desc,
const curve25519_secret_key_t *client_auth_sk,
hs_desc_encrypted_data_t *desc_encrypted)
{
- int ret;
+ int ret = HS_DESC_DECODE_ENCRYPTED_ERROR;
uint32_t version;
tor_assert(desc);
@@ -2398,7 +2407,6 @@ hs_desc_decode_encrypted(const hs_descriptor_t *desc,
/* Let's make sure we have a supported version as well. By correctly parsing
* the plaintext, this should not fail. */
if (BUG(!hs_desc_is_supported_version(version))) {
- ret = -1;
goto err;
}
/* Extra precaution. Having no handler for the supported version should
@@ -2417,9 +2425,9 @@ hs_desc_decode_encrypted(const hs_descriptor_t *desc,
return ret;
}
-/* Table of superencrypted decode function version specific. The function are
+/** Table of superencrypted decode function version specific. The function are
* indexed by the version number so v3 callback is at index 3 in the array. */
-static int
+static hs_desc_decode_status_t
(*decode_superencrypted_handlers[])(
const hs_descriptor_t *desc,
hs_desc_superencrypted_data_t *desc_superencrypted) =
@@ -2428,15 +2436,14 @@ static int
desc_decode_superencrypted_v3,
};
-/* Decode the superencrypted data section of the given descriptor and store the
- * data in the given superencrypted data object. Return 0 on success else a
- * negative value on error. */
-int
+/** Decode the superencrypted data section of the given descriptor and store
+ * the data in the given superencrypted data object. */
+hs_desc_decode_status_t
hs_desc_decode_superencrypted(const hs_descriptor_t *desc,
hs_desc_superencrypted_data_t *
desc_superencrypted)
{
- int ret;
+ int ret = HS_DESC_DECODE_SUPERENC_ERROR;
uint32_t version;
tor_assert(desc);
@@ -2450,7 +2457,6 @@ hs_desc_decode_superencrypted(const hs_descriptor_t *desc,
/* Let's make sure we have a supported version as well. By correctly parsing
* the plaintext, this should not fail. */
if (BUG(!hs_desc_is_supported_version(version))) {
- ret = -1;
goto err;
}
/* Extra precaution. Having no handler for the supported version should
@@ -2468,9 +2474,9 @@ hs_desc_decode_superencrypted(const hs_descriptor_t *desc,
return ret;
}
-/* Table of plaintext decode function version specific. The function are
+/** Table of plaintext decode function version specific. The function are
* indexed by the version number so v3 callback is at index 3 in the array. */
-static int
+static hs_desc_decode_status_t
(*decode_plaintext_handlers[])(
smartlist_t *tokens,
hs_desc_plaintext_data_t *desc,
@@ -2481,13 +2487,13 @@ static int
desc_decode_plaintext_v3,
};
-/* Fully decode the given descriptor plaintext and store the data in the
- * plaintext data object. Returns 0 on success else a negative value. */
-int
+/** Fully decode the given descriptor plaintext and store the data in the
+ * plaintext data object. */
+hs_desc_decode_status_t
hs_desc_decode_plaintext(const char *encoded,
hs_desc_plaintext_data_t *plaintext)
{
- int ok = 0, ret = -1;
+ int ok = 0, ret = HS_DESC_DECODE_PLAINTEXT_ERROR;
memarea_t *area = NULL;
smartlist_t *tokens = NULL;
size_t encoded_len;
@@ -2537,11 +2543,11 @@ hs_desc_decode_plaintext(const char *encoded,
/* Run the version specific plaintext decoder. */
ret = decode_plaintext_handlers[plaintext->version](tokens, plaintext,
encoded, encoded_len);
- if (ret < 0) {
+ if (ret != HS_DESC_DECODE_OK) {
goto err;
}
/* Success. Descriptor has been populated with the data. */
- ret = 0;
+ ret = HS_DESC_DECODE_OK;
err:
if (tokens) {
@@ -2554,19 +2560,19 @@ hs_desc_decode_plaintext(const char *encoded,
return ret;
}
-/* Fully decode an encoded descriptor and set a newly allocated descriptor
+/** Fully decode an encoded descriptor and set a newly allocated descriptor
* object in desc_out. Client secret key is used to decrypt the "encrypted"
* section if not NULL else it's ignored.
*
* Return 0 on success. A negative value is returned on error and desc_out is
* set to NULL. */
-int
+hs_desc_decode_status_t
hs_desc_decode_descriptor(const char *encoded,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
const curve25519_secret_key_t *client_auth_sk,
hs_descriptor_t **desc_out)
{
- int ret = -1;
+ hs_desc_decode_status_t ret = HS_DESC_DECODE_GENERIC_ERROR;
hs_descriptor_t *desc;
tor_assert(encoded);
@@ -2580,20 +2586,20 @@ hs_desc_decode_descriptor(const char *encoded,
goto err;
}
- memcpy(desc->subcredential, subcredential, sizeof(desc->subcredential));
+ memcpy(&desc->subcredential, subcredential, sizeof(desc->subcredential));
ret = hs_desc_decode_plaintext(encoded, &desc->plaintext_data);
- if (ret < 0) {
+ if (ret != HS_DESC_DECODE_OK) {
goto err;
}
ret = hs_desc_decode_superencrypted(desc, &desc->superencrypted_data);
- if (ret < 0) {
+ if (ret != HS_DESC_DECODE_OK) {
goto err;
}
ret = hs_desc_decode_encrypted(desc, client_auth_sk, &desc->encrypted_data);
- if (ret < 0) {
+ if (ret != HS_DESC_DECODE_OK) {
goto err;
}
@@ -2614,7 +2620,7 @@ hs_desc_decode_descriptor(const char *encoded,
return ret;
}
-/* Table of encode function version specific. The functions are indexed by the
+/** Table of encode function version specific. The functions are indexed by the
* version number so v3 callback is at index 3 in the array. */
static int
(*encode_handlers[])(
@@ -2627,7 +2633,7 @@ static int
desc_encode_v3,
};
-/* Encode the given descriptor desc including signing with the given key pair
+/** Encode the given descriptor desc including signing with the given key pair
* signing_kp and encrypting with the given descriptor cookie.
*
* If the client authorization is enabled, descriptor_cookie must be the same
@@ -2670,9 +2676,10 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc,
* symmetric only if the client auth is disabled. That is, the descriptor
* cookie will be NULL. */
if (!descriptor_cookie) {
- ret = hs_desc_decode_descriptor(*encoded_out, desc->subcredential,
+ ret = hs_desc_decode_descriptor(*encoded_out, &desc->subcredential,
NULL, NULL);
- if (BUG(ret < 0)) {
+ if (BUG(ret != HS_DESC_DECODE_OK)) {
+ ret = -1;
goto err;
}
}
@@ -2684,7 +2691,7 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc,
return ret;
}
-/* Free the content of the plaintext section of a descriptor. */
+/** Free the content of the plaintext section of a descriptor. */
void
hs_desc_plaintext_data_free_contents(hs_desc_plaintext_data_t *desc)
{
@@ -2700,7 +2707,7 @@ hs_desc_plaintext_data_free_contents(hs_desc_plaintext_data_t *desc)
memwipe(desc, 0, sizeof(*desc));
}
-/* Free the content of the superencrypted section of a descriptor. */
+/** Free the content of the superencrypted section of a descriptor. */
void
hs_desc_superencrypted_data_free_contents(hs_desc_superencrypted_data_t *desc)
{
@@ -2720,7 +2727,7 @@ hs_desc_superencrypted_data_free_contents(hs_desc_superencrypted_data_t *desc)
memwipe(desc, 0, sizeof(*desc));
}
-/* Free the content of the encrypted section of a descriptor. */
+/** Free the content of the encrypted section of a descriptor. */
void
hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc)
{
@@ -2740,7 +2747,7 @@ hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc)
memwipe(desc, 0, sizeof(*desc));
}
-/* Free the descriptor plaintext data object. */
+/** Free the descriptor plaintext data object. */
void
hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc)
{
@@ -2748,7 +2755,7 @@ hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc)
tor_free(desc);
}
-/* Free the descriptor plaintext data object. */
+/** Free the descriptor plaintext data object. */
void
hs_desc_superencrypted_data_free_(hs_desc_superencrypted_data_t *desc)
{
@@ -2756,7 +2763,7 @@ hs_desc_superencrypted_data_free_(hs_desc_superencrypted_data_t *desc)
tor_free(desc);
}
-/* Free the descriptor encrypted data object. */
+/** Free the descriptor encrypted data object. */
void
hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc)
{
@@ -2764,7 +2771,7 @@ hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc)
tor_free(desc);
}
-/* Free the given descriptor object. */
+/** Free the given descriptor object. */
void
hs_descriptor_free_(hs_descriptor_t *desc)
{
@@ -2778,7 +2785,7 @@ hs_descriptor_free_(hs_descriptor_t *desc)
tor_free(desc);
}
-/* Return the size in bytes of the given plaintext data object. A sizeof() is
+/** Return the size in bytes of the given plaintext data object. A sizeof() is
* not enough because the object contains pointers and the encrypted blob.
* This is particularly useful for our OOM subsystem that tracks the HSDir
* cache size for instance. */
@@ -2790,7 +2797,7 @@ hs_desc_plaintext_obj_size(const hs_desc_plaintext_data_t *data)
data->superencrypted_blob_size);
}
-/* Return the size in bytes of the given encrypted data object. Used by OOM
+/** Return the size in bytes of the given encrypted data object. Used by OOM
* subsystem. */
static size_t
hs_desc_encrypted_obj_size(const hs_desc_encrypted_data_t *data)
@@ -2810,18 +2817,20 @@ hs_desc_encrypted_obj_size(const hs_desc_encrypted_data_t *data)
return sizeof(*data) + intro_size;
}
-/* Return the size in bytes of the given descriptor object. Used by OOM
+/** Return the size in bytes of the given descriptor object. Used by OOM
* subsystem. */
size_t
hs_desc_obj_size(const hs_descriptor_t *data)
{
- tor_assert(data);
+ if (data == NULL) {
+ return 0;
+ }
return (hs_desc_plaintext_obj_size(&data->plaintext_data) +
hs_desc_encrypted_obj_size(&data->encrypted_data) +
sizeof(data->subcredential));
}
-/* Return a newly allocated descriptor intro point. */
+/** Return a newly allocated descriptor intro point. */
hs_desc_intro_point_t *
hs_desc_intro_point_new(void)
{
@@ -2830,7 +2839,7 @@ hs_desc_intro_point_new(void)
return ip;
}
-/* Free a descriptor intro point object. */
+/** Free a descriptor intro point object. */
void
hs_desc_intro_point_free_(hs_desc_intro_point_t *ip)
{
@@ -2849,7 +2858,7 @@ hs_desc_intro_point_free_(hs_desc_intro_point_t *ip)
tor_free(ip);
}
-/* Allocate and build a new fake client info for the descriptor. Return a
+/** Allocate and build a new fake client info for the descriptor. Return a
* newly allocated object. This can't fail. */
hs_desc_authorized_client_t *
hs_desc_build_fake_authorized_client(void)
@@ -2867,11 +2876,11 @@ hs_desc_build_fake_authorized_client(void)
return client_auth;
}
-/* Using the service's subcredential, client public key, auth ephemeral secret
+/** Using the service's subcredential, client public key, auth ephemeral secret
* key, and descriptor cookie, build the auth client so we can then encode the
* descriptor for publication. client_out must be already allocated. */
void
-hs_desc_build_authorized_client(const uint8_t *subcredential,
+hs_desc_build_authorized_client(const hs_subcredential_t *subcredential,
const curve25519_public_key_t *client_auth_pk,
const curve25519_secret_key_t *
auth_ephemeral_sk,
@@ -2899,7 +2908,7 @@ hs_desc_build_authorized_client(const uint8_t *subcredential,
/* Get the KEYS part so we can derive the CLIENT-ID and COOKIE-KEY. */
keystream_length =
- build_descriptor_cookie_keys(subcredential, DIGEST256_LEN,
+ build_descriptor_cookie_keys(subcredential,
auth_ephemeral_sk, client_auth_pk,
&keystream);
tor_assert(keystream_length > 0);
@@ -2925,14 +2934,14 @@ hs_desc_build_authorized_client(const uint8_t *subcredential,
crypto_cipher_free(cipher);
}
-/* Free an authoriezd client object. */
+/** Free an authoriezd client object. */
void
hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client)
{
tor_free(client);
}
-/* From the given descriptor, remove and free every introduction point. */
+/** From the given descriptor, remove and free every introduction point. */
void
hs_descriptor_clear_intro_points(hs_descriptor_t *desc)
{
diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h
index 0a843f4f3c..08daa904b6 100644
--- a/src/feature/hs/hs_descriptor.h
+++ b/src/feature/hs/hs_descriptor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,92 +14,118 @@
#include "core/or/or.h"
#include "trunnel/ed25519_cert.h" /* needed for trunnel */
#include "feature/nodelist/torcert.h"
+#include "core/crypto/hs_ntor.h" /* for hs_subcredential_t */
/* Trunnel */
struct link_specifier_t;
-/* The earliest descriptor format version we support. */
+/** The earliest descriptor format version we support. */
#define HS_DESC_SUPPORTED_FORMAT_VERSION_MIN 3
-/* The latest descriptor format version we support. */
+/** The latest descriptor format version we support. */
#define HS_DESC_SUPPORTED_FORMAT_VERSION_MAX 3
-/* Default lifetime of a descriptor in seconds. The valus is set at 3 hours
+/** Default lifetime of a descriptor in seconds. The valus is set at 3 hours
* which is 180 minutes or 10800 seconds. */
#define HS_DESC_DEFAULT_LIFETIME (3 * 60 * 60)
-/* Maximum lifetime of a descriptor in seconds. The value is set at 12 hours
+/** Maximum lifetime of a descriptor in seconds. The value is set at 12 hours
* which is 720 minutes or 43200 seconds. */
#define HS_DESC_MAX_LIFETIME (12 * 60 * 60)
-/* Lifetime of certificate in the descriptor. This defines the lifetime of the
+/** Lifetime of certificate in the descriptor. This defines the lifetime of the
* descriptor signing key and the cross certification cert of that key. It is
* set to 54 hours because a descriptor can be around for 48 hours and because
* consensuses are used after the hour, add an extra 6 hours to give some time
* for the service to stop using it. */
#define HS_DESC_CERT_LIFETIME (54 * 60 * 60)
-/* Length of the salt needed for the encrypted section of a descriptor. */
+/** Length of the salt needed for the encrypted section of a descriptor. */
#define HS_DESC_ENCRYPTED_SALT_LEN 16
-/* Length of the KDF output value which is the length of the secret key,
+/** Length of the KDF output value which is the length of the secret key,
* the secret IV and MAC key length which is the length of H() output. */
#define HS_DESC_ENCRYPTED_KDF_OUTPUT_LEN \
CIPHER256_KEY_LEN + CIPHER_IV_LEN + DIGEST256_LEN
-/* Pad plaintext of superencrypted data section before encryption so that its
+/** Pad plaintext of superencrypted data section before encryption so that its
* length is a multiple of this value. */
#define HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE 10000
-/* Maximum length in bytes of a full hidden service descriptor. */
+/** Maximum length in bytes of a full hidden service descriptor. */
#define HS_DESC_MAX_LEN 50000 /* 50kb max size */
-/* Key length for the descriptor symmetric encryption. As specified in the
+/** Key length for the descriptor symmetric encryption. As specified in the
* protocol, we use AES-256 for the encrypted section of the descriptor. The
* following is the length in bytes and the bit size. */
#define HS_DESC_ENCRYPTED_KEY_LEN CIPHER256_KEY_LEN
#define HS_DESC_ENCRYPTED_BIT_SIZE (HS_DESC_ENCRYPTED_KEY_LEN * 8)
-/* Length of each components in the auth client section in the descriptor. */
+/** Length of each components in the auth client section in the descriptor. */
#define HS_DESC_CLIENT_ID_LEN 8
#define HS_DESC_DESCRIPTOR_COOKIE_LEN 16
#define HS_DESC_COOKIE_KEY_LEN 32
#define HS_DESC_COOKIE_KEY_BIT_SIZE (HS_DESC_COOKIE_KEY_LEN * 8)
#define HS_DESC_ENCRYPED_COOKIE_LEN HS_DESC_DESCRIPTOR_COOKIE_LEN
-/* The number of auth client entries in the descriptor must be the multiple
+/** The number of auth client entries in the descriptor must be the multiple
* of this constant. */
#define HS_DESC_AUTH_CLIENT_MULTIPLE 16
-/* Type of authentication in the descriptor. */
+/** Type of authentication in the descriptor. */
typedef enum {
HS_DESC_AUTH_ED25519 = 1
} hs_desc_auth_type_t;
-/* Introduction point information located in a descriptor. */
+/** Error code when decoding a descriptor. */
+typedef enum {
+ /* The configured client authorization for the requested .onion address
+ * failed to decode the descriptor. */
+ HS_DESC_DECODE_BAD_CLIENT_AUTH = -6,
+
+ /* The requested .onion address requires a client authorization. */
+ HS_DESC_DECODE_NEED_CLIENT_AUTH = -5,
+
+ /* Error during decryption of the encrypted layer. */
+ HS_DESC_DECODE_ENCRYPTED_ERROR = -4,
+
+ /* Error during decryption of the super encrypted layer. */
+ HS_DESC_DECODE_SUPERENC_ERROR = -3,
+
+ /* Error while decoding the plaintext section. */
+ HS_DESC_DECODE_PLAINTEXT_ERROR = -2,
+
+ /* Generic error. */
+ HS_DESC_DECODE_GENERIC_ERROR = -1,
+
+ /* Decoding a descriptor was successful. */
+ HS_DESC_DECODE_OK = 0,
+} hs_desc_decode_status_t;
+
+/** Introduction point information located in a descriptor. */
typedef struct hs_desc_intro_point_t {
- /* Link specifier(s) which details how to extend to the relay. This list
+ /** Link specifier(s) which details how to extend to the relay. This list
* contains link_specifier_t objects. It MUST have at least one. */
smartlist_t *link_specifiers;
- /* Onion key of the introduction point used to extend to it for the ntor
+ /** Onion key of the introduction point used to extend to it for the ntor
* handshake. */
curve25519_public_key_t onion_key;
- /* Authentication key used to establish the introduction point circuit and
+ /** Authentication key used to establish the introduction point circuit and
* cross-certifies the blinded public key for the replica thus signed by
* the blinded key and in turn signs it. */
tor_cert_t *auth_key_cert;
- /* Encryption key for the "ntor" type. */
+ /** Encryption key for the "ntor" type. */
curve25519_public_key_t enc_key;
- /* Certificate cross certifying the descriptor signing key by the encryption
+ /** Certificate cross certifying the descriptor signing key by the encryption
* curve25519 key. This certificate contains the signing key and is of type
* CERT_TYPE_CROSS_HS_IP_KEYS [0B]. */
tor_cert_t *enc_key_cert;
- /* (Optional): If this introduction point is a legacy one that is version <=
+ /** (Optional): If this introduction point is a legacy one that is version <=
* 0.2.9.x (HSIntro=3), we use this extra key for the intro point to be able
* to relay the cells to the service correctly. */
struct {
- /* RSA public key. */
+ /** RSA public key. */
crypto_pk_t *key;
- /* Cross certified cert with the descriptor signing key (RSA->Ed). Because
+ /** Cross certified cert with the descriptor signing key (RSA->Ed). Because
* of the cross certification API, we need to keep the certificate binary
* blob and its length in order to properly encode it after. */
struct {
@@ -108,115 +134,115 @@ typedef struct hs_desc_intro_point_t {
} cert;
} legacy;
- /* True iff the introduction point has passed the cross certification. Upon
+ /** True iff the introduction point has passed the cross certification. Upon
* decoding an intro point, this must be true. */
unsigned int cross_certified : 1;
} hs_desc_intro_point_t;
-/* Authorized client information located in a descriptor. */
+/** Authorized client information located in a descriptor. */
typedef struct hs_desc_authorized_client_t {
- /* An identifier that the client will use to identify which auth client
+ /** An identifier that the client will use to identify which auth client
* entry it needs to use. */
uint8_t client_id[HS_DESC_CLIENT_ID_LEN];
- /* An IV that is used to decrypt the encrypted descriptor cookie. */
+ /** An IV that is used to decrypt the encrypted descriptor cookie. */
uint8_t iv[CIPHER_IV_LEN];
- /* An encrypted descriptor cookie that the client needs to decrypt to use
+ /** An encrypted descriptor cookie that the client needs to decrypt to use
* it to decrypt the descriptor. */
uint8_t encrypted_cookie[HS_DESC_ENCRYPED_COOKIE_LEN];
} hs_desc_authorized_client_t;
-/* The encrypted data section of a descriptor. Obviously the data in this is
+/** The encrypted data section of a descriptor. Obviously the data in this is
* in plaintext but encrypted once encoded. */
typedef struct hs_desc_encrypted_data_t {
- /* Bitfield of CREATE2 cell supported formats. The only currently supported
+ /** Bitfield of CREATE2 cell supported formats. The only currently supported
* format is ntor. */
unsigned int create2_ntor : 1;
- /* A list of authentication types that a client must at least support one
+ /** A list of authentication types that a client must at least support one
* in order to contact the service. Contains NULL terminated strings. */
smartlist_t *intro_auth_types;
- /* Is this descriptor a single onion service? */
+ /** Is this descriptor a single onion service? */
unsigned int single_onion_service : 1;
- /* A list of intro points. Contains hs_desc_intro_point_t objects. */
+ /** A list of intro points. Contains hs_desc_intro_point_t objects. */
smartlist_t *intro_points;
} hs_desc_encrypted_data_t;
-/* The superencrypted data section of a descriptor. Obviously the data in
+/** The superencrypted data section of a descriptor. Obviously the data in
* this is in plaintext but encrypted once encoded. */
typedef struct hs_desc_superencrypted_data_t {
- /* This field contains ephemeral x25519 public key which is used by
+ /** This field contains ephemeral x25519 public key which is used by
* the encryption scheme in the client authorization. */
curve25519_public_key_t auth_ephemeral_pubkey;
- /* A list of authorized clients. Contains hs_desc_authorized_client_t
+ /** A list of authorized clients. Contains hs_desc_authorized_client_t
* objects. */
smartlist_t *clients;
- /* Decoding only: The b64-decoded encrypted blob from the descriptor */
+ /** Decoding only: The b64-decoded encrypted blob from the descriptor */
uint8_t *encrypted_blob;
- /* Decoding only: Size of the encrypted_blob */
+ /** Decoding only: Size of the encrypted_blob */
size_t encrypted_blob_size;
} hs_desc_superencrypted_data_t;
-/* Plaintext data that is unencrypted information of the descriptor. */
+/** Plaintext data that is unencrypted information of the descriptor. */
typedef struct hs_desc_plaintext_data_t {
- /* Version of the descriptor format. Spec specifies this field as a
+ /** Version of the descriptor format. Spec specifies this field as a
* positive integer. */
uint32_t version;
- /* The lifetime of the descriptor in seconds. */
+ /** The lifetime of the descriptor in seconds. */
uint32_t lifetime_sec;
- /* Certificate with the short-term ed22519 descriptor signing key for the
+ /** Certificate with the short-term ed22519 descriptor signing key for the
* replica which is signed by the blinded public key for that replica. */
tor_cert_t *signing_key_cert;
- /* Signing public key which is used to sign the descriptor. Same public key
+ /** Signing public key which is used to sign the descriptor. Same public key
* as in the signing key certificate. */
ed25519_public_key_t signing_pubkey;
- /* Blinded public key used for this descriptor derived from the master
+ /** Blinded public key used for this descriptor derived from the master
* identity key and generated for a specific replica number. */
ed25519_public_key_t blinded_pubkey;
- /* Revision counter is incremented at each upload, regardless of whether
+ /** Revision counter is incremented at each upload, regardless of whether
* the descriptor has changed. This avoids leaking whether the descriptor
* has changed. Spec specifies this as a 8 bytes positive integer. */
uint64_t revision_counter;
- /* Decoding only: The b64-decoded superencrypted blob from the descriptor */
+ /** Decoding only: The b64-decoded superencrypted blob from the descriptor */
uint8_t *superencrypted_blob;
- /* Decoding only: Size of the superencrypted_blob */
+ /** Decoding only: Size of the superencrypted_blob */
size_t superencrypted_blob_size;
} hs_desc_plaintext_data_t;
-/* Service descriptor in its decoded form. */
+/** Service descriptor in its decoded form. */
typedef struct hs_descriptor_t {
- /* Contains the plaintext part of the descriptor. */
+ /** Contains the plaintext part of the descriptor. */
hs_desc_plaintext_data_t plaintext_data;
- /* The following contains what's in the superencrypted part of the
+ /** The following contains what's in the superencrypted part of the
* descriptor. It's only encrypted in the encoded version of the descriptor
* thus the data contained in that object is in plaintext. */
hs_desc_superencrypted_data_t superencrypted_data;
- /* The following contains what's in the encrypted part of the descriptor.
+ /** The following contains what's in the encrypted part of the descriptor.
* It's only encrypted in the encoded version of the descriptor thus the
* data contained in that object is in plaintext. */
hs_desc_encrypted_data_t encrypted_data;
- /* Subcredentials of a service, used by the client and service to decrypt
+ /** Subcredentials of a service, used by the client and service to decrypt
* the encrypted data. */
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
} hs_descriptor_t;
-/* Return true iff the given descriptor format version is supported. */
+/** Return true iff the given descriptor format version is supported. */
static inline int
hs_desc_is_supported_version(uint32_t version)
{
@@ -252,7 +278,7 @@ MOCK_DECL(int,
char **encoded_out));
int hs_desc_decode_descriptor(const char *encoded,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
const curve25519_secret_key_t *client_auth_sk,
hs_descriptor_t **desc_out);
int hs_desc_decode_plaintext(const char *encoded,
@@ -277,7 +303,7 @@ void hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client);
hs_desc_authorized_client_t *hs_desc_build_fake_authorized_client(void);
-void hs_desc_build_authorized_client(const uint8_t *subcredential,
+void hs_desc_build_authorized_client(const hs_subcredential_t *subcredential,
const curve25519_public_key_t *
client_auth_pk,
const curve25519_secret_key_t *
diff --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c
index 19794e09d3..1f7415a280 100644
--- a/src/feature/hs/hs_dos.c
+++ b/src/feature/hs/hs_dos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019, The Tor Project, Inc. */
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -31,20 +31,23 @@
#include "feature/hs/hs_dos.h"
-/* Default value of the allowed INTRODUCE2 cell rate per second. Above that
+/** Default value of the allowed INTRODUCE2 cell rate per second. Above that
* value per second, the introduction is denied. */
#define HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC 25
-/* Default value of the allowed INTRODUCE2 cell burst per second. This is the
+/** Default value of the allowed INTRODUCE2 cell burst per second. This is the
* maximum value a token bucket has per second. We thus allow up to this value
* of INTRODUCE2 cell per second but the bucket is refilled by the rate value
* but never goes above that burst value. */
#define HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC 200
-/* Default value of the consensus parameter enabling or disabling the
+/** Default value of the consensus parameter enabling or disabling the
* introduction DoS defense. Disabled by default. */
#define HS_DOS_INTRODUCE_ENABLED_DEFAULT 0
+/** INTRODUCE2 rejected request counter. */
+static uint64_t intro2_rejected_count = 0;
+
/* Consensus parameters. The ESTABLISH_INTRO DoS cell extension have higher
* priority than these values. If no extension is sent, these are used only by
* the introduction point. */
@@ -62,7 +65,7 @@ get_intro2_enable_consensus_param(const networkstatus_t *ns)
HS_DOS_INTRODUCE_ENABLED_DEFAULT, 0, 1);
}
-/* Return the parameter for the introduction rate per sec. */
+/** Return the parameter for the introduction rate per sec. */
STATIC uint32_t
get_intro2_rate_consensus_param(const networkstatus_t *ns)
{
@@ -71,7 +74,7 @@ get_intro2_rate_consensus_param(const networkstatus_t *ns)
0, INT32_MAX);
}
-/* Return the parameter for the introduction burst per sec. */
+/** Return the parameter for the introduction burst per sec. */
STATIC uint32_t
get_intro2_burst_consensus_param(const networkstatus_t *ns)
{
@@ -80,7 +83,7 @@ get_intro2_burst_consensus_param(const networkstatus_t *ns)
0, INT32_MAX);
}
-/* Go over all introduction circuit relay side and adjust their rate/burst
+/** Go over all introduction circuit relay side and adjust their rate/burst
* values using the global parameters. This is called right after the
* consensus parameters might have changed. */
static void
@@ -102,7 +105,7 @@ update_intro_circuits(void)
smartlist_free(intro_circs);
}
-/* Set consensus parameters. */
+/** Set consensus parameters. */
static void
set_consensus_parameters(const networkstatus_t *ns)
{
@@ -122,7 +125,7 @@ set_consensus_parameters(const networkstatus_t *ns)
* Public API.
*/
-/* Initialize the INTRODUCE2 token bucket for the DoS defenses using the
+/** Initialize the INTRODUCE2 token bucket for the DoS defenses using the
* consensus/default values. We might get a cell extension that changes those
* later but if we don't, the default or consensus parameters are used. */
void
@@ -138,7 +141,7 @@ hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
(uint32_t) approx_time());
}
-/* Called when the consensus has changed. We might have new consensus
+/** Called when the consensus has changed. We might have new consensus
* parameters to look at. */
void
hs_dos_consensus_has_changed(const networkstatus_t *ns)
@@ -152,7 +155,7 @@ hs_dos_consensus_has_changed(const networkstatus_t *ns)
set_consensus_parameters(ns);
}
-/* Return true iff an INTRODUCE2 cell can be sent on the given service
+/** Return true iff an INTRODUCE2 cell can be sent on the given service
* introduction circuit. */
bool
hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
@@ -163,12 +166,12 @@ hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
* This can be set by the consensus, the ESTABLISH_INTRO cell extension or
* the hardcoded values in tor code. */
if (!s_intro_circ->introduce2_dos_defense_enabled) {
- return true;
+ goto allow;
}
/* Should not happen but if so, scream loudly. */
if (BUG(TO_CIRCUIT(s_intro_circ)->purpose != CIRCUIT_PURPOSE_INTRO_POINT)) {
- return false;
+ goto disallow;
}
/* This is called just after we got a valid and parsed INTRODUCE1 cell. The
@@ -189,10 +192,30 @@ hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
}
/* Finally, we can send a new INTRODUCE2 if there are still tokens. */
- return token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0;
+ if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
+ goto allow;
+ }
+
+ /* If we reach this point, then it means the bucket has reached zero, and
+ we're going to disallow. */
+
+ disallow:
+ /* Increment stats counter, we are rejecting the INTRO2 cell. */
+ intro2_rejected_count++;
+ return false;
+
+ allow:
+ return true;
+}
+
+/** Return rolling count of rejected INTRO2. */
+uint64_t
+hs_dos_get_intro2_rejected_count(void)
+{
+ return intro2_rejected_count;
}
-/* Initialize the onion service Denial of Service subsystem. */
+/** Initialize the onion service Denial of Service subsystem. */
void
hs_dos_init(void)
{
diff --git a/src/feature/hs/hs_dos.h b/src/feature/hs/hs_dos.h
index ccf4e27179..8e36ece204 100644
--- a/src/feature/hs/hs_dos.h
+++ b/src/feature/hs/hs_dos.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019, The Tor Project, Inc. */
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -24,6 +24,9 @@ void hs_dos_consensus_has_changed(const networkstatus_t *ns);
bool hs_dos_can_send_intro2(or_circuit_t *s_intro_circ);
void hs_dos_setup_default_intro2_defenses(or_circuit_t *circ);
+/* Statistics. */
+uint64_t hs_dos_get_intro2_rejected_count(void);
+
#ifdef HS_DOS_PRIVATE
#ifdef TOR_UNIT_TESTS
diff --git a/src/feature/hs/hs_ident.c b/src/feature/hs/hs_ident.c
index a00e55ec23..1d93ff9610 100644
--- a/src/feature/hs/hs_ident.c
+++ b/src/feature/hs/hs_ident.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,7 +10,7 @@
#include "lib/crypt_ops/crypto_util.h"
#include "feature/hs/hs_ident.h"
-/* Return a newly allocated circuit identifier. The given public key is copied
+/** Return a newly allocated circuit identifier. The given public key is copied
* identity_pk into the identifier. */
hs_ident_circuit_t *
hs_ident_circuit_new(const ed25519_public_key_t *identity_pk)
@@ -20,7 +20,7 @@ hs_ident_circuit_new(const ed25519_public_key_t *identity_pk)
return ident;
}
-/* Free the given circuit identifier. */
+/** Free the given circuit identifier. */
void
hs_ident_circuit_free_(hs_ident_circuit_t *ident)
{
@@ -31,7 +31,7 @@ hs_ident_circuit_free_(hs_ident_circuit_t *ident)
tor_free(ident);
}
-/* For a given circuit identifier src, return a newly allocated copy of it.
+/** For a given circuit identifier src, return a newly allocated copy of it.
* This can't fail. */
hs_ident_circuit_t *
hs_ident_circuit_dup(const hs_ident_circuit_t *src)
@@ -41,7 +41,7 @@ hs_ident_circuit_dup(const hs_ident_circuit_t *src)
return ident;
}
-/* For a given directory connection identifier src, return a newly allocated
+/** For a given directory connection identifier src, return a newly allocated
* copy of it. This can't fail. */
hs_ident_dir_conn_t *
hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src)
@@ -51,7 +51,7 @@ hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src)
return ident;
}
-/* Free the given directory connection identifier. */
+/** Free the given directory connection identifier. */
void
hs_ident_dir_conn_free_(hs_ident_dir_conn_t *ident)
{
@@ -62,7 +62,7 @@ hs_ident_dir_conn_free_(hs_ident_dir_conn_t *ident)
tor_free(ident);
}
-/* Initialized the allocated ident object with identity_pk and blinded_pk.
+/** Initialized the allocated ident object with identity_pk and blinded_pk.
* None of them can be NULL since a valid directory connection identifier must
* have all fields set. */
void
@@ -78,7 +78,7 @@ hs_ident_dir_conn_init(const ed25519_public_key_t *identity_pk,
ed25519_pubkey_copy(&ident->blinded_pk, blinded_pk);
}
-/* Return a newly allocated edge connection identifier. The given public key
+/** Return a newly allocated edge connection identifier. The given public key
* identity_pk is copied into the identifier. */
hs_ident_edge_conn_t *
hs_ident_edge_conn_new(const ed25519_public_key_t *identity_pk)
@@ -88,7 +88,7 @@ hs_ident_edge_conn_new(const ed25519_public_key_t *identity_pk)
return ident;
}
-/* Free the given edge connection identifier. */
+/** Free the given edge connection identifier. */
void
hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident)
{
@@ -99,7 +99,7 @@ hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident)
tor_free(ident);
}
-/* Return true if the given ident is valid for an introduction circuit. */
+/** Return true if the given ident is valid for an introduction circuit. */
int
hs_ident_intro_circ_is_valid(const hs_ident_circuit_t *ident)
{
@@ -120,4 +120,3 @@ hs_ident_intro_circ_is_valid(const hs_ident_circuit_t *ident)
invalid:
return 0;
}
-
diff --git a/src/feature/hs/hs_ident.h b/src/feature/hs/hs_ident.h
index 82ca50f6b5..f4b9b2432d 100644
--- a/src/feature/hs/hs_ident.h
+++ b/src/feature/hs/hs_ident.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,70 +25,71 @@
#include "feature/hs/hs_common.h"
-/* Length of the rendezvous cookie that is used to connect circuits at the
+/** Length of the rendezvous cookie that is used to connect circuits at the
* rendezvous point. */
#define HS_REND_COOKIE_LEN DIGEST_LEN
-/* Type of circuit an hs_ident_t object is associated with. */
+/** Type of circuit an hs_ident_t object is associated with. */
typedef enum {
HS_IDENT_CIRCUIT_INTRO = 1,
HS_IDENT_CIRCUIT_RENDEZVOUS = 2,
} hs_ident_circuit_type_t;
-/* Client and service side circuit identifier that is used for hidden service
+/** Client and service side circuit identifier that is used for hidden service
* circuit establishment. Not all fields contain data, it depends on the
* circuit purpose. This is attached to an origin_circuit_t. All fields are
* used by both client and service. */
typedef struct hs_ident_circuit_t {
- /* (All circuit) The public key used to uniquely identify the service. It is
+ /** (All circuit) The public key used to uniquely identify the service. It is
* the one found in the onion address. */
ed25519_public_key_t identity_pk;
- /* (All circuit) Introduction point authentication key. It's also needed on
+ /** (All circuit) Introduction point authentication key. It's also needed on
* the rendezvous circuit for the ntor handshake. It's used as the unique key
* of the introduction point so it should not be shared between multiple
* intro points. */
ed25519_public_key_t intro_auth_pk;
- /* (Only client rendezvous circuit) Introduction point encryption public
+ /** (Only client rendezvous circuit) Introduction point encryption public
* key. We keep it in the rendezvous identifier for the ntor handshake. */
curve25519_public_key_t intro_enc_pk;
- /* (Only rendezvous circuit) Rendezvous cookie sent from the client to the
+ /** (Only rendezvous circuit) Rendezvous cookie sent from the client to the
* service with an INTRODUCE1 cell and used by the service in an
* RENDEZVOUS1 cell. */
uint8_t rendezvous_cookie[HS_REND_COOKIE_LEN];
- /* (Only service rendezvous circuit) The HANDSHAKE_INFO needed in the
+ /** (Only service rendezvous circuit) The HANDSHAKE_INFO needed in the
* RENDEZVOUS1 cell of the service. The construction is as follows:
- * SERVER_PK [32 bytes]
- * AUTH_MAC [32 bytes]
+ *
+ * SERVER_PK [32 bytes]
+ * AUTH_MAC [32 bytes]
*/
uint8_t rendezvous_handshake_info[CURVE25519_PUBKEY_LEN + DIGEST256_LEN];
- /* (Only client rendezvous circuit) Client ephemeral keypair needed for the
+ /** (Only client rendezvous circuit) Client ephemeral keypair needed for the
* e2e encryption with the service. */
curve25519_keypair_t rendezvous_client_kp;
- /* (Only rendezvous circuit) The NTOR_KEY_SEED needed for key derivation for
+ /** (Only rendezvous circuit) The NTOR_KEY_SEED needed for key derivation for
* the e2e encryption with the client on the circuit. */
uint8_t rendezvous_ntor_key_seed[DIGEST256_LEN];
- /* (Only rendezvous circuit) Number of streams associated with this
+ /** (Only rendezvous circuit) Number of streams associated with this
* rendezvous circuit. We track this because there is a check on a maximum
* value. */
uint64_t num_rdv_streams;
} hs_ident_circuit_t;
-/* Client and service side directory connection identifier used for a
+/** Client and service side directory connection identifier used for a
* directory connection to identify which service is being queried. This is
* attached to a dir_connection_t. */
typedef struct hs_ident_dir_conn_t {
- /* The public key used to uniquely identify the service. It is the one found
+ /** The public key used to uniquely identify the service. It is the one found
* in the onion address. */
ed25519_public_key_t identity_pk;
- /* The blinded public key used to uniquely identify the descriptor that this
+ /** The blinded public key used to uniquely identify the descriptor that this
* directory connection identifier is for. Only used by the service-side code
* to fine control descriptor uploads. */
ed25519_public_key_t blinded_pk;
@@ -96,15 +97,15 @@ typedef struct hs_ident_dir_conn_t {
/* XXX: Client authorization. */
} hs_ident_dir_conn_t;
-/* Client and service side edge connection identifier used for an edge
+/** Client and service side edge connection identifier used for an edge
* connection to identify which service is being queried. This is attached to
* a edge_connection_t. */
typedef struct hs_ident_edge_conn_t {
- /* The public key used to uniquely identify the service. It is the one found
+ /** The public key used to uniquely identify the service. It is the one found
* in the onion address. */
ed25519_public_key_t identity_pk;
- /* The original virtual port that was used by the client to access the onion
+ /** The original virtual port that was used by the client to access the onion
* service, regardless of the internal port forwarding that might have
* happened on the service-side. */
uint16_t orig_virtual_port;
@@ -139,4 +140,3 @@ void hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident);
int hs_ident_intro_circ_is_valid(const hs_ident_circuit_t *ident);
#endif /* !defined(TOR_HS_IDENT_H) */
-
diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c
index fe8486b1a6..e282d1f1bd 100644
--- a/src/feature/hs/hs_intropoint.c
+++ b/src/feature/hs/hs_intropoint.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -147,7 +147,7 @@ verify_establish_intro_cell(const trn_cell_establish_intro_t *cell,
return 0;
}
-/* Send an INTRO_ESTABLISHED cell to <b>circ</b>. */
+/** Send an INTRO_ESTABLISHED cell to <b>circ</b>. */
MOCK_IMPL(int,
hs_intro_send_intro_established_cell,(or_circuit_t *circ))
{
@@ -182,7 +182,7 @@ hs_intro_send_intro_established_cell,(or_circuit_t *circ))
return ret;
}
-/* Validate the cell DoS extension parameters. Return true iff they've been
+/** Validate the cell DoS extension parameters. Return true iff they've been
* bound check and can be used. Else return false. See proposal 305 for
* details and reasons about this validation. */
STATIC bool
@@ -244,7 +244,7 @@ cell_dos_extension_parameters_are_valid(uint64_t intro2_rate_per_sec,
return ret;
}
-/* Parse the cell DoS extension and apply defenses on the given circuit if
+/** Parse the cell DoS extension and apply defenses on the given circuit if
* validation passes. If the cell extension is malformed or contains unusable
* values, the DoS defenses is disabled on the circuit. */
static void
@@ -321,7 +321,7 @@ handle_establish_intro_cell_dos_extension(
return;
}
-/* Parse every cell extension in the given ESTABLISH_INTRO cell. */
+/** Parse every cell extension in the given ESTABLISH_INTRO cell. */
static void
handle_establish_intro_cell_extensions(
const trn_cell_establish_intro_t *parsed_cell,
@@ -457,7 +457,7 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request,
return retval;
}
-/* Return True if circuit is suitable for being an intro circuit. */
+/** Return True if circuit is suitable for being an intro circuit. */
static int
circuit_is_suitable_intro_point(const or_circuit_t *circ,
const char *log_cell_type_str)
@@ -482,14 +482,14 @@ circuit_is_suitable_intro_point(const or_circuit_t *circ,
return 1;
}
-/* Return True if circuit is suitable for being service-side intro circuit. */
+/** Return True if circuit is suitable for being service-side intro circuit. */
int
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
+/** 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. */
int
hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
@@ -523,7 +523,7 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
return -1;
}
-/* Send an INTRODUCE_ACK cell onto the circuit <b>circ</b> with the status
+/** Send an INTRODUCE_ACK cell onto the circuit <b>circ</b> with the status
* value in <b>status</b>. Depending on the status, it can be ACK or a NACK.
* Return 0 on success else a negative value on error which will close the
* circuit. */
@@ -567,7 +567,7 @@ send_introduce_ack_cell(or_circuit_t *circ, uint16_t status)
return ret;
}
-/* Validate a parsed INTRODUCE1 <b>cell</b>. Return 0 if valid or else a
+/** Validate a parsed INTRODUCE1 <b>cell</b>. Return 0 if valid or else a
* negative value for an invalid cell that should be NACKed. */
STATIC int
validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell)
@@ -613,7 +613,7 @@ validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell)
return -1;
}
-/* We just received a non legacy INTRODUCE1 cell on <b>client_circ</b> with
+/** We just received a non legacy INTRODUCE1 cell on <b>client_circ</b> with
* the payload in <b>request</b> of size <b>request_len</b>. Return 0 if
* everything went well, or -1 if an error occurred. This function is in charge
* of sending back an INTRODUCE_ACK cell and will close client_circ on error.
@@ -712,7 +712,7 @@ 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
+/** 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)
@@ -729,7 +729,7 @@ introduce1_cell_is_legacy(const uint8_t *request)
return 0;
}
-/* Return true iff the circuit <b>circ</b> is suitable for receiving an
+/** Return true iff the circuit <b>circ</b> is suitable for receiving an
* INTRODUCE1 cell. */
STATIC int
circuit_is_suitable_for_introduce1(const or_circuit_t *circ)
@@ -760,7 +760,7 @@ circuit_is_suitable_for_introduce1(const or_circuit_t *circ)
return 1;
}
-/* We just received an INTRODUCE1 cell on <b>circ</b>. Figure out which type
+/** We just received an INTRODUCE1 cell on <b>circ</b>. Figure out which type
* it is and pass it to the appropriate handler. Return 0 on success else a
* negative value and the circuit is closed. */
int
@@ -804,8 +804,8 @@ hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request,
return -1;
}
-/* Clear memory allocated by the given intropoint object ip (but don't free the
- * object itself). */
+/** Clear memory allocated by the given intropoint object ip (but don't free
+ * the object itself). */
void
hs_intropoint_clear(hs_intropoint_t *ip)
{
diff --git a/src/feature/hs/hs_intropoint.h b/src/feature/hs/hs_intropoint.h
index 94ebf021e4..8b2b9892b3 100644
--- a/src/feature/hs/hs_intropoint.h
+++ b/src/feature/hs/hs_intropoint.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,15 +12,15 @@
#include "lib/crypt_ops/crypto_curve25519.h"
#include "feature/nodelist/torcert.h"
-/* Object containing introduction point common data between the service and
+/** Object containing introduction point common data between the service and
* the client side. */
typedef struct hs_intropoint_t {
- /* Does this intro point only supports legacy ID ?. */
+ /** Does this intro point only supports legacy ID ?. */
unsigned int is_only_legacy : 1;
- /* Authentication key certificate from the descriptor. */
+ /** Authentication key certificate from the descriptor. */
tor_cert_t *auth_key_cert;
- /* A list of link specifier. */
+ /** A list of link specifier. */
smartlist_t *link_specifiers;
} hs_intropoint_t;
@@ -64,4 +64,3 @@ STATIC bool cell_dos_extension_parameters_are_valid(
#endif /* defined(HS_INTROPOINT_PRIVATE) */
#endif /* !defined(TOR_HS_INTRO_H) */
-
diff --git a/src/feature/hs/hs_ob.c b/src/feature/hs/hs_ob.c
new file mode 100644
index 0000000000..9499c28d20
--- /dev/null
+++ b/src/feature/hs/hs_ob.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_ob.c
+ * \brief Implement Onion Balance specific code.
+ **/
+
+#define HS_OB_PRIVATE
+
+#include "feature/hs/hs_service.h"
+
+#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/networkstatus_st.h"
+
+#include "lib/confmgt/confmgt.h"
+#include "lib/encoding/confline.h"
+
+#include "feature/hs/hs_ob.h"
+
+/* Options config magic number. */
+#define OB_OPTIONS_MAGIC 0x631DE7EA
+
+/* Helper macros. */
+#define VAR(varname, conftype, member, initvalue) \
+ CONFIG_VAR_ETYPE(ob_options_t, varname, conftype, member, 0, initvalue)
+#define V(member,conftype,initvalue) \
+ VAR(#member, conftype, member, initvalue)
+
+/* Dummy instance of ob_options_t, used for type-checking its members with
+ * CONF_CHECK_VAR_TYPE. */
+DUMMY_TYPECHECK_INSTANCE(ob_options_t);
+
+/* Array of variables for the config file options. */
+static const config_var_t config_vars[] = {
+ V(MasterOnionAddress, LINELIST, NULL),
+
+ END_OF_CONFIG_VARS
+};
+
+/* "Extra" variable in the state that receives lines we can't parse. This
+ * lets us preserve options from versions of Tor newer than us. */
+static const struct_member_t config_extra_vars = {
+ .name = "__extra",
+ .type = CONFIG_TYPE_LINELIST,
+ .offset = offsetof(ob_options_t, ExtraLines),
+};
+
+/* Configuration format of ob_options_t. */
+static const config_format_t config_format = {
+ .size = sizeof(ob_options_t),
+ .magic = {
+ "ob_options_t",
+ OB_OPTIONS_MAGIC,
+ offsetof(ob_options_t, magic_),
+ },
+ .vars = config_vars,
+ .extra = &config_extra_vars,
+};
+
+/* Global configuration manager for the config file. */
+static config_mgr_t *config_options_mgr = NULL;
+
+/* Return the configuration manager for the config file. */
+static const config_mgr_t *
+get_config_options_mgr(void)
+{
+ if (PREDICT_UNLIKELY(config_options_mgr == NULL)) {
+ config_options_mgr = config_mgr_new(&config_format);
+ config_mgr_freeze(config_options_mgr);
+ }
+ return config_options_mgr;
+}
+
+#define ob_option_free(val) \
+ FREE_AND_NULL(ob_options_t, ob_option_free_, (val))
+
+/** Helper: Free a config options object. */
+static void
+ob_option_free_(ob_options_t *opts)
+{
+ if (opts == NULL) {
+ return;
+ }
+ config_free(get_config_options_mgr(), opts);
+}
+
+/** Return an allocated config options object. */
+static ob_options_t *
+ob_option_new(void)
+{
+ ob_options_t *opts = config_new(get_config_options_mgr());
+ config_init(get_config_options_mgr(), opts);
+ return opts;
+}
+
+/** Helper function: From the configuration line value which is an onion
+ * address with the ".onion" extension, find the public key and put it in
+ * pkey_out.
+ *
+ * On success, true is returned. Else, false and pkey is untouched. */
+static bool
+get_onion_public_key(const char *value, ed25519_public_key_t *pkey_out)
+{
+ char address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+ tor_assert(value);
+ tor_assert(pkey_out);
+
+ if (strcmpend(value, ".onion")) {
+ /* Not a .onion extension, bad format. */
+ return false;
+ }
+
+ /* Length validation. The -1 is because sizeof() counts the NUL byte. */
+ if (strlen(value) >
+ (HS_SERVICE_ADDR_LEN_BASE32 + sizeof(".onion") - 1)) {
+ /* Too long, bad format. */
+ return false;
+ }
+
+ /* We don't want the .onion so we add 2 because size - 1 is copied with
+ * strlcpy() in order to accomodate the NUL byte and sizeof() counts the NUL
+ * byte so we need to remove them from the equation. */
+ strlcpy(address, value, strlen(value) - sizeof(".onion") + 2);
+
+ if (hs_parse_address_no_log(address, pkey_out, NULL, NULL, NULL) < 0) {
+ return false;
+ }
+
+ /* Success. */
+ return true;
+}
+
+/** Parse the given ob options in opts and set the service config object
+ * accordingly.
+ *
+ * Return 1 on success else 0. */
+static int
+ob_option_parse(hs_service_config_t *config, const ob_options_t *opts)
+{
+ int ret = 0;
+ config_line_t *line;
+
+ tor_assert(config);
+ tor_assert(opts);
+
+ for (line = opts->MasterOnionAddress; line; line = line->next) {
+ /* Allocate config list if need be. */
+ if (!config->ob_master_pubkeys) {
+ config->ob_master_pubkeys = smartlist_new();
+ }
+ ed25519_public_key_t *pubkey = tor_malloc_zero(sizeof(*pubkey));
+
+ if (!get_onion_public_key(line->value, pubkey)) {
+ log_warn(LD_REND, "OnionBalance: MasterOnionAddress %s is invalid",
+ line->value);
+ tor_free(pubkey);
+ goto end;
+ }
+ smartlist_add(config->ob_master_pubkeys, pubkey);
+ log_notice(LD_REND, "OnionBalance: MasterOnionAddress %s registered",
+ line->value);
+ }
+ /* Success. */
+ ret = 1;
+
+ end:
+ /* No keys added, we free the list since no list means no onion balance
+ * support for this tor instance. */
+ if (smartlist_len(config->ob_master_pubkeys) == 0) {
+ smartlist_free(config->ob_master_pubkeys);
+ }
+ return ret;
+}
+
+/** For the given master public key and time period, compute the subcredential
+ * and put them into subcredential. The subcredential parameter needs to be at
+ * least DIGEST256_LEN in size. */
+static void
+build_subcredential(const ed25519_public_key_t *pkey, uint64_t tp,
+ hs_subcredential_t *subcredential)
+{
+ ed25519_public_key_t blinded_pubkey;
+
+ tor_assert(pkey);
+ tor_assert(subcredential);
+
+ hs_build_blinded_pubkey(pkey, NULL, 0, tp, &blinded_pubkey);
+ hs_get_subcredential(pkey, &blinded_pubkey, subcredential);
+}
+
+/*
+ * Public API.
+ */
+
+/** Return true iff the given service is configured as an onion balance
+ * instance. To satisfy that condition, there must at least be one master
+ * ed25519 public key configured. */
+bool
+hs_ob_service_is_instance(const hs_service_t *service)
+{
+ if (BUG(service == NULL)) {
+ return false;
+ }
+
+ /* No list, we are not an instance. */
+ if (!service->config.ob_master_pubkeys) {
+ return false;
+ }
+
+ return smartlist_len(service->config.ob_master_pubkeys) > 0;
+}
+
+/** Read and parse the config file at fname on disk. The service config object
+ * is populated with the options if any.
+ *
+ * Return 1 on success else 0. This is to follow the "ok" convention in
+ * hs_config.c. */
+int
+hs_ob_parse_config_file(hs_service_config_t *config)
+{
+ static const char *fname = "ob_config";
+ int ret = 0;
+ char *content = NULL, *errmsg = NULL, *config_file_path = NULL;
+ ob_options_t *options = NULL;
+ config_line_t *lines = NULL;
+
+ tor_assert(config);
+
+ /* Read file from disk. */
+ config_file_path = hs_path_from_filename(config->directory_path, fname);
+ content = read_file_to_str(config_file_path, 0, NULL);
+ if (!content) {
+ log_warn(LD_FS, "OnionBalance: Unable to read config file %s",
+ escaped(config_file_path));
+ goto end;
+ }
+
+ /* Parse lines. */
+ if (config_get_lines(content, &lines, 0) < 0) {
+ goto end;
+ }
+
+ options = ob_option_new();
+ config_assign(get_config_options_mgr(), options, lines, 0, &errmsg);
+ if (errmsg) {
+ log_warn(LD_REND, "OnionBalance: Unable to parse config file: %s",
+ errmsg);
+ tor_free(errmsg);
+ goto end;
+ }
+
+ /* Parse the options and set the service config object with the details. */
+ ret = ob_option_parse(config, options);
+
+ end:
+ config_free_lines(lines);
+ ob_option_free(options);
+ tor_free(content);
+ tor_free(config_file_path);
+ return ret;
+}
+
+/** Compute all possible subcredentials for every onion master key in the given
+ * service config object. subcredentials_out is allocated and set as an
+ * continous array containing all possible values.
+ *
+ * On success, return the number of subcredential put in the array which will
+ * correspond to an arry of size: n * DIGEST256_LEN where DIGEST256_LEN is the
+ * length of a single subcredential.
+ *
+ * If the given configuration object has no OB master keys configured, 0 is
+ * returned and subcredentials_out is set to NULL.
+ *
+ * Otherwise, this can't fail. */
+STATIC size_t
+compute_subcredentials(const hs_service_t *service,
+ hs_subcredential_t **subcredentials_out)
+{
+ unsigned int num_pkeys, idx = 0;
+ hs_subcredential_t *subcreds = NULL;
+ const int steps[3] = {0, -1, 1};
+ const unsigned int num_steps = ARRAY_LENGTH(steps);
+ const uint64_t tp = hs_get_time_period_num(0);
+
+ tor_assert(service);
+ tor_assert(subcredentials_out);
+ /* Our caller has checked these too */
+ tor_assert(service->desc_current);
+ tor_assert(service->desc_next);
+
+ /* Make sure we are an OB instance, or bail out. */
+ num_pkeys = smartlist_len(service->config.ob_master_pubkeys);
+ if (!num_pkeys) {
+ *subcredentials_out = NULL;
+ return 0;
+ }
+
+ /* Time to build all the subcredentials for each time period: two for each
+ * instance descriptor plus three for the onionbalance frontend service: the
+ * previous one (-1), the current one (0) and the next one (1) for each
+ * configured key in order to accomodate client and service consensus skew.
+ *
+ * If the client consensus after_time is at 23:00 but the service one is at
+ * 01:00, the client will be using the previous time period where the
+ * service will think it is the client next time period. Thus why we have
+ * to try them all.
+ *
+ * The normal use case works because the service gets the descriptor object
+ * that corresponds to the intro point's request, and because each
+ * descriptor corresponds to a specific subcredential, we get the right
+ * subcredential out of it, and use that to do the decryption.
+ *
+ * As a slight optimization, statistically, the current time period (0) will
+ * be the one to work first so we'll put them first in the array to maximize
+ * our chance of success. */
+
+ /* We use a flat array, not a smartlist_t, in order to minimize memory
+ * allocation.
+ *
+ * Size of array is: length of a single subcredential multiplied by the
+ * number of time period we need to compute and finally multiplied by the
+ * total number of keys we are about to process. In other words, for each
+ * key, we allocate 3 subcredential slots. Then in the end we also add two
+ * subcredentials for this instance's active descriptors. */
+ subcreds =
+ tor_calloc((num_steps * num_pkeys) + 2, sizeof(hs_subcredential_t));
+
+ /* For each master pubkey we add 3 subcredentials: */
+ for (unsigned int i = 0; i < num_steps; i++) {
+ SMARTLIST_FOREACH_BEGIN(service->config.ob_master_pubkeys,
+ const ed25519_public_key_t *, pkey) {
+ build_subcredential(pkey, tp + steps[i], &subcreds[idx]);
+ idx++;
+ } SMARTLIST_FOREACH_END(pkey);
+ }
+
+ /* And then in the end we add the two subcredentials of the current active
+ * instance descriptors */
+ memcpy(&subcreds[idx++], &service->desc_current->desc->subcredential,
+ sizeof(hs_subcredential_t));
+ memcpy(&subcreds[idx++], &service->desc_next->desc->subcredential,
+ sizeof(hs_subcredential_t));
+
+ log_info(LD_REND, "Refreshing %u onionbalance keys (TP #%d).",
+ idx, (int)tp);
+
+ *subcredentials_out = subcreds;
+ return idx;
+}
+
+/**
+ * If we are an Onionbalance instance, refresh our keys.
+ *
+ * If we are not an Onionbalance instance or we are not ready to do so, this
+ * is a NOP.
+ *
+ * This function is called everytime we build a new descriptor. That's because
+ * we want our Onionbalance keys to always use up-to-date subcredentials both
+ * for the instance (ourselves) and for the onionbalance frontend.
+ */
+void
+hs_ob_refresh_keys(hs_service_t *service)
+{
+ hs_subcredential_t *ob_subcreds = NULL;
+ size_t num_subcreds;
+
+ tor_assert(service);
+
+ /* Don't do any of this if we are not configured as an OB instance */
+ if (!hs_ob_service_is_instance(service)) {
+ return;
+ }
+
+ /* We need both service descriptors created to make onionbalance keys.
+ *
+ * That's because we fetch our own (the instance's) subcredentials from our
+ * own descriptors which should always include the latest subcredentials that
+ * clients would use.
+ *
+ * This function is called with each descriptor build, so we will be
+ * eventually be called when both descriptors are created. */
+ if (!service->desc_current || !service->desc_next) {
+ return;
+ }
+
+ /* Get a new set of subcreds */
+ num_subcreds = compute_subcredentials(service, &ob_subcreds);
+ if (BUG(!num_subcreds)) {
+ return;
+ }
+
+ /* Delete old subcredentials if any */
+ if (service->state.ob_subcreds) {
+ tor_free(service->state.ob_subcreds);
+ }
+
+ service->state.ob_subcreds = ob_subcreds;
+ service->state.n_ob_subcreds = num_subcreds;
+}
+
+/** Free any memory allocated by the onionblance subsystem. */
+void
+hs_ob_free_all(void)
+{
+ config_mgr_free(config_options_mgr);
+}
diff --git a/src/feature/hs/hs_ob.h b/src/feature/hs/hs_ob.h
new file mode 100644
index 0000000000..d6e6e73a84
--- /dev/null
+++ b/src/feature/hs/hs_ob.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_ob.h
+ * \brief Header file for the specific code for onion balance.
+ **/
+
+#ifndef TOR_HS_OB_H
+#define TOR_HS_OB_H
+
+#include "feature/hs/hs_service.h"
+
+bool hs_ob_service_is_instance(const hs_service_t *service);
+
+int hs_ob_parse_config_file(hs_service_config_t *config);
+
+struct hs_subcredential_t;
+
+void hs_ob_free_all(void);
+
+void hs_ob_refresh_keys(hs_service_t *service);
+
+#ifdef HS_OB_PRIVATE
+
+STATIC size_t compute_subcredentials(const hs_service_t *service,
+ struct hs_subcredential_t **subcredentials);
+
+typedef struct ob_options_t {
+ /** Magic number to identify the structure in memory. */
+ uint32_t magic_;
+ /** Master Onion Address(es). */
+ struct config_line_t *MasterOnionAddress;
+ /** Extra Lines for configuration we might not know. */
+ struct config_line_t *ExtraLines;
+} ob_options_t;
+
+#endif /* defined(HS_OB_PRIVATE) */
+
+#endif /* !defined(TOR_HS_OB_H) */
diff --git a/src/feature/hs/hs_options.inc b/src/feature/hs/hs_options.inc
new file mode 100644
index 0000000000..1a1444fd05
--- /dev/null
+++ b/src/feature/hs/hs_options.inc
@@ -0,0 +1,36 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dirauth_options.inc
+ * @brief Declare configuration options for a single hidden service.
+ *
+ * Note that this options file behaves differently from most, since it
+ * is not used directly by the options manager. Instead, it is applied to
+ * a group of hidden service options starting with a HiddenServiceDir and
+ * extending up to the next HiddenServiceDir.
+ **/
+
+/** Holds configuration for a single hidden service. */
+BEGIN_CONF_STRUCT(hs_opts_t)
+
+CONF_VAR(HiddenServiceDir, FILENAME, 0, NULL)
+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")
+CONF_VAR(HiddenServiceNumIntroductionPoints, POSINT, 0, "3")
+CONF_VAR(HiddenServiceExportCircuitID, STRING, 0, NULL)
+CONF_VAR(HiddenServiceEnableIntroDoSDefense, BOOL, 0, "0")
+CONF_VAR(HiddenServiceEnableIntroDoSRatePerSec, POSINT, 0, "25")
+CONF_VAR(HiddenServiceEnableIntroDoSBurstPerSec, POSINT, 0, "200")
+CONF_VAR(HiddenServiceOnionBalanceInstance, BOOL, 0, "0")
+
+END_CONF_STRUCT(hs_opts_t)
diff --git a/src/feature/hs/hs_opts_st.h b/src/feature/hs/hs_opts_st.h
new file mode 100644
index 0000000000..279f0d6da6
--- /dev/null
+++ b/src/feature/hs/hs_opts_st.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2001 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 dirauth_options_st.h
+ * @brief Structure hs_opts_t to hold options for a single hidden service.
+ **/
+
+#ifndef TOR_FEATURE_HS_HS_OPTS_ST_H
+#define TOR_FEATURE_HS_HS_OPTS_ST_H
+
+#include "lib/conf/confdecl.h"
+#define CONF_CONTEXT STRUCT
+#include "feature/hs/hs_options.inc"
+#undef CONF_CONTEXT
+
+/**
+ * An hs_opts_t holds the parsed options for a single HS configuration
+ * section.
+ *
+ * This name ends with 'opts' instead of 'options' to signal that it is not
+ * handled directly by the or_options_t configuration manager, but that
+ * first we partition the "HiddenService*" options by section.
+ **/
+typedef struct hs_opts_t hs_opts_t;
+
+#endif /* !defined(TOR_FEATURE_HS_HS_OPTS_ST_H) */
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index 17ac4fa4a9..a42879a48f 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -30,7 +30,6 @@
#include "feature/rend/rendservice.h"
#include "lib/crypt_ops/crypto_ope.h"
#include "lib/crypt_ops/crypto_rand.h"
-#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/hs/hs_circuit.h"
@@ -42,6 +41,7 @@
#include "feature/hs/hs_intropoint.h"
#include "feature/hs/hs_service.h"
#include "feature/hs/hs_stats.h"
+#include "feature/hs/hs_ob.h"
#include "feature/dircommon/dir_connection_st.h"
#include "core/or/edge_connection_st.h"
@@ -67,7 +67,8 @@
#include <unistd.h>
#endif
-/* Helper macro. Iterate over every service in the global map. The var is the
+#ifndef COCCI
+/** Helper macro. Iterate over every service in the global map. The var is the
* name of the service pointer. */
#define FOR_EACH_SERVICE_BEGIN(var) \
STMT_BEGIN \
@@ -76,7 +77,7 @@
var = *var##_iter;
#define FOR_EACH_SERVICE_END } STMT_END ;
-/* Helper macro. Iterate over both current and previous descriptor of a
+/** Helper macro. Iterate over both current and previous descriptor of a
* service. The var is the name of the descriptor pointer. This macro skips
* any descriptor object of the service that is NULL. */
#define FOR_EACH_DESCRIPTOR_BEGIN(service, var) \
@@ -88,6 +89,7 @@
(var = service->desc_next); \
if (var == NULL) continue;
#define FOR_EACH_DESCRIPTOR_END } STMT_END ;
+#endif /* !defined(COCCI) */
/* Onion service directory file names. */
static const char fname_keyfile_prefix[] = "hs_ed25519";
@@ -95,7 +97,7 @@ static const char dname_client_pubkeys[] = "authorized_clients";
static const char fname_hostname[] = "hostname";
static const char address_tld[] = "onion";
-/* Staging list of service object. When configuring service, we add them to
+/** Staging list of service object. When configuring service, we add them to
* this list considered a staging area and they will get added to our global
* map once the keys have been loaded. These two steps are separated because
* loading keys requires that we are an actual running tor process. */
@@ -118,7 +120,7 @@ static int service_encode_descriptor(const hs_service_t *service,
const ed25519_keypair_t *signing_kp,
char **encoded_out);
-/* Helper: Function to compare two objects in the service map. Return 1 if the
+/** Helper: Function to compare two objects in the service map. Return 1 if the
* two service have the same master public identity key. */
static inline int
hs_service_ht_eq(const hs_service_t *first, const hs_service_t *second)
@@ -130,7 +132,7 @@ hs_service_ht_eq(const hs_service_t *first, const hs_service_t *second)
&second->keys.identity_pk);
}
-/* Helper: Function for the service hash table code below. The key used is the
+/** Helper: Function for the service hash table code below. The key used is the
* master public identity key which is ultimately the onion address. */
static inline unsigned int
hs_service_ht_hash(const hs_service_t *service)
@@ -140,7 +142,7 @@ hs_service_ht_hash(const hs_service_t *service)
sizeof(service->keys.identity_pk.pubkey));
}
-/* This is _the_ global hash map of hidden services which indexed the service
+/** This is _the_ global hash map of hidden services which indexed the service
* contained in it by master public identity key which is roughly the onion
* address of the service. */
static struct hs_service_ht *hs_service_map;
@@ -150,13 +152,13 @@ HT_PROTOTYPE(hs_service_ht, /* Name of hashtable. */
hs_service_t, /* Object contained in the map. */
hs_service_node, /* The name of the HT_ENTRY member. */
hs_service_ht_hash, /* Hashing function. */
- hs_service_ht_eq) /* Compare function for objects. */
+ hs_service_ht_eq); /* Compare function for objects. */
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_)
+ 0.6, tor_reallocarray, tor_free_);
-/* Query the given service map with a public key and return a service object
+/** Query the given service map with a public key and return a service object
* if found else NULL. It is also possible to set a directory path in the
* search query. If pk is NULL, then it will be set to zero indicating the
* hash table to compare the directory path instead. */
@@ -171,7 +173,7 @@ find_service(hs_service_ht *map, const ed25519_public_key_t *pk)
return HT_FIND(hs_service_ht, map, &dummy_service);
}
-/* Register the given service in the given map. If the service already exists
+/** Register the given service in the given map. If the service already exists
* in the map, -1 is returned. On success, 0 is returned and the service
* ownership has been transferred to the global map. */
STATIC int
@@ -196,7 +198,7 @@ register_service(hs_service_ht *map, hs_service_t *service)
return 0;
}
-/* Remove a given service from the given map. If service is NULL or the
+/** Remove a given service from the given map. If service is NULL or the
* service key is unset, return gracefully. */
STATIC void
remove_service(hs_service_ht *map, hs_service_t *service)
@@ -226,7 +228,7 @@ remove_service(hs_service_ht *map, hs_service_t *service)
}
}
-/* Set the default values for a service configuration object <b>c</b>. */
+/** Set the default values for a service configuration object <b>c</b>. */
static void
set_service_default_config(hs_service_config_t *c,
const or_options_t *options)
@@ -247,7 +249,7 @@ set_service_default_config(hs_service_config_t *c,
c->intro_dos_burst_per_sec = HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT;
}
-/* From a service configuration object config, clear everything from it
+/** From a service configuration object config, clear everything from it
* meaning free allocated pointers and reset the values. */
STATIC void
service_clear_config(hs_service_config_t *config)
@@ -266,10 +268,15 @@ service_clear_config(hs_service_config_t *config)
service_authorized_client_free(p));
smartlist_free(config->clients);
}
+ if (config->ob_master_pubkeys) {
+ SMARTLIST_FOREACH(config->ob_master_pubkeys, ed25519_public_key_t *, k,
+ tor_free(k));
+ smartlist_free(config->ob_master_pubkeys);
+ }
memset(config, 0, sizeof(*config));
}
-/* Helper function to return a human readable description of the given intro
+/** Helper function to return a human readable description of the given intro
* point object.
*
* This function is not thread-safe. Each call to this invalidates the
@@ -301,7 +308,7 @@ describe_intro_point(const hs_service_intro_point_t *ip)
return buf;
}
-/* Return the lower bound of maximum INTRODUCE2 cells per circuit before we
+/** Return the lower bound of maximum INTRODUCE2 cells per circuit before we
* rotate intro point (defined by a consensus parameter or the default
* value). */
static int32_t
@@ -314,7 +321,7 @@ get_intro_point_min_introduce2(void)
0, INT32_MAX);
}
-/* Return the upper bound of maximum INTRODUCE2 cells per circuit before we
+/** Return the upper bound of maximum INTRODUCE2 cells per circuit before we
* rotate intro point (defined by a consensus parameter or the default
* value). */
static int32_t
@@ -327,8 +334,8 @@ get_intro_point_max_introduce2(void)
0, INT32_MAX);
}
-/* Return the minimum lifetime in seconds of an introduction point defined by a
- * consensus parameter or the default value. */
+/** Return the minimum lifetime in seconds of an introduction point defined by
+ * a consensus parameter or the default value. */
static int32_t
get_intro_point_min_lifetime(void)
{
@@ -344,8 +351,8 @@ get_intro_point_min_lifetime(void)
0, INT32_MAX);
}
-/* Return the maximum lifetime in seconds of an introduction point defined by a
- * consensus parameter or the default value. */
+/** Return the maximum lifetime in seconds of an introduction point defined by
+ * a consensus parameter or the default value. */
static int32_t
get_intro_point_max_lifetime(void)
{
@@ -361,7 +368,7 @@ get_intro_point_max_lifetime(void)
0, INT32_MAX);
}
-/* Return the number of extra introduction point defined by a consensus
+/** Return the number of extra introduction point defined by a consensus
* parameter or the default value. */
static int32_t
get_intro_point_num_extra(void)
@@ -372,7 +379,7 @@ get_intro_point_num_extra(void)
NUM_INTRO_POINTS_EXTRA, 0, 128);
}
-/* Helper: Function that needs to return 1 for the HT for each loop which
+/** Helper: Function that needs to return 1 for the HT for each loop which
* frees every service in an hash map. */
static int
ht_free_service_(struct hs_service_t *service, void *data)
@@ -384,7 +391,7 @@ ht_free_service_(struct hs_service_t *service, void *data)
return 1;
}
-/* Free every service that can be found in the global map. Once done, clear
+/** Free every service that can be found in the global map. Once done, clear
* and free the global map. */
static void
service_free_all(void)
@@ -406,7 +413,7 @@ service_free_all(void)
}
}
-/* Free a given service intro point object. */
+/** Free a given service intro point object. */
STATIC void
service_intro_point_free_(hs_service_intro_point_t *ip)
{
@@ -421,7 +428,7 @@ service_intro_point_free_(hs_service_intro_point_t *ip)
tor_free(ip);
}
-/* Helper: free an hs_service_intro_point_t object. This function is used by
+/** Helper: free an hs_service_intro_point_t object. This function is used by
* digest256map_free() which requires a void * pointer. */
static void
service_intro_point_free_void(void *obj)
@@ -429,7 +436,7 @@ service_intro_point_free_void(void *obj)
service_intro_point_free_(obj);
}
-/* Return a newly allocated service intro point and fully initialized from the
+/** Return a newly allocated service intro point and fully initialized from the
* given node_t node, if non NULL.
*
* If node is NULL, returns a hs_service_intro_point_t with an empty link
@@ -507,7 +514,7 @@ service_intro_point_new(const node_t *node)
return NULL;
}
-/* Add the given intro point object to the given intro point map. The intro
+/** Add the given intro point object to the given intro point map. The intro
* point MUST have its RSA encryption key set if this is a legacy type or the
* authentication key set otherwise. */
STATIC void
@@ -523,7 +530,7 @@ service_intro_point_add(digest256map_t *map, hs_service_intro_point_t *ip)
tor_assert_nonfatal(!old_ip_entry);
}
-/* For a given service, remove the intro point from that service's descriptors
+/** For a given service, remove the intro point from that service's descriptors
* (check both current and next descriptor) */
STATIC void
service_intro_point_remove(const hs_service_t *service,
@@ -541,7 +548,7 @@ service_intro_point_remove(const hs_service_t *service,
} FOR_EACH_DESCRIPTOR_END;
}
-/* For a given service and authentication key, return the intro point or NULL
+/** For a given service and authentication key, return the intro point or NULL
* if not found. This will check both descriptors in the service. */
STATIC hs_service_intro_point_t *
service_intro_point_find(const hs_service_t *service,
@@ -572,7 +579,7 @@ service_intro_point_find(const hs_service_t *service,
return ip;
}
-/* For a given service and intro point, return the descriptor for which the
+/** For a given service and intro point, return the descriptor for which the
* intro point is assigned to. NULL is returned if not found. */
STATIC hs_service_descriptor_t *
service_desc_find_by_intro(const hs_service_t *service,
@@ -594,7 +601,7 @@ service_desc_find_by_intro(const hs_service_t *service,
return descp;
}
-/* From a circuit identifier, get all the possible objects associated with the
+/** From a circuit identifier, get all the possible objects associated with the
* ident. If not NULL, service, ip or desc are set if the object can be found.
* They are untouched if they can't be found.
*
@@ -627,7 +634,7 @@ get_objects_from_ident(const hs_ident_circuit_t *ident,
}
}
-/* From a given intro point, return the first link specifier of type
+/** From a given intro point, return the first link specifier of type
* encountered in the link specifier list. Return NULL if it can't be found.
*
* The caller does NOT have ownership of the object, the intro point does. */
@@ -650,7 +657,7 @@ get_link_spec_by_type(const hs_service_intro_point_t *ip, uint8_t type)
return lnk_spec;
}
-/* Given a service intro point, return the node_t associated to it. This can
+/** Given a service intro point, return the node_t associated to it. This can
* return NULL if the given intro point has no legacy ID or if the node can't
* be found in the consensus. */
STATIC const node_t *
@@ -669,7 +676,7 @@ get_node_from_intro_point(const hs_service_intro_point_t *ip)
(const char *) link_specifier_getconstarray_un_legacy_id(ls));
}
-/* Given a service intro point, return the extend_info_t for it. This can
+/** Given a service intro point, return the extend_info_t for it. This can
* return NULL if the node can't be found for the intro point or the extend
* info can't be created for the found node. If direct_conn is set, the extend
* info is validated on if we can connect directly. */
@@ -698,10 +705,10 @@ get_extend_info_from_intro_point(const hs_service_intro_point_t *ip,
return info;
}
-/* Return the number of introduction points that are established for the
+/** Return the number of introduction points that are established for the
* given descriptor. */
-static unsigned int
-count_desc_circuit_established(const hs_service_descriptor_t *desc)
+MOCK_IMPL(STATIC unsigned int,
+count_desc_circuit_established, (const hs_service_descriptor_t *desc))
{
unsigned int count = 0;
@@ -709,13 +716,13 @@ count_desc_circuit_established(const hs_service_descriptor_t *desc)
DIGEST256MAP_FOREACH(desc->intro_points.map, key,
const hs_service_intro_point_t *, ip) {
- count += ip->circuit_established;
+ count += !!hs_circ_service_get_established_intro_circ(ip);
} DIGEST256MAP_FOREACH_END;
return count;
}
-/* For a given service and descriptor of that service, close all active
+/** For a given service and descriptor of that service, close all active
* directory connections. */
static void
close_directory_connections(const hs_service_t *service,
@@ -750,7 +757,7 @@ close_directory_connections(const hs_service_t *service,
smartlist_free(dir_conns);
}
-/* Close all rendezvous circuits for the given service. */
+/** Close all rendezvous circuits for the given service. */
static void
close_service_rp_circuits(hs_service_t *service)
{
@@ -780,7 +787,7 @@ close_service_rp_circuits(hs_service_t *service)
}
}
-/* Close the circuit(s) for the given map of introduction points. */
+/** Close the circuit(s) for the given map of introduction points. */
static void
close_intro_circuits(hs_service_intropoints_t *intro_points)
{
@@ -798,7 +805,7 @@ close_intro_circuits(hs_service_intropoints_t *intro_points)
} DIGEST256MAP_FOREACH_END;
}
-/* Close all introduction circuits for the given service. */
+/** Close all introduction circuits for the given service. */
static void
close_service_intro_circuits(hs_service_t *service)
{
@@ -809,7 +816,7 @@ close_service_intro_circuits(hs_service_t *service)
} FOR_EACH_DESCRIPTOR_END;
}
-/* Close any circuits related to the given service. */
+/** Close any circuits related to the given service. */
static void
close_service_circuits(hs_service_t *service)
{
@@ -825,7 +832,7 @@ close_service_circuits(hs_service_t *service)
close_service_rp_circuits(service);
}
-/* Move every ephemeral services from the src service map to the dst service
+/** Move every ephemeral services from the src service map to the dst service
* map. It is possible that a service can't be register to the dst map which
* won't stop the process of moving them all but will trigger a log warn. */
static void
@@ -855,7 +862,7 @@ move_ephemeral_services(hs_service_ht *src, hs_service_ht *dst)
}
}
-/* Return a const string of the directory path escaped. If this is an
+/** Return a const string of the directory path escaped. If this is an
* ephemeral service, it returns "[EPHEMERAL]". This can only be called from
* the main thread because escaped() uses a static variable. */
static const char *
@@ -883,13 +890,21 @@ move_hs_state(hs_service_t *src_service, hs_service_t *dst_service)
if (dst->replay_cache_rend_cookie != NULL) {
replaycache_free(dst->replay_cache_rend_cookie);
}
+
dst->replay_cache_rend_cookie = src->replay_cache_rend_cookie;
+ src->replay_cache_rend_cookie = NULL; /* steal pointer reference */
+
dst->next_rotation_time = src->next_rotation_time;
- src->replay_cache_rend_cookie = NULL; /* steal pointer reference */
+ if (src->ob_subcreds) {
+ dst->ob_subcreds = src->ob_subcreds;
+ dst->n_ob_subcreds = src->n_ob_subcreds;
+
+ src->ob_subcreds = NULL; /* steal pointer reference */
+ }
}
-/* Register services that are in the staging list. Once this function returns,
+/** Register services that are in the staging list. Once this function returns,
* the global service map will be set with the right content and all non
* surviving services will be cleaned up. */
static void
@@ -957,7 +972,7 @@ register_all_services(void)
hs_service_map_has_changed();
}
-/* Write the onion address of a given service to the given filename fname_ in
+/** Write the onion address of a given service to the given filename fname_ in
* the service directory. Return 0 on success else -1 on error. */
STATIC int
write_address_to_file(const hs_service_t *service, const char *fname_)
@@ -998,7 +1013,7 @@ write_address_to_file(const hs_service_t *service, const char *fname_)
return ret;
}
-/* Load and/or generate private keys for the given service. On success, the
+/** Load and/or generate private keys for the given service. On success, the
* hostname file will be written to disk along with the master private key iff
* the service is not configured for offline keys. Return 0 on success else -1
* on failure. */
@@ -1074,7 +1089,7 @@ load_service_keys(hs_service_t *service)
return ret;
}
-/* Check if the client file name is valid or not. Return 1 if valid,
+/** Check if the client file name is valid or not. Return 1 if valid,
* otherwise return 0. */
STATIC int
client_filename_is_valid(const char *filename)
@@ -1096,7 +1111,7 @@ client_filename_is_valid(const char *filename)
return ret;
}
-/* Parse an authorized client from a string. The format of a client string
+/** Parse an authorized client from a string. The format of a client string
* looks like (see rend-spec-v3.txt):
*
* <auth-type>:<key-type>:<base32-encoded-public-key>
@@ -1178,7 +1193,7 @@ parse_authorized_client(const char *client_key_str)
return client;
}
-/* Load all the client public keys for the given service. Return 0 on
+/** Load all the client public keys for the given service. Return 0 on
* success else -1 on failure. */
static int
load_client_keys(hs_service_t *service)
@@ -1281,6 +1296,7 @@ load_client_keys(hs_service_t *service)
return ret;
}
+/** Release all storage held in <b>client</b>. */
STATIC void
service_authorized_client_free_(hs_service_authorized_client_t *client)
{
@@ -1291,7 +1307,7 @@ service_authorized_client_free_(hs_service_authorized_client_t *client)
tor_free(client);
}
-/* Free a given service descriptor object and all key material is wiped. */
+/** Free a given service descriptor object and all key material is wiped. */
STATIC void
service_descriptor_free_(hs_service_descriptor_t *desc)
{
@@ -1312,7 +1328,7 @@ service_descriptor_free_(hs_service_descriptor_t *desc)
tor_free(desc);
}
-/* Return a newly allocated service descriptor object. */
+/** Return a newly allocated service descriptor object. */
STATIC hs_service_descriptor_t *
service_descriptor_new(void)
{
@@ -1325,7 +1341,7 @@ service_descriptor_new(void)
return sdesc;
}
-/* Allocate and return a deep copy of client. */
+/** Allocate and return a deep copy of client. */
static hs_service_authorized_client_t *
service_authorized_client_dup(const hs_service_authorized_client_t *client)
{
@@ -1343,7 +1359,7 @@ service_authorized_client_dup(const hs_service_authorized_client_t *client)
return client_dup;
}
-/* If two authorized clients are equal, return 0. If the first one should come
+/** If two authorized clients are equal, return 0. If the first one should come
* before the second, return less than zero. If the first should come after
* the second, return greater than zero. */
static int
@@ -1360,7 +1376,7 @@ service_authorized_client_cmp(const hs_service_authorized_client_t *client1,
CURVE25519_PUBKEY_LEN);
}
-/* Helper for sorting authorized clients. */
+/** Helper for sorting authorized clients. */
static int
compare_service_authorzized_client_(const void **_a, const void **_b)
{
@@ -1368,7 +1384,7 @@ compare_service_authorzized_client_(const void **_a, const void **_b)
return service_authorized_client_cmp(a, b);
}
-/* If the list of hs_service_authorized_client_t's is different between
+/** If the list of hs_service_authorized_client_t's is different between
* src and dst, return 1. Otherwise, return 0. */
STATIC int
service_authorized_client_config_equal(const hs_service_config_t *config1,
@@ -1429,7 +1445,7 @@ service_authorized_client_config_equal(const hs_service_config_t *config1,
return ret;
}
-/* Move descriptor(s) from the src service to the dst service and modify their
+/** Move descriptor(s) from the src service to the dst service and modify their
* content if necessary. We do this during SIGHUP when we re-create our
* hidden services. */
static void
@@ -1488,7 +1504,7 @@ move_descriptors(hs_service_t *src, hs_service_t *dst)
service_descriptor_free(dst->desc_next);
}
-/* From the given service, remove all expired failing intro points for each
+/** From the given service, remove all expired failing intro points for each
* descriptor. */
static void
remove_expired_failing_intro(hs_service_t *service, time_t now)
@@ -1507,7 +1523,7 @@ remove_expired_failing_intro(hs_service_t *service, time_t now)
} FOR_EACH_DESCRIPTOR_END;
}
-/* For the given descriptor desc, put all node_t object found from its failing
+/** For the given descriptor desc, put all node_t object found from its failing
* intro point list and put them in the given node_list. */
static void
setup_intro_point_exclude_list(const hs_service_descriptor_t *desc,
@@ -1525,7 +1541,7 @@ setup_intro_point_exclude_list(const hs_service_descriptor_t *desc,
} DIGESTMAP_FOREACH_END;
}
-/* For the given failing intro point ip, we add its time of failure to the
+/** For the given failing intro point ip, we add its time of failure to the
* failed map and index it by identity digest (legacy ID) in the descriptor
* desc failed id map. */
static void
@@ -1549,7 +1565,7 @@ remember_failing_intro_point(const hs_service_intro_point_t *ip,
tor_free(prev_ptr);
}
-/* Using a given descriptor signing keypair signing_kp, a service intro point
+/** Using a given descriptor signing keypair signing_kp, a service intro point
* object ip and the time now, setup the content of an already allocated
* descriptor intro desc_ip.
*
@@ -1638,7 +1654,7 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp,
return ret;
}
-/* Using the given descriptor from the given service, build the descriptor
+/** Using the given descriptor from the given service, build the descriptor
* intro point list so we can then encode the descriptor for publication. This
* function does not pick intro points, they have to be in the descriptor
* current map. Cryptographic material (keys) must be initialized in the
@@ -1659,7 +1675,7 @@ build_desc_intro_points(const hs_service_t *service,
DIGEST256MAP_FOREACH(desc->intro_points.map, key,
const hs_service_intro_point_t *, ip) {
- if (!ip->circuit_established) {
+ if (!hs_circ_service_get_established_intro_circ(ip)) {
/* Ignore un-established intro points. They can linger in that list
* because their circuit has not opened and they haven't been removed
* yet even though we have enough intro circuits.
@@ -1678,7 +1694,7 @@ build_desc_intro_points(const hs_service_t *service,
} DIGEST256MAP_FOREACH_END;
}
-/* Build the descriptor signing key certificate. */
+/** Build the descriptor signing key certificate. */
static void
build_desc_signing_key_cert(hs_service_descriptor_t *desc, time_t now)
{
@@ -1704,7 +1720,7 @@ build_desc_signing_key_cert(hs_service_descriptor_t *desc, time_t now)
tor_assert_nonfatal(plaintext->signing_key_cert);
}
-/* Populate the descriptor encrypted section from the given service object.
+/** Populate the descriptor encrypted section from the given service object.
* This will generate a valid list of introduction points that can be used
* after for circuit creation. Return 0 on success else -1 on error. */
static int
@@ -1734,7 +1750,7 @@ build_service_desc_encrypted(const hs_service_t *service,
return 0;
}
-/* Populate the descriptor superencrypted section from the given service
+/** Populate the descriptor superencrypted section from the given service
* object. This will generate a valid list of hs_desc_authorized_client_t
* of clients that are authorized to use the service. Return 0 on success
* else -1 on error. */
@@ -1762,7 +1778,8 @@ build_service_desc_superencrypted(const hs_service_t *service,
sizeof(curve25519_public_key_t));
/* Test that subcred is not zero because we might use it below */
- if (BUG(fast_mem_is_zero((char*)desc->desc->subcredential, DIGEST256_LEN))) {
+ if (BUG(fast_mem_is_zero((char*)desc->desc->subcredential.subcred,
+ DIGEST256_LEN))) {
return -1;
}
@@ -1779,7 +1796,7 @@ build_service_desc_superencrypted(const hs_service_t *service,
/* Prepare the client for descriptor and then add to the list in the
* superencrypted part of the descriptor */
- hs_desc_build_authorized_client(desc->desc->subcredential,
+ hs_desc_build_authorized_client(&desc->desc->subcredential,
&client->client_pk,
&desc->auth_ephemeral_kp.seckey,
desc->descriptor_cookie, desc_client);
@@ -1817,7 +1834,7 @@ build_service_desc_superencrypted(const hs_service_t *service,
return 0;
}
-/* Populate the descriptor plaintext section from the given service object.
+/** Populate the descriptor plaintext section from the given service object.
* The caller must make sure that the keys in the descriptors are valid that
* is are non-zero. This can't fail. */
static void
@@ -1835,7 +1852,7 @@ build_service_desc_plaintext(const hs_service_t *service,
/* Set the subcredential. */
hs_get_subcredential(&service->keys.identity_pk, &desc->blinded_kp.pubkey,
- desc->desc->subcredential);
+ &desc->desc->subcredential);
plaintext = &desc->desc->plaintext_data;
@@ -1868,7 +1885,7 @@ generate_ope_cipher_for_desc(const hs_service_descriptor_t *hs_desc)
return crypto_ope_new(key);
}
-/* For the given service and descriptor object, create the key material which
+/** For the given service and descriptor object, create the key material which
* is the blinded keypair, the descriptor signing keypair, the ephemeral
* keypair, and the descriptor cookie. Return 0 on success else -1 on error
* where the generated keys MUST be ignored. */
@@ -1930,7 +1947,7 @@ build_service_desc_keys(const hs_service_t *service,
return ret;
}
-/* Given a service and the current time, build a descriptor for the service.
+/** Given a service and the current time, build a descriptor for the service.
* This function does not pick introduction point, this needs to be done by
* the update function. On success, desc_out will point to the newly allocated
* descriptor object.
@@ -1978,16 +1995,22 @@ build_service_descriptor(hs_service_t *service, uint64_t time_period_num,
/* Assign newly built descriptor to the next slot. */
*desc_out = desc;
+
/* Fire a CREATED control port event. */
hs_control_desc_event_created(service->onion_address,
&desc->blinded_kp.pubkey);
+
+ /* If we are an onionbalance instance, we refresh our keys when we rotate
+ * descriptors. */
+ hs_ob_refresh_keys(service);
+
return;
err:
service_descriptor_free(desc);
}
-/* Build both descriptors for the given service that has just booted up.
+/** Build both descriptors for the given service that has just booted up.
* Because it's a special case, it deserves its special function ;). */
static void
build_descriptors_for_new_service(hs_service_t *service, time_t now)
@@ -2037,7 +2060,7 @@ build_descriptors_for_new_service(hs_service_t *service, time_t now)
safe_str_client(service->onion_address));
}
-/* Build descriptors for each service if needed. There are conditions to build
+/** Build descriptors for each service if needed. There are conditions to build
* a descriptor which are details in the function. */
STATIC void
build_all_descriptors(time_t now)
@@ -2070,7 +2093,7 @@ build_all_descriptors(time_t now)
} FOR_EACH_DESCRIPTOR_END;
}
-/* Randomly pick a node to become an introduction point but not present in the
+/** Randomly pick a node to become an introduction point but not present in the
* given exclude_nodes list. The chosen node is put in the exclude list
* regardless of success or not because in case of failure, the node is simply
* unsusable from that point on.
@@ -2131,7 +2154,7 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes)
return NULL;
}
-/* For a given descriptor from the given service, pick any needed intro points
+/** For a given descriptor from the given service, pick any needed intro points
* and update the current map with those newly picked intro points. Return the
* number node that might have been added to the descriptor current map. */
static unsigned int
@@ -2255,7 +2278,7 @@ service_desc_schedule_upload(hs_service_descriptor_t *desc,
}
}
-/* Pick missing intro points for this descriptor if needed. */
+/** Pick missing intro points for this descriptor if needed. */
static void
update_service_descriptor_intro_points(hs_service_t *service,
hs_service_descriptor_t *desc, time_t now)
@@ -2296,7 +2319,7 @@ update_service_descriptor_intro_points(hs_service_t *service,
}
}
-/* Update descriptor intro points for each service if needed. We do this as
+/** Update descriptor intro points for each service if needed. We do this as
* part of the periodic event because we need to establish intro point circuits
* before we publish descriptors. */
STATIC void
@@ -2311,7 +2334,7 @@ update_all_descriptors_intro_points(time_t now)
} FOR_EACH_SERVICE_END;
}
-/* Return true iff the given intro point has expired that is it has been used
+/** Return true iff the given intro point has expired that is it has been used
* for too long or we've reached our max seen INTRODUCE2 cell. */
STATIC int
intro_point_should_expire(const hs_service_intro_point_t *ip,
@@ -2333,7 +2356,7 @@ intro_point_should_expire(const hs_service_intro_point_t *ip,
return 1;
}
-/* Return true iff we should remove the intro point ip from its service.
+/** Return true iff we should remove the intro point ip from its service.
*
* We remove an intro point from the service descriptor list if one of
* these criteria is met:
@@ -2369,10 +2392,6 @@ should_remove_intro_point(hs_service_intro_point_t *ip, time_t now)
* remove it because it might simply be valid and opened at the previous
* scheduled event for the last retry. */
- /* Did we established already? */
- if (ip->circuit_established) {
- goto end;
- }
/* Do we simply have an existing circuit regardless of its state? */
if (hs_circ_service_get_intro_circ(ip)) {
goto end;
@@ -2395,7 +2414,7 @@ should_remove_intro_point(hs_service_intro_point_t *ip, time_t now)
return ret;
}
-/* Go over the given set of intro points for each service and remove any
+/** Go over the given set of intro points for each service and remove any
* invalid ones.
*
* If an intro point is removed, the circuit (if any) is immediately close.
@@ -2405,12 +2424,10 @@ static void
cleanup_intro_points(hs_service_t *service, time_t now)
{
/* List of intro points to close. We can't mark the intro circuits for close
- * in the modify loop because doing so calls
- * hs_service_intro_circ_has_closed() which does a digest256map_get() on the
- * intro points map (that we are iterating over). This can't be done in a
- * single iteration after a MAP_DEL_CURRENT, the object will still be
- * returned leading to a use-after-free. So, we close the circuits and free
- * the intro points after the loop if any. */
+ * in the modify loop because doing so calls back into the HS subsystem and
+ * we need to keep that code path outside of the service/desc loop so those
+ * maps don't get modified during the close making us in a possible
+ * use-after-free situation. */
smartlist_t *ips_to_free = smartlist_new();
tor_assert(service);
@@ -2458,7 +2475,7 @@ cleanup_intro_points(hs_service_t *service, time_t now)
smartlist_free(ips_to_free);
}
-/* Set the next rotation time of the descriptors for the given service for the
+/** Set the next rotation time of the descriptors for the given service for the
* time now. */
static void
set_rotation_time(hs_service_t *service)
@@ -2477,7 +2494,7 @@ set_rotation_time(hs_service_t *service)
}
}
-/* Return true iff the service should rotate its descriptor. The time now is
+/** Return true iff the service should rotate its descriptor. The time now is
* only used to fetch the live consensus and if none can be found, this
* returns false. */
static unsigned int
@@ -2529,7 +2546,7 @@ should_rotate_descriptors(hs_service_t *service, time_t now)
return 1;
}
-/* Rotate the service descriptors of the given service. The current descriptor
+/** Rotate the service descriptors of the given service. The current descriptor
* will be freed, the next one put in as the current and finally the next
* descriptor pointer is NULLified. */
static void
@@ -2551,7 +2568,7 @@ rotate_service_descriptors(hs_service_t *service)
set_rotation_time(service);
}
-/* Rotate descriptors for each service if needed. A non existing current
+/** Rotate descriptors for each service if needed. A non existing current
* descriptor will trigger a descriptor build for the next time period. */
STATIC void
rotate_all_descriptors(time_t now)
@@ -2580,7 +2597,7 @@ rotate_all_descriptors(time_t now)
} FOR_EACH_SERVICE_END;
}
-/* Scheduled event run from the main loop. Make sure all our services are up
+/** Scheduled event run from the main loop. Make sure all our services are up
* to date and ready for the other scheduled events. This includes looking at
* the introduction points status and descriptor rotation time. */
STATIC void
@@ -2615,7 +2632,7 @@ run_housekeeping_event(time_t now)
} FOR_EACH_SERVICE_END;
}
-/* Scheduled event run from the main loop. Make sure all descriptors are up to
+/** Scheduled event run from the main loop. Make sure all descriptors are up to
* date. Once this returns, each service descriptor needs to be considered for
* new introduction circuits and then for upload. */
static void
@@ -2638,7 +2655,7 @@ run_build_descriptor_event(time_t now)
update_all_descriptors_intro_points(now);
}
-/* For the given service, launch any intro point circuits that could be
+/** For the given service, launch any intro point circuits that could be
* needed. This considers every descriptor of the service. */
static void
launch_intro_point_circuits(hs_service_t *service)
@@ -2692,7 +2709,7 @@ launch_intro_point_circuits(hs_service_t *service)
} FOR_EACH_DESCRIPTOR_END;
}
-/* Don't try to build more than this many circuits before giving up for a
+/** Don't try to build more than this many circuits before giving up for a
* while. Dynamically calculated based on the configured number of intro
* points for the given service and how many descriptor exists. The default
* use case of 3 introduction points and two descriptors will allow 28
@@ -2708,7 +2725,7 @@ get_max_intro_circ_per_period(const hs_service_t *service)
tor_assert(service->config.num_intro_points <=
HS_CONFIG_V3_MAX_INTRO_POINTS);
-/* For a testing network, allow to do it for the maximum amount so circuit
+/** For a testing network, allow to do it for the maximum amount so circuit
* creation and rotation and so on can actually be tested without limit. */
#define MAX_INTRO_POINT_CIRCUIT_RETRIES_TESTING -1
if (get_options()->TestingTorNetwork) {
@@ -2737,7 +2754,7 @@ get_max_intro_circ_per_period(const hs_service_t *service)
return (count * multiplier);
}
-/* For the given service, return 1 if the service is allowed to launch more
+/** For the given service, return 1 if the service is allowed to launch more
* introduction circuits else 0 if the maximum has been reached for the retry
* period of INTRO_CIRC_RETRY_PERIOD. */
STATIC int
@@ -2783,7 +2800,7 @@ can_service_launch_intro_circuit(hs_service_t *service, time_t now)
return 1;
}
-/* Scheduled event run from the main loop. Make sure we have all the circuits
+/** Scheduled event run from the main loop. Make sure we have all the circuits
* we need for each service. */
static void
run_build_circuit_event(time_t now)
@@ -2813,7 +2830,7 @@ run_build_circuit_event(time_t now)
} FOR_EACH_SERVICE_END;
}
-/* Encode and sign the service descriptor desc and upload it to the given
+/** Encode and sign the service descriptor desc and upload it to the given
* hidden service directory. This does nothing if PublishHidServDescriptors
* is false. */
static void
@@ -2829,7 +2846,7 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
/* Let's avoid doing that if tor is configured to not publish. */
if (!get_options()->PublishHidServDescriptors) {
log_info(LD_REND, "Service %s not publishing descriptor. "
- "PublishHidServDescriptors is set to 1.",
+ "PublishHidServDescriptors is set to 0.",
safe_str_client(service->onion_address));
goto end;
}
@@ -2949,7 +2966,7 @@ set_descriptor_revision_counter(hs_service_descriptor_t *hs_desc, time_t now,
hs_desc->desc->plaintext_data.revision_counter = rev_counter;
}
-/* Encode and sign the service descriptor desc and upload it to the
+/** Encode and sign the service descriptor desc and upload it to the
* responsible hidden service directories. If for_next_period is true, the set
* of directories are selected using the next hsdir_index. This does nothing
* if PublishHidServDescriptors is false. */
@@ -3046,13 +3063,85 @@ service_desc_hsdirs_changed(const hs_service_t *service,
return should_reupload;
}
-/* Return 1 if the given descriptor from the given service can be uploaded
+/** These are all the reasons why a descriptor upload can't occur. We use
+ * those to log the reason properly with the right rate limiting and for the
+ * right descriptor. */
+typedef enum {
+ LOG_DESC_UPLOAD_REASON_MISSING_IPS = 0,
+ LOG_DESC_UPLOAD_REASON_IP_NOT_ESTABLISHED = 1,
+ LOG_DESC_UPLOAD_REASON_NOT_TIME = 2,
+ LOG_DESC_UPLOAD_REASON_NO_LIVE_CONSENSUS = 3,
+ LOG_DESC_UPLOAD_REASON_NO_DIRINFO = 4,
+} log_desc_upload_reason_t;
+
+/** Maximum number of reasons. This is used to allocate the static array of
+ * all rate limiting objects. */
+#define LOG_DESC_UPLOAD_REASON_MAX LOG_DESC_UPLOAD_REASON_NO_DIRINFO
+
+/** Log the reason why we can't upload the given descriptor for the given
+ * service. This takes a message string (allocated by the caller) and a
+ * reason.
+ *
+ * Depending on the reason and descriptor, different rate limit applies. This
+ * is done because this function will basically be called every second. Each
+ * descriptor for each reason uses its own log rate limit object in order to
+ * avoid message suppression for different reasons and descriptors. */
+static void
+log_cant_upload_desc(const hs_service_t *service,
+ const hs_service_descriptor_t *desc, const char *msg,
+ const log_desc_upload_reason_t reason)
+{
+ /* Writing the log every minute shouldn't be too annoying for log rate limit
+ * since this can be emitted every second for each descriptor.
+ *
+ * However, for one specific case, we increase it to 10 minutes because it
+ * is hit constantly, as an expected behavior, which is the reason
+ * indicating that it is not the time to upload. */
+ static ratelim_t limits[2][LOG_DESC_UPLOAD_REASON_MAX + 1] =
+ { { RATELIM_INIT(60), RATELIM_INIT(60), RATELIM_INIT(60 * 10),
+ RATELIM_INIT(60), RATELIM_INIT(60) },
+ { RATELIM_INIT(60), RATELIM_INIT(60), RATELIM_INIT(60 * 10),
+ RATELIM_INIT(60), RATELIM_INIT(60) },
+ };
+ bool is_next_desc = false;
+ unsigned int rlim_pos = 0;
+ ratelim_t *rlim = NULL;
+
+ tor_assert(service);
+ tor_assert(desc);
+ tor_assert(msg);
+
+ /* Make sure the reason value is valid. It should never happen because we
+ * control that value in the code flow but will be apparent during
+ * development if a reason is added but LOG_DESC_UPLOAD_REASON_NUM_ is not
+ * updated. */
+ if (BUG(reason > LOG_DESC_UPLOAD_REASON_MAX)) {
+ return;
+ }
+
+ /* Ease our life. Flag that tells us if the descriptor is the next one. */
+ is_next_desc = (service->desc_next == desc);
+
+ /* Current descriptor is the first element in the ratelimit object array.
+ * The next descriptor is the second element. */
+ rlim_pos = (is_next_desc ? 1 : 0);
+ /* Get the ratelimit object for the reason _and_ right descriptor. */
+ rlim = &limits[rlim_pos][reason];
+
+ log_fn_ratelim(rlim, LOG_INFO, LD_REND,
+ "Service %s can't upload its %s descriptor: %s",
+ safe_str_client(service->onion_address),
+ (is_next_desc) ? "next" : "current", msg);
+}
+
+/** Return 1 if the given descriptor from the given service can be uploaded
* else return 0 if it can not. */
static int
should_service_upload_descriptor(const hs_service_t *service,
const hs_service_descriptor_t *desc, time_t now)
{
- unsigned int num_intro_points;
+ char *msg = NULL;
+ unsigned int num_intro_points, count_ip_established;
tor_assert(service);
tor_assert(desc);
@@ -3072,38 +3161,58 @@ should_service_upload_descriptor(const hs_service_t *service,
* upload descriptor in this case. We need at least one for the service to
* be reachable. */
if (desc->missing_intro_points && num_intro_points == 0) {
+ msg = tor_strdup("Missing intro points");
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_MISSING_IPS);
goto cannot;
}
/* Check if all our introduction circuit have been established for all the
* intro points we have selected. */
- if (count_desc_circuit_established(desc) != num_intro_points) {
+ count_ip_established = count_desc_circuit_established(desc);
+ if (count_ip_established != num_intro_points) {
+ tor_asprintf(&msg, "Intro circuits aren't yet all established (%d/%d).",
+ count_ip_established, num_intro_points);
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_IP_NOT_ESTABLISHED);
goto cannot;
}
/* Is it the right time to upload? */
if (desc->next_upload_time > now) {
+ tor_asprintf(&msg, "Next upload time is %ld, it is now %ld.",
+ (long int) desc->next_upload_time, (long int) now);
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_NOT_TIME);
goto cannot;
}
/* Don't upload desc if we don't have a live consensus */
if (!networkstatus_get_live_consensus(now)) {
+ msg = tor_strdup("No live consensus");
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_NO_LIVE_CONSENSUS);
goto cannot;
}
/* Do we know enough router descriptors to have adequate vision of the HSDir
hash ring? */
if (!router_have_minimum_dir_info()) {
+ msg = tor_strdup("Not enough directory information");
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_NO_DIRINFO);
goto cannot;
}
/* Can upload! */
return 1;
+
cannot:
+ tor_free(msg);
return 0;
}
-/* Refresh the given service descriptor meaning this will update every mutable
+/** Refresh the given service descriptor meaning this will update every mutable
* field that needs to be updated before we upload.
*
* This should ONLY be called before uploading a descriptor. It assumes that
@@ -3134,7 +3243,7 @@ refresh_service_descriptor(const hs_service_t *service,
set_descriptor_revision_counter(desc, now, service->desc_current == desc);
}
-/* Scheduled event run from the main loop. Try to upload the descriptor for
+/** Scheduled event run from the main loop. Try to upload the descriptor for
* each service. */
STATIC void
run_upload_descriptor_event(time_t now)
@@ -3183,7 +3292,7 @@ run_upload_descriptor_event(time_t now)
consider_republishing_hs_descriptors = 0;
}
-/* Called when the introduction point circuit is done building and ready to be
+/** Called when the introduction point circuit is done building and ready to be
* used. */
static void
service_intro_circ_has_opened(origin_circuit_t *circ)
@@ -3241,7 +3350,7 @@ service_intro_circ_has_opened(origin_circuit_t *circ)
return;
}
-/* Called when a rendezvous circuit is done building and ready to be used. */
+/** Called when a rendezvous circuit is done building and ready to be used. */
static void
service_rendezvous_circ_has_opened(origin_circuit_t *circ)
{
@@ -3282,7 +3391,7 @@ service_rendezvous_circ_has_opened(origin_circuit_t *circ)
return;
}
-/* We've been expecting an INTRO_ESTABLISHED cell on this circuit and it just
+/** We've been expecting an INTRO_ESTABLISHED cell on this circuit and it just
* arrived. Handle the INTRO_ESTABLISHED cell arriving on the given
* introduction circuit. Return 0 on success else a negative value. */
static int
@@ -3325,11 +3434,6 @@ service_handle_intro_established(origin_circuit_t *circ,
goto err;
}
- /* Flag that we have an established circuit for this intro point. This value
- * is what indicates the upload scheduled event if we are ready to build the
- * intro point into the descriptor and upload. */
- ip->circuit_established = 1;
-
log_info(LD_REND, "Successfully received an INTRO_ESTABLISHED cell "
"on circuit %u for service %s",
TO_CIRCUIT(circ)->n_circ_id,
@@ -3340,7 +3444,7 @@ service_handle_intro_established(origin_circuit_t *circ,
return -1;
}
-/* We just received an INTRODUCE2 cell on the established introduction circuit
+/** We just received an INTRODUCE2 cell on the established introduction circuit
* circ. Handle the cell and return 0 on success else a negative value. */
static int
service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload,
@@ -3378,7 +3482,7 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload,
/* The following will parse, decode and launch the rendezvous point circuit.
* Both current and legacy cells are handled. */
- if (hs_circ_handle_introduce2(service, circ, ip, desc->desc->subcredential,
+ if (hs_circ_handle_introduce2(service, circ, ip, &desc->desc->subcredential,
payload, payload_len) < 0) {
goto err;
}
@@ -3388,7 +3492,7 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload,
return -1;
}
-/* Add to list every filename used by service. This is used by the sandbox
+/** Add to list every filename used by service. This is used by the sandbox
* subsystem. */
static void
service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list)
@@ -3410,7 +3514,7 @@ service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list)
smartlist_add(list, hs_path_from_filename(s_dir, fname));
}
-/* Return true iff the given service identity key is present on disk. */
+/** Return true iff the given service identity key is present on disk. */
static int
service_key_on_disk(const char *directory_path)
{
@@ -3434,7 +3538,7 @@ service_key_on_disk(const char *directory_path)
return ret;
}
-/* This is a proxy function before actually calling hs_desc_encode_descriptor
+/** This is a proxy function before actually calling hs_desc_encode_descriptor
* because we need some preprocessing here */
static int
service_encode_descriptor(const hs_service_t *service,
@@ -3465,7 +3569,7 @@ service_encode_descriptor(const hs_service_t *service,
/* Public API */
/* ========== */
-/* This is called everytime the service map (v2 or v3) changes that is if an
+/** This is called everytime the service map (v2 or v3) changes that is if an
* element is added or removed. */
void
hs_service_map_has_changed(void)
@@ -3476,7 +3580,7 @@ hs_service_map_has_changed(void)
rescan_periodic_events(get_options());
}
-/* Upload an encoded descriptor in encoded_desc of the given version. This
+/** 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
* routerstatus_t object.
@@ -3524,7 +3628,7 @@ hs_service_upload_desc_to_dir(const char *encoded_desc,
directory_request_free(dir_req);
}
-/* Add the ephemeral service using the secret key sk and ports. Both max
+/** 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
@@ -3610,7 +3714,7 @@ hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
return ret;
}
-/* For the given onion address, delete the ephemeral service. Return 0 on
+/** For the given onion address, delete the ephemeral service. Return 0 on
* success else -1 on error. */
int
hs_service_del_ephemeral(const char *address)
@@ -3660,7 +3764,7 @@ hs_service_del_ephemeral(const char *address)
return -1;
}
-/* Using the ed25519 public key pk, find a service for that key and return the
+/** Using the ed25519 public key pk, find a service for that key and return the
* current encoded descriptor as a newly allocated string or NULL if not
* found. This is used by the control port subsystem. */
char *
@@ -3686,7 +3790,7 @@ hs_service_lookup_current_desc(const ed25519_public_key_t *pk)
return NULL;
}
-/* Return the number of service we have configured and usable. */
+/** Return the number of service we have configured and usable. */
MOCK_IMPL(unsigned int,
hs_service_get_num_services,(void))
{
@@ -3696,49 +3800,7 @@ hs_service_get_num_services,(void))
return HT_SIZE(hs_service_map);
}
-/* Called once an introduction circuit is closed. If the circuit doesn't have
- * a v3 identifier, it is ignored. */
-void
-hs_service_intro_circ_has_closed(origin_circuit_t *circ)
-{
- hs_service_t *service = NULL;
- hs_service_intro_point_t *ip = NULL;
- hs_service_descriptor_t *desc = NULL;
-
- tor_assert(circ);
-
- if (circ->hs_ident == NULL) {
- /* This is not a v3 circuit, ignore. */
- goto end;
- }
-
- get_objects_from_ident(circ->hs_ident, &service, &ip, &desc);
- if (service == NULL) {
- /* This is possible if the circuits are closed and the service is
- * immediately deleted. */
- log_info(LD_REND, "Unable to find any hidden service associated "
- "identity key %s on intro circuit %u.",
- ed25519_fmt(&circ->hs_ident->identity_pk),
- TO_CIRCUIT(circ)->n_circ_id);
- goto end;
- }
- if (ip == NULL) {
- /* The introduction point object has already been removed probably by our
- * cleanup process so ignore. */
- goto end;
- }
- /* Can't have an intro point object without a descriptor. */
- tor_assert(desc);
-
- /* Circuit disappeared so make sure the intro point is updated. By
- * keeping the object in the descriptor, we'll be able to retry. */
- ip->circuit_established = 0;
-
- end:
- return;
-}
-
-/* Given conn, a rendezvous edge connection acting as an exit stream, look up
+/** Given conn, a rendezvous edge connection acting as an exit stream, look up
* the hidden service for the circuit circ, and look up the port and address
* based on the connection port. Assign the actual connection address.
*
@@ -3836,7 +3898,7 @@ hs_service_exports_circuit_id(const ed25519_public_key_t *pk)
return service->config.circuit_id_protocol;
}
-/* Add to file_list every filename used by a configured hidden service, and to
+/** Add to file_list every filename used by a configured hidden service, and to
* dir_list every directory path used by a configured hidden service. This is
* used by the sandbox subsystem to whitelist those. */
void
@@ -3861,7 +3923,7 @@ hs_service_lists_fnames_for_sandbox(smartlist_t *file_list,
} FOR_EACH_DESCRIPTOR_END;
}
-/* Called when our internal view of the directory has changed. We might have
+/** Called when our internal view of the directory has changed. We might have
* received a new batch of descriptors which might affect the shape of the
* HSDir hash ring. Signal that we should reexamine the hash ring and
* re-upload our HS descriptors if needed. */
@@ -3878,7 +3940,7 @@ hs_service_dir_info_changed(void)
}
}
-/* Called when we get an INTRODUCE2 cell on the circ. Respond to the cell and
+/** Called when we get an INTRODUCE2 cell on the circ. Respond to the cell and
* launch a circuit to the rendezvous point. */
int
hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload,
@@ -3909,7 +3971,7 @@ hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload,
return ret;
}
-/* Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an
+/** Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an
* established introduction point. Return 0 on success else a negative value
* and the circuit is closed. */
int
@@ -3946,7 +4008,7 @@ hs_service_receive_intro_established(origin_circuit_t *circ,
return -1;
}
-/* Called when any kind of hidden service circuit is done building thus
+/** Called when any kind of hidden service circuit is done building thus
* opened. This is the entry point from the circuit subsystem. */
void
hs_service_circuit_has_opened(origin_circuit_t *circ)
@@ -3975,7 +4037,7 @@ hs_service_circuit_has_opened(origin_circuit_t *circ)
}
}
-/* Return the service version by looking at the key in the service directory.
+/** Return the service version by looking at the key in the service directory.
* If the key is not found or unrecognized, -1 is returned. Else, the service
* version is returned. */
int
@@ -4005,7 +4067,7 @@ hs_service_get_version_from_key(const hs_service_t *service)
return version;
}
-/* Load and/or generate keys for all onion services including the client
+/** Load and/or generate keys for all onion services including the client
* authorization if any. Return 0 on success, -1 on failure. */
int
hs_service_load_all_keys(void)
@@ -4041,7 +4103,51 @@ hs_service_load_all_keys(void)
return -1;
}
-/* Put all service object in the given service list. After this, the caller
+/** Log the status of introduction points for all version 3 onion services
+ * at log severity <b>severity</b>.
+ */
+void
+hs_service_dump_stats(int severity)
+{
+ origin_circuit_t *circ;
+
+ FOR_EACH_SERVICE_BEGIN(hs) {
+
+ tor_log(severity, LD_GENERAL, "Service configured in %s:",
+ service_escaped_dir(hs));
+ FOR_EACH_DESCRIPTOR_BEGIN(hs, desc) {
+
+ DIGEST256MAP_FOREACH(desc->intro_points.map, key,
+ hs_service_intro_point_t *, ip) {
+ const node_t *intro_node;
+ const char *nickname;
+
+ intro_node = get_node_from_intro_point(ip);
+ if (!intro_node) {
+ tor_log(severity, LD_GENERAL, " Couldn't find intro point, "
+ "skipping");
+ continue;
+ }
+ nickname = node_get_nickname(intro_node);
+ if (!nickname) {
+ continue;
+ }
+
+ circ = hs_circ_service_get_intro_circ(ip);
+ if (!circ) {
+ tor_log(severity, LD_GENERAL, " Intro point at %s: no circuit",
+ nickname);
+ continue;
+ }
+ tor_log(severity, LD_GENERAL, " Intro point %s: circuit is %s",
+ nickname, circuit_state_to_string(circ->base_.state));
+ } DIGEST256MAP_FOREACH_END;
+
+ } FOR_EACH_DESCRIPTOR_END;
+ } FOR_EACH_SERVICE_END;
+}
+
+/** Put all service object in the given service list. After this, the caller
* looses ownership of every elements in the list and responsible to free the
* list pointer. */
void
@@ -4058,7 +4164,7 @@ hs_service_stage_services(const smartlist_t *service_list)
smartlist_add_all(hs_service_staging_list, service_list);
}
-/* Allocate and initilize a service object. The service configuration will
+/** Allocate and initilize a service object. The service configuration will
* contain the default values. Return the newly allocated object pointer. This
* function can't fail. */
hs_service_t *
@@ -4076,7 +4182,7 @@ hs_service_new(const or_options_t *options)
return service;
}
-/* Free the given <b>service</b> object and all its content. This function
+/** Free the given <b>service</b> object and all its content. This function
* also takes care of wiping service keys from memory. It is safe to pass a
* NULL pointer. */
void
@@ -4099,13 +4205,18 @@ hs_service_free_(hs_service_t *service)
replaycache_free(service->state.replay_cache_rend_cookie);
}
+ /* Free onionbalance subcredentials (if any) */
+ if (service->state.ob_subcreds) {
+ tor_free(service->state.ob_subcreds);
+ }
+
/* Wipe service keys. */
memwipe(&service->keys.identity_sk, 0, sizeof(service->keys.identity_sk));
tor_free(service);
}
-/* Periodic callback. Entry point from the main loop to the HS service
+/** Periodic callback. Entry point from the main loop to the HS service
* subsystem. This is call every second. This is skipped if tor can't build a
* circuit or the network is disabled. */
void
@@ -4128,7 +4239,7 @@ hs_service_run_scheduled_events(time_t now)
run_upload_descriptor_event(now);
}
-/* Initialize the service HS subsystem. */
+/** Initialize the service HS subsystem. */
void
hs_service_init(void)
{
@@ -4145,24 +4256,25 @@ hs_service_init(void)
hs_service_staging_list = smartlist_new();
}
-/* Release all global storage of the hidden service subsystem. */
+/** Release all global storage of the hidden service subsystem. */
void
hs_service_free_all(void)
{
rend_service_free_all();
service_free_all();
+ hs_config_free_all();
}
#ifdef TOR_UNIT_TESTS
-/* Return the global service map size. Only used by unit test. */
+/** Return the global service map size. Only used by unit test. */
STATIC unsigned int
get_hs_service_map_size(void)
{
return HT_SIZE(hs_service_map);
}
-/* Return the staging list size. Only used by unit test. */
+/** Return the staging list size. Only used by unit test. */
STATIC int
get_hs_service_staging_list_size(void)
{
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index c4bbb293bb..b5bff5bee5 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,92 +21,92 @@
/* Trunnel */
#include "trunnel/hs/cell_establish_intro.h"
-/* When loading and configuring a service, this is the default version it will
+#include "ext/ht.h"
+
+/** When loading and configuring a service, this is the default version it will
* be configured for as it is possible that no HiddenServiceVersion is
* present. */
#define HS_SERVICE_DEFAULT_VERSION HS_VERSION_THREE
-/* As described in the specification, service publishes their next descriptor
+/** As described in the specification, service publishes their next descriptor
* at a random time between those two values (in seconds). */
#define HS_SERVICE_NEXT_UPLOAD_TIME_MIN (60 * 60)
+/** Maximum interval for uploading next descriptor (in seconds). */
#define HS_SERVICE_NEXT_UPLOAD_TIME_MAX (120 * 60)
-/* Service side introduction point. */
+/** Service side introduction point. */
typedef struct hs_service_intro_point_t {
- /* Top level intropoint "shared" data between client/service. */
+ /** Top level intropoint "shared" data between client/service. */
hs_intropoint_t base;
- /* Onion key of the introduction point used to extend to it for the ntor
+ /** Onion key of the introduction point used to extend to it for the ntor
* handshake. */
curve25519_public_key_t onion_key;
- /* Authentication keypair used to create the authentication certificate
+ /** Authentication keypair used to create the authentication certificate
* which is published in the descriptor. */
ed25519_keypair_t auth_key_kp;
- /* Encryption keypair for the "ntor" type. */
+ /** Encryption keypair for the "ntor" type. */
curve25519_keypair_t enc_key_kp;
- /* Legacy key if that intro point doesn't support v3. This should be used if
+ /** Legacy key if that intro point doesn't support v3. This should be used if
* the base object legacy flag is set. */
crypto_pk_t *legacy_key;
- /* Legacy key SHA1 public key digest. This should be used only if the base
+ /** Legacy key SHA1 public key digest. This should be used only if the base
* object legacy flag is set. */
uint8_t legacy_key_digest[DIGEST_LEN];
- /* Amount of INTRODUCE2 cell accepted from this intro point. */
+ /** Amount of INTRODUCE2 cell accepted from this intro point. */
uint64_t introduce2_count;
- /* Maximum number of INTRODUCE2 cell this intro point should accept. */
+ /** Maximum number of INTRODUCE2 cell this intro point should accept. */
uint64_t introduce2_max;
- /* The time at which this intro point should expire and stop being used. */
+ /** The time at which this intro point should expire and stop being used. */
time_t time_to_expire;
- /* The amount of circuit creation we've made to this intro point. This is
+ /** The amount of circuit creation we've made to this intro point. This is
* incremented every time we do a circuit relaunch on this intro point 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. */
uint32_t circuit_retries;
- /* Set if this intro point has an established circuit. */
- unsigned int circuit_established : 1;
-
- /* Replay cache recording the encrypted part of an INTRODUCE2 cell that the
+ /** Replay cache recording the encrypted part of an INTRODUCE2 cell that the
* circuit associated with this intro point has received. This is used to
* prevent replay attacks. */
replaycache_t *replay_cache;
- /* Support the INTRO2 DoS defense. If set, the DoS extension described by
+ /** Support the INTRO2 DoS defense. If set, the DoS extension described by
* proposal 305 is sent. */
unsigned int support_intro2_dos_defense : 1;
} hs_service_intro_point_t;
-/* Object handling introduction points of a service. */
+/** Object handling introduction points of a service. */
typedef struct hs_service_intropoints_t {
- /* The time at which we've started our retry period to build circuits. We
+ /** The time at which we've started our retry period to build circuits. We
* don't want to stress circuit creation so we can only retry for a certain
* time and then after we stop and wait. */
time_t retry_period_started;
- /* Number of circuit we've launched during a single retry period. */
+ /** Number of circuit we've launched during a single retry period. */
unsigned int num_circuits_launched;
- /* Contains the current hs_service_intro_point_t objects indexed by
+ /** Contains the current hs_service_intro_point_t objects indexed by
* authentication public key. */
digest256map_t *map;
- /* Contains node's identity key digest that were introduction point for this
+ /** Contains node's identity key digest that were introduction point for this
* descriptor but were retried to many times. We keep those so we avoid
* re-picking them over and over for a circuit retry period.
* XXX: Once we have #22173, change this to only use ed25519 identity. */
digestmap_t *failed_id;
} hs_service_intropoints_t;
-/* Representation of a service descriptor.
+/** Representation of a service descriptor.
*
* Some elements of the descriptor are mutable whereas others are immutable:
-
+ *
* Immutable elements are initialized once when the descriptor is built (when
* service descriptors gets rotated). This means that these elements are
* initialized once and then they don't change for the lifetime of the
@@ -121,40 +121,42 @@ typedef struct hs_service_intropoints_t {
* update_service_descriptor_intro_points().
*/
typedef struct hs_service_descriptor_t {
- /* Immutable: Client authorization ephemeral keypair. */
+ /** Immutable: Client authorization ephemeral keypair. */
curve25519_keypair_t auth_ephemeral_kp;
- /* Immutable: Descriptor cookie used to encrypt the descriptor, when the
+ /** Immutable: Descriptor cookie used to encrypt the descriptor, when the
* client authorization is enabled */
uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
- /* Immutable: Descriptor signing keypair. */
+ /** Immutable: Descriptor signing keypair. */
ed25519_keypair_t signing_kp;
- /* Immutable: Blinded keypair derived from the master identity public key. */
+ /** Immutable: Blinded keypair derived from the master identity public
+ * key. */
ed25519_keypair_t blinded_kp;
- /* Immutable: The time period number this descriptor has been created for. */
+ /** Immutable: The time period number this descriptor has been created
+ * for. */
uint64_t time_period_num;
/** Immutable: The OPE cipher for encrypting revision counters for this
* descriptor. Tied to the descriptor blinded key. */
struct crypto_ope_t *ope_cipher;
- /* Mutable: Decoded descriptor. This object is used for encoding when the
+ /** Mutable: Decoded descriptor. This object is used for encoding when the
* service publishes the descriptor. */
hs_descriptor_t *desc;
- /* Mutable: When is the next time when we should upload the descriptor. */
+ /** Mutable: When is the next time when we should upload the descriptor. */
time_t next_upload_time;
- /* Mutable: Introduction points assign to this descriptor which contains
+ /** Mutable: Introduction points assign to this descriptor which contains
* hs_service_intropoints_t object indexed by authentication key (the RSA key
* if the node is legacy). */
hs_service_intropoints_t intro_points;
- /* Mutable: True iff we have missing intro points for this descriptor because
- * we couldn't pick any nodes. */
+ /** Mutable: True iff we have missing intro points for this descriptor
+ * because we couldn't pick any nodes. */
unsigned int missing_intro_points : 1;
/** Mutable: List of the responsible HSDirs (their b64ed identity digest)
@@ -164,20 +166,20 @@ typedef struct hs_service_descriptor_t {
smartlist_t *previous_hsdirs;
} hs_service_descriptor_t;
-/* Service key material. */
+/** Service key material. */
typedef struct hs_service_keys_t {
- /* Master identify public key. */
+ /** Master identify public key. */
ed25519_public_key_t identity_pk;
- /* Master identity private key. */
+ /** Master identity private key. */
ed25519_secret_key_t identity_sk;
- /* True iff the key is kept offline which means the identity_sk MUST not be
+ /** True iff the key is kept offline which means the identity_sk MUST not be
* used in that case. */
unsigned int is_identify_key_offline : 1;
} hs_service_keys_t;
/** Service side configuration of client authorization. */
typedef struct hs_service_authorized_client_t {
- /* The client auth public key used to encrypt the descriptor cookie. */
+ /** The client auth public key used to encrypt the descriptor cookie. */
curve25519_public_key_t client_pk;
} hs_service_authorized_client_t;
@@ -190,120 +192,129 @@ typedef enum {
HS_CIRCUIT_ID_PROTOCOL_HAPROXY
} hs_circuit_id_protocol_t;
-/* Service configuration. The following are set from the torrc options either
+/** Service configuration. The following are set from the torrc options either
* set by the configuration file or by the control port. Nothing else should
* change those values. */
typedef struct hs_service_config_t {
- /* Protocol version of the service. Specified by HiddenServiceVersion
+ /** Protocol version of the service. Specified by HiddenServiceVersion
* option. */
uint32_t version;
- /* Have we explicitly set HiddenServiceVersion? */
+ /** Have we explicitly set HiddenServiceVersion? */
unsigned int hs_version_explicitly_set : 1;
- /* List of rend_service_port_config_t */
+ /** List of rend_service_port_config_t */
smartlist_t *ports;
- /* Path on the filesystem where the service persistent data is stored. NULL
+ /** Path on the filesystem where the service persistent data is stored. NULL
* if the service is ephemeral. Specified by HiddenServiceDir option. */
char *directory_path;
- /* The maximum number of simultaneous streams per rendezvous circuit that
+ /** The maximum number of simultaneous streams per rendezvous circuit that
* are allowed to be created. No limit if 0. Specified by
* HiddenServiceMaxStreams option. */
uint64_t max_streams_per_rdv_circuit;
- /* If true, we close circuits that exceed the max_streams_per_rdv_circuit
+ /** If true, we close circuits that exceed the max_streams_per_rdv_circuit
* limit. Specified by HiddenServiceMaxStreamsCloseCircuit option. */
unsigned int max_streams_close_circuit : 1;
- /* How many introduction points this service has. Specified by
+ /** How many introduction points this service has. Specified by
* HiddenServiceNumIntroductionPoints option. */
unsigned int num_intro_points;
- /* True iff the client auth is enabled. */
+ /** 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
+ /** List of hs_service_authorized_client_t's of clients that may access this
* service. Specified by HiddenServiceAuthorizeClient option. */
smartlist_t *clients;
- /* True iff we allow request made on unknown ports. Specified by
+ /** True iff we allow request made on unknown ports. Specified by
* HiddenServiceAllowUnknownPorts option. */
unsigned int allow_unknown_ports : 1;
- /* If true, this service is a Single Onion Service. Specified by
+ /** If true, this service is a Single Onion Service. Specified by
* HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode options. */
unsigned int is_single_onion : 1;
- /* If true, allow group read permissions on the directory_path. Specified by
+ /** If true, allow group read permissions on the directory_path. Specified by
* HiddenServiceDirGroupReadable option. */
unsigned int dir_group_readable : 1;
- /* Is this service ephemeral? */
+ /** Is this service ephemeral? */
unsigned int is_ephemeral : 1;
- /* Does this service export the circuit ID of its clients? */
+ /** Does this service export the circuit ID of its clients? */
hs_circuit_id_protocol_t circuit_id_protocol;
- /* DoS defenses. For the ESTABLISH_INTRO cell extension. */
+ /** DoS defenses. For the ESTABLISH_INTRO cell extension. */
unsigned int has_dos_defense_enabled : 1;
uint32_t intro_dos_rate_per_sec;
uint32_t intro_dos_burst_per_sec;
+
+ /** If set, contains the Onion Balance master ed25519 public key (taken from
+ * an .onion addresses) that this tor instance serves as backend. */
+ smartlist_t *ob_master_pubkeys;
} hs_service_config_t;
-/* Service state. */
+/** Service state. */
typedef struct hs_service_state_t {
- /* The time at which we've started our retry period to build circuits. We
+ /** The time at which we've started our retry period to build circuits. We
* don't want to stress circuit creation so we can only retry for a certain
* time and then after we stop and wait. */
time_t intro_circ_retry_started_time;
- /* Number of circuit we've launched during a single retry period. This
+ /** Number of circuit we've launched during a single retry period. This
* should never go over MAX_INTRO_CIRCS_PER_PERIOD. */
unsigned int num_intro_circ_launched;
- /* Replay cache tracking the REND_COOKIE found in INTRODUCE2 cell to detect
+ /** Replay cache tracking the REND_COOKIE found in INTRODUCE2 cell 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 *replay_cache_rend_cookie;
- /* When is the next time we should rotate our descriptors. This is has to be
+ /** When is the next time we should rotate our descriptors. This is has to be
* done at the start time of the next SRV protocol run. */
time_t next_rotation_time;
+
+ /* If this is an onionbalance instance, this is an array of subcredentials
+ * that should be used when decrypting an INTRO2 cell. If this is not an
+ * onionbalance instance, this is NULL.
+ * See [ONIONBALANCE] section in rend-spec-v3.txt for more details . */
+ hs_subcredential_t *ob_subcreds;
+ /* Number of OB subcredentials */
+ size_t n_ob_subcreds;
} hs_service_state_t;
-/* Representation of a service running on this tor instance. */
+/** Representation of a service running on this tor instance. */
typedef struct hs_service_t {
- /* Onion address base32 encoded and NUL terminated. We keep it for logging
+ /** Onion address base32 encoded and NUL terminated. We keep it for logging
* purposes so we don't have to build it everytime. */
char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
- /* Hashtable node: use to look up the service by its master public identity
+ /** Hashtable node: use to look up the service by its master public identity
* key in the service global map. */
HT_ENTRY(hs_service_t) hs_service_node;
- /* Service state which contains various flags and counters. */
+ /** Service state which contains various flags and counters. */
hs_service_state_t state;
- /* Key material of the service. */
+ /** Key material of the service. */
hs_service_keys_t keys;
- /* Configuration of the service. */
+ /** Configuration of the service. */
hs_service_config_t config;
- /* Current descriptor. */
+ /** Current descriptor. */
hs_service_descriptor_t *desc_current;
- /* Next descriptor. */
+ /** Next descriptor. */
hs_service_descriptor_t *desc_next;
-
- /* XXX: Credential (client auth.) #20700. */
-
} hs_service_t;
-/* For the service global hash map, we define a specific type for it which
+/** For the service global hash map, we define a specific type for it which
* will make it safe to use and specific to some controlled parameters such as
* the hashing function and how to compare services. */
typedef HT_HEAD(hs_service_ht, hs_service_t) hs_service_ht;
@@ -317,6 +328,11 @@ void hs_service_free_all(void);
/* Service new/free functions. */
hs_service_t *hs_service_new(const or_options_t *options);
void hs_service_free_(hs_service_t *service);
+/**
+ * @copydoc hs_service_free_
+ *
+ * Additionally, set the pointer <b>s</b> to NULL.
+ **/
#define hs_service_free(s) FREE_AND_NULL(hs_service_t, hs_service_free_, (s))
MOCK_DECL(unsigned int, hs_service_get_num_services,(void));
@@ -339,8 +355,6 @@ int hs_service_receive_introduce2(origin_circuit_t *circ,
const uint8_t *payload,
size_t payload_len);
-void hs_service_intro_circ_has_closed(origin_circuit_t *circ);
-
char *hs_service_lookup_current_desc(const ed25519_public_key_t *pk);
hs_service_add_ephemeral_status_t
@@ -359,6 +373,8 @@ void hs_service_upload_desc_to_dir(const char *encoded_desc,
hs_circuit_id_protocol_t
hs_service_exports_circuit_id(const ed25519_public_key_t *pk);
+void hs_service_dump_stats(int severity);
+
#ifdef HS_SERVICE_PRIVATE
#ifdef TOR_UNIT_TESTS
@@ -370,6 +386,9 @@ STATIC hs_service_t *get_first_service(void);
STATIC hs_service_intro_point_t *service_intro_point_find_by_ident(
const hs_service_t *service,
const hs_ident_circuit_t *ident);
+
+MOCK_DECL(STATIC unsigned int, count_desc_circuit_established,
+ (const hs_service_descriptor_t *desc));
#endif /* defined(TOR_UNIT_TESTS) */
/* Service accessors. */
diff --git a/src/feature/hs/hs_stats.c b/src/feature/hs/hs_stats.c
index f24b731328..f9d458d630 100644
--- a/src/feature/hs/hs_stats.c
+++ b/src/feature/hs/hs_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_stats.h b/src/feature/hs/hs_stats.h
index 6700eca15b..aea2ccf5c2 100644
--- a/src/feature/hs/hs_stats.h
+++ b/src/feature/hs/hs_stats.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 6c86c02f47..6ce0bf5c69 100644
--- a/src/feature/hs/hsdir_index_st.h
+++ b/src/feature/hs/hsdir_index_st.h
@@ -1,24 +1,29 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file hsdir_index_st.h
+ * @brief HS directory index structure
+ **/
+
#ifndef HSDIR_INDEX_ST_H
#define HSDIR_INDEX_ST_H
-/* Hidden service directory index used in a node_t which is set once we set
+/** Hidden service directory index used in a node_t which is set once we set
* the consensus. */
struct hsdir_index_t {
- /* HSDir index to use when fetching a descriptor. */
+ /** HSDir index to use when fetching a descriptor. */
uint8_t fetch[DIGEST256_LEN];
- /* HSDir index used by services to store their first and second
+ /** HSDir index used by services to store their first and second
* descriptor. The first descriptor is chronologically older than the second
* one and uses older TP and SRV values. */
uint8_t store_first[DIGEST256_LEN];
+ /** Newer index, for second descriptor. */
uint8_t store_second[DIGEST256_LEN];
};
#endif /* !defined(HSDIR_INDEX_ST_H) */
-
diff --git a/src/feature/hs/include.am b/src/feature/hs/include.am
new file mode 100644
index 0000000000..af1dc65585
--- /dev/null
+++ b/src/feature/hs/include.am
@@ -0,0 +1,39 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/hs/hs_cache.c \
+ src/feature/hs/hs_cell.c \
+ src/feature/hs/hs_circuit.c \
+ src/feature/hs/hs_circuitmap.c \
+ src/feature/hs/hs_client.c \
+ src/feature/hs/hs_common.c \
+ src/feature/hs/hs_config.c \
+ src/feature/hs/hs_control.c \
+ src/feature/hs/hs_descriptor.c \
+ src/feature/hs/hs_dos.c \
+ src/feature/hs/hs_ident.c \
+ src/feature/hs/hs_intropoint.c \
+ src/feature/hs/hs_ob.c \
+ src/feature/hs/hs_service.c \
+ src/feature/hs/hs_stats.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/hs/hs_cache.h \
+ src/feature/hs/hs_cell.h \
+ src/feature/hs/hs_circuit.h \
+ src/feature/hs/hs_circuitmap.h \
+ src/feature/hs/hs_client.h \
+ src/feature/hs/hs_common.h \
+ src/feature/hs/hs_config.h \
+ src/feature/hs/hs_control.h \
+ src/feature/hs/hs_descriptor.h \
+ src/feature/hs/hs_dos.h \
+ src/feature/hs/hs_ident.h \
+ src/feature/hs/hs_intropoint.h \
+ src/feature/hs/hs_ob.h \
+ src/feature/hs/hs_opts_st.h \
+ src/feature/hs/hs_options.inc \
+ src/feature/hs/hs_service.h \
+ src/feature/hs/hs_stats.h \
+ src/feature/hs/hsdir_index_st.h
diff --git a/src/feature/hs_common/.may_include b/src/feature/hs_common/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/hs_common/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/hs_common/feature_hs_common.md b/src/feature/hs_common/feature_hs_common.md
new file mode 100644
index 0000000000..3a5e351a0a
--- /dev/null
+++ b/src/feature/hs_common/feature_hs_common.md
@@ -0,0 +1,3 @@
+@dir /feature/hs_common
+@brief feature/hs_common: Common to v2 (old) and v3 (current) onion services
+
diff --git a/src/feature/hs_common/include.am b/src/feature/hs_common/include.am
new file mode 100644
index 0000000000..3bb9225c12
--- /dev/null
+++ b/src/feature/hs_common/include.am
@@ -0,0 +1,10 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/hs_common/replaycache.c \
+ src/feature/hs_common/shared_random_client.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/hs_common/replaycache.h \
+ src/feature/hs_common/shared_random_client.h
diff --git a/src/feature/hs_common/replaycache.c b/src/feature/hs_common/replaycache.c
index 9e8c13b1c5..ab058ce759 100644
--- a/src/feature/hs_common/replaycache.c
+++ b/src/feature/hs_common/replaycache.c
@@ -1,4 +1,4 @@
- /* Copyright (c) 2012-2019, The Tor Project, Inc. */
+ /* Copyright (c) 2012-2020, 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 01f5e600c2..3a3eed29c0 100644
--- a/src/feature/hs_common/replaycache.h
+++ b/src/feature/hs_common/replaycache.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,16 +14,16 @@ typedef struct replaycache_t replaycache_t;
#ifdef REPLAYCACHE_PRIVATE
struct replaycache_t {
- /* Scrub interval */
+ /** Scrub interval */
time_t scrub_interval;
- /* Last scrubbed */
+ /** Last scrubbed */
time_t scrubbed;
- /*
+ /**
* Horizon
* (don't return true on digests in the cache but older than this)
*/
time_t horizon;
- /*
+ /**
* Digest map: keys are digests, values are times the digest was last seen
*/
digest256map_t *digests_seen;
@@ -34,6 +34,11 @@ struct replaycache_t {
/* replaycache_t free/new */
void replaycache_free_(replaycache_t *r);
+/**
+ * @copydoc replaycache_free_
+ *
+ * Additionally, set the pointer <b>r</b> to NULL.
+ **/
#define replaycache_free(r) \
FREE_AND_NULL(replaycache_t, replaycache_free_, (r))
replaycache_t * replaycache_new(time_t horizon, time_t interval);
diff --git a/src/feature/hs_common/shared_random_client.c b/src/feature/hs_common/shared_random_client.c
index 5772034c6d..3f46321be4 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-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,17 +8,17 @@
* as part of the dirauth module.
**/
-#define SHARED_RANDOM_CLIENT_PRIVATE
#include "feature/hs_common/shared_random_client.h"
#include "app/config/config.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/authmode.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/networkstatus.h"
#include "lib/encoding/binascii.h"
#include "feature/nodelist/networkstatus_st.h"
-/* Convert a given srv object to a string for the control port. This doesn't
+/** Convert a given srv object to a string for the control port. This doesn't
* fail and the srv object MUST be valid. */
static char *
srv_to_control_string(const sr_srv_t *srv)
@@ -32,7 +32,25 @@ srv_to_control_string(const sr_srv_t *srv)
return srv_str;
}
-/* Return the voting interval of the tor vote subsystem. */
+/**
+ * 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.
+ **/
+#define DEFAULT_NETWORK_VOTING_INTERVAL (3600)
+
+/* 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
+ * authority, but they do not always set V3AuthoritativeDir.
+ */
+#ifdef TOR_UNIT_TESTS
+#define ASSUME_AUTHORITY_SCHEDULING 1
+#else
+#define ASSUME_AUTHORITY_SCHEDULING 0
+#endif
+
+/** Return the voting interval of the tor vote subsystem. */
int
get_voting_interval(void)
{
@@ -40,45 +58,32 @@ get_voting_interval(void)
networkstatus_t *consensus = networkstatus_get_live_consensus(time(NULL));
if (consensus) {
+ /* Ideally we have a live consensus and we can just use that. */
+ interval = (int)(consensus->fresh_until - consensus->valid_after);
+ } else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) {
+ /* If we don't have a live consensus and we're an authority,
+ * we should believe our own view of what the schedule ought to be. */
+ interval = dirauth_sched_get_configured_interval();
+ } else if ((consensus = networkstatus_get_latest_consensus())) {
+ /* If we're a client, then maybe a latest consensus is good enough?
+ * It's better than falling back to the non-consensus case. */
interval = (int)(consensus->fresh_until - consensus->valid_after);
} else {
- /* Same for both a testing and real network. We voluntarily ignore the
- * InitialVotingInterval since it complexifies things and it doesn't
- * affect the SR protocol. */
- interval = get_options()->V3AuthVotingInterval;
+ /* 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;
}
tor_assert(interval > 0);
return interval;
}
-/* Given the current consensus, return the start time of the current round of
- * the SR protocol. For example, if it's 23:47:08, the current round thus
- * started at 23:47:00 for a voting interval of 10 seconds.
- *
- * This function uses the consensus voting schedule to derive its results,
- * instead of the actual consensus we are currently using, so it should be used
- * for voting purposes. */
-time_t
-get_start_time_of_current_round(void)
-{
- const or_options_t *options = get_options();
- int voting_interval = get_voting_interval();
- /* First, get the start time of the next round */
- time_t next_start = voting_schedule_get_next_valid_after_time();
- /* Now roll back next_start by a voting interval to find the start time of
- the current round. */
- time_t curr_start = voting_schedule_get_start_of_next_interval(
- next_start - voting_interval - 1,
- voting_interval,
- options->TestingV3AuthVotingStartOffset);
- return curr_start;
-}
-
/*
* Public API
*/
-/* Encode the given shared random value and put it in dst. Destination
+/** Encode the given shared random value and put it in dst. Destination
* buffer must be at least SR_SRV_VALUE_BASE64_LEN plus the NULL byte. */
void
sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv)
@@ -99,7 +104,7 @@ sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv)
strlcpy(dst, buf, dst_len);
}
-/* Return the current SRV string representation for the control port. Return a
+/** Return the current SRV string representation for the control port. Return a
* newly allocated string on success containing the value else "" if not found
* or if we don't have a valid consensus yet. */
char *
@@ -115,7 +120,7 @@ sr_get_current_for_control(void)
return srv_str;
}
-/* Return the previous SRV string representation for the control port. Return
+/** Return the previous SRV string representation for the control port. Return
* a newly allocated string on success containing the value else "" if not
* found or if we don't have a valid consensus yet. */
char *
@@ -131,7 +136,7 @@ sr_get_previous_for_control(void)
return srv_str;
}
-/* Return current shared random value from the latest consensus. Caller can
+/** Return current shared random value from the latest consensus. Caller can
* NOT keep a reference to the returned pointer. Return NULL if none. */
const sr_srv_t *
sr_get_current(const networkstatus_t *ns)
@@ -154,7 +159,7 @@ sr_get_current(const networkstatus_t *ns)
return NULL;
}
-/* Return previous shared random value from the latest consensus. Caller can
+/** Return previous shared random value from the latest consensus. Caller can
* NOT keep a reference to the returned pointer. Return NULL if none. */
const sr_srv_t *
sr_get_previous(const networkstatus_t *ns)
@@ -177,7 +182,7 @@ sr_get_previous(const networkstatus_t *ns)
return NULL;
}
-/* Parse a list of arguments from a SRV value either from a vote, consensus
+/** Parse a list of arguments from a SRV value either from a vote, consensus
* or from our disk state and return a newly allocated srv object. NULL is
* returned on error.
*
@@ -238,13 +243,27 @@ sr_state_get_start_time_of_current_protocol_run(void)
time_t beginning_of_curr_round;
/* This function is not used for voting purposes, so if we have a live
- consensus, use its valid-after as the beginning of the current round,
- otherwise resort to the voting schedule which should always exist. */
+ consensus, use its valid-after as the beginning of the current round.
+ If we have no consensus but we're an authority, use our own
+ schedule. Otherwise, try using our view of the voting interval
+ to figure out when the current round _should_ be starting.
+ */
networkstatus_t *ns = networkstatus_get_live_consensus(approx_time());
if (ns) {
beginning_of_curr_round = ns->valid_after;
+ } else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) {
+ beginning_of_curr_round = dirauth_sched_get_cur_valid_after_time();
} else {
- beginning_of_curr_round = get_start_time_of_current_round();
+ /* voting_interval comes from get_voting_interval(), so if we're in
+ * this case as a client, we already tried to get the voting interval
+ * from the latest_consensus and gave a bug warning if we couldn't.
+ *
+ * We wouldn't want to look at the latest consensus's valid_after time,
+ * since that would be out of date. */
+ beginning_of_curr_round = voting_sched_get_start_of_interval_after(
+ approx_time() - voting_interval,
+ voting_interval,
+ 0);
}
/* Get current SR protocol round */
@@ -290,4 +309,3 @@ sr_state_get_protocol_run_duration(void)
int total_protocol_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
return total_protocol_rounds * get_voting_interval();
}
-
diff --git a/src/feature/hs_common/shared_random_client.h b/src/feature/hs_common/shared_random_client.h
index c90c52cfea..37a086d590 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-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -38,11 +38,9 @@ time_t sr_state_get_start_time_of_current_protocol_run(void);
time_t sr_state_get_start_time_of_previous_protocol_run(void);
unsigned int sr_state_get_phase_duration(void);
unsigned int sr_state_get_protocol_run_duration(void);
-time_t get_start_time_of_current_round(void);
#ifdef TOR_UNIT_TESTS
#endif /* TOR_UNIT_TESTS */
#endif /* !defined(TOR_SHARED_RANDOM_CLIENT_H) */
-
diff --git a/src/feature/keymgt/.may_include b/src/feature/keymgt/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/keymgt/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/keymgt/feature_keymgt.md b/src/feature/keymgt/feature_keymgt.md
new file mode 100644
index 0000000000..1eac7cca50
--- /dev/null
+++ b/src/feature/keymgt/feature_keymgt.md
@@ -0,0 +1,3 @@
+@dir /feature/keymgt
+@brief feature/keymgt: Store keys for relays, authorities, etc.
+
diff --git a/src/feature/keymgt/include.am b/src/feature/keymgt/include.am
new file mode 100644
index 0000000000..bc9beaa523
--- /dev/null
+++ b/src/feature/keymgt/include.am
@@ -0,0 +1,8 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/keymgt/loadkey.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/keymgt/loadkey.h
diff --git a/src/feature/keymgt/loadkey.c b/src/feature/keymgt/loadkey.c
index a8cbf0e582..7958bd964f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -33,7 +33,7 @@
/** Try to read an RSA key from <b>fname</b>. If <b>fname</b> doesn't exist
* and <b>generate</b> is true, create a new RSA key and save it in
* <b>fname</b>. Return the read/created key, or NULL on error. Log all
- * errors at level <b>severity</b>. If <b>created_out/b> is non-NULL and a
+ * errors at level <b>severity</b>. If <b>created_out</b> is non-NULL and a
* new key was created, set *<b>created_out</b> to true.
*/
crypto_pk_t *
diff --git a/src/feature/keymgt/loadkey.h b/src/feature/keymgt/loadkey.h
index 0a5af0b804..5a8ca32dea 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/.may_include b/src/feature/nodelist/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/nodelist/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c
index 9fc3b62525..97e44d53e3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -46,7 +46,7 @@
#include "feature/nodelist/networkstatus_voter_info_st.h"
#include "feature/nodelist/node_st.h"
-DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t)
+DECLARE_TYPED_DIGESTMAP_FNS(dsmap, digest_ds_map_t, download_status_t)
#define DSMAP_FOREACH(map, keyvar, valvar) \
DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \
valvar)
@@ -464,11 +464,13 @@ trusted_dirs_load_certs_from_string(const char *contents, int source,
(ds->addr != cert->addr ||
ds->dir_port != cert->dir_port)) {
char *a = tor_dup_ip(cert->addr);
- log_notice(LD_DIR, "Updating address for directory authority %s "
- "from %s:%d to %s:%d based on certificate.",
- ds->nickname, ds->address, (int)ds->dir_port,
- a, cert->dir_port);
- tor_free(a);
+ if (a) {
+ log_notice(LD_DIR, "Updating address for directory authority %s "
+ "from %s:%d to %s:%d based on certificate.",
+ ds->nickname, ds->address, (int)ds->dir_port,
+ a, cert->dir_port);
+ tor_free(a);
+ }
ds->addr = cert->addr;
ds->dir_port = cert->dir_port;
}
diff --git a/src/feature/nodelist/authcert.h b/src/feature/nodelist/authcert.h
index 071293f9ee..33065589ba 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 bf9b690c24..9145b12bbf 100644
--- a/src/feature/nodelist/authority_cert_st.h
+++ b/src/feature/nodelist/authority_cert_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file authority_cert_st.h
+ * @brief Authority certificate structure.
+ **/
+
#ifndef AUTHORITY_CERT_ST_H
#define AUTHORITY_CERT_ST_H
@@ -29,4 +34,3 @@ struct authority_cert_t {
};
#endif /* !defined(AUTHORITY_CERT_ST_H) */
-
diff --git a/src/feature/nodelist/desc_store_st.h b/src/feature/nodelist/desc_store_st.h
index 4d1378cdfa..5f35a490a5 100644
--- a/src/feature/nodelist/desc_store_st.h
+++ b/src/feature/nodelist/desc_store_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file desc_store_st.h
+ * @brief Routerinfo/extrainfo storage structure.
+ **/
+
#ifndef DESC_STORE_ST_H
#define DESC_STORE_ST_H
diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c
index 1e46837685..00896d5a44 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/describe.h b/src/feature/nodelist/describe.h
index 6c0d6dc48d..d0fa1af263 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c
index ccbb378513..33d1bfc4d0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,6 +27,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/or/policies.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
@@ -357,6 +358,9 @@ trusted_dir_server_new(const char *nickname, const char *address,
}
if (!hostname)
hostname = tor_dup_ip(a);
+
+ if (!hostname)
+ return NULL;
} else {
if (tor_lookup_hostname(address, &a)) {
log_warn(LD_CONFIG,
diff --git a/src/feature/nodelist/dirlist.h b/src/feature/nodelist/dirlist.h
index c49162f1e9..9201e76a9c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/document_signature_st.h b/src/feature/nodelist/document_signature_st.h
index ac2a803252..4bde9d89ec 100644
--- a/src/feature/nodelist/document_signature_st.h
+++ b/src/feature/nodelist/document_signature_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file document_signature_st.h
+ * @brief Authority signature structure
+ **/
+
#ifndef DOCUMENT_SIGNATURE_ST_H
#define DOCUMENT_SIGNATURE_ST_H
@@ -26,4 +31,3 @@ struct document_signature_t {
};
#endif /* !defined(DOCUMENT_SIGNATURE_ST_H) */
-
diff --git a/src/feature/nodelist/extrainfo_st.h b/src/feature/nodelist/extrainfo_st.h
index 22c708f018..6bd6232cd8 100644
--- a/src/feature/nodelist/extrainfo_st.h
+++ b/src/feature/nodelist/extrainfo_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file extrainfo_st.h
+ * @brief A relay's extra-info structure.
+ **/
+
#ifndef EXTRAINFO_ST_H
#define EXTRAINFO_ST_H
@@ -27,4 +32,3 @@ struct extrainfo_t {
};
#endif /* !defined(EXTRAINFO_ST_H) */
-
diff --git a/src/feature/nodelist/feature_nodelist.md b/src/feature/nodelist/feature_nodelist.md
new file mode 100644
index 0000000000..9d715308c2
--- /dev/null
+++ b/src/feature/nodelist/feature_nodelist.md
@@ -0,0 +1,2 @@
+@dir /feature/nodelist
+@brief feature/nodelist: Download and manage a list of relays
diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c
index fea7cf4c65..ca4a312639 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,10 +27,6 @@
* allocated character buffer. Use the same format as in network-status
* documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
*
- * consensus_method is the current consensus method when format is
- * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other
- * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD.
- *
* Return 0 on success, -1 on failure.
*
* The format argument has one of the following values:
@@ -47,7 +43,6 @@ char *
routerstatus_format_entry(const routerstatus_t *rs, const char *version,
const char *protocols,
routerstatus_format_type_t format,
- int consensus_method,
const vote_routerstatus_t *vrs)
{
char *summary;
@@ -58,6 +53,10 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
char digest64[BASE64_DIGEST_LEN+1];
smartlist_t *chunks = smartlist_new();
+ const char *ip_str = fmt_addr32(rs->addr);
+ if (ip_str[0] == '\0')
+ goto err;
+
format_iso_time(published, rs->published_on);
digest_to_base64(identity64, rs->identity_digest);
digest_to_base64(digest64, rs->descriptor_digest);
@@ -69,7 +68,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
(format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
(format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
published,
- fmt_addr32(rs->addr),
+ ip_str,
(int)rs->or_port,
(int)rs->dir_port);
@@ -78,12 +77,6 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
* networkstatus_type_t values, with an additional control port value
* added -MP */
- /* V3 microdesc consensuses only have "a" lines in later consensus methods
- */
- if (format == NS_V3_CONSENSUS_MICRODESC &&
- consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS)
- goto done;
-
/* Possible "a" line. At most one for now. */
if (!tor_addr_is_null(&rs->ipv6_addr)) {
smartlist_add_asprintf(chunks, "a %s\n",
@@ -124,6 +117,8 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
if (format != NS_CONTROL_PORT) {
/* Blow up more or less nicely if we didn't get anything or not the
* thing we expected.
+ * This should be kept in sync with the function
+ * routerstatus_has_visibly_changed and the struct routerstatus_t
*/
if (!desc) {
char id[HEX_DIGEST_LEN+1];
diff --git a/src/feature/nodelist/fmt_routerstatus.h b/src/feature/nodelist/fmt_routerstatus.h
index ddd7a7cf37..a007989af3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -35,7 +35,6 @@ char *routerstatus_format_entry(
const char *version,
const char *protocols,
routerstatus_format_type_t format,
- int consensus_method,
const vote_routerstatus_t *vrs);
#endif /* !defined(TOR_FMT_ROUTERSTATUS_H) */
diff --git a/src/feature/nodelist/include.am b/src/feature/nodelist/include.am
new file mode 100644
index 0000000000..2f5d58ec1c
--- /dev/null
+++ b/src/feature/nodelist/include.am
@@ -0,0 +1,49 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/nodelist/authcert.c \
+ src/feature/nodelist/describe.c \
+ src/feature/nodelist/dirlist.c \
+ src/feature/nodelist/microdesc.c \
+ src/feature/nodelist/networkstatus.c \
+ src/feature/nodelist/nickname.c \
+ src/feature/nodelist/nodefamily.c \
+ src/feature/nodelist/nodelist.c \
+ src/feature/nodelist/node_select.c \
+ src/feature/nodelist/routerinfo.c \
+ src/feature/nodelist/routerlist.c \
+ src/feature/nodelist/routerset.c \
+ src/feature/nodelist/fmt_routerstatus.c \
+ src/feature/nodelist/torcert.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/nodelist/authcert.h \
+ src/feature/nodelist/authority_cert_st.h \
+ src/feature/nodelist/describe.h \
+ src/feature/nodelist/desc_store_st.h \
+ src/feature/nodelist/dirlist.h \
+ src/feature/nodelist/document_signature_st.h \
+ src/feature/nodelist/extrainfo_st.h \
+ src/feature/nodelist/microdesc.h \
+ src/feature/nodelist/microdesc_st.h \
+ src/feature/nodelist/networkstatus.h \
+ src/feature/nodelist/networkstatus_sr_info_st.h \
+ src/feature/nodelist/networkstatus_st.h \
+ src/feature/nodelist/networkstatus_voter_info_st.h \
+ src/feature/nodelist/nickname.h \
+ src/feature/nodelist/node_st.h \
+ src/feature/nodelist/nodefamily.h \
+ src/feature/nodelist/nodefamily_st.h \
+ src/feature/nodelist/nodelist.h \
+ src/feature/nodelist/node_select.h \
+ src/feature/nodelist/routerinfo.h \
+ src/feature/nodelist/routerinfo_st.h \
+ src/feature/nodelist/routerlist.h \
+ src/feature/nodelist/routerlist_st.h \
+ src/feature/nodelist/routerset.h \
+ src/feature/nodelist/fmt_routerstatus.h \
+ src/feature/nodelist/routerstatus_st.h \
+ src/feature/nodelist/signed_descriptor_st.h \
+ src/feature/nodelist/torcert.h \
+ src/feature/nodelist/vote_routerstatus_st.h
diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c
index 89ac0a2f83..cf7732b8dc 100644
--- a/src/feature/nodelist/microdesc.c
+++ b/src/feature/nodelist/microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2019, The Tor Project, Inc. */
+/* Copyright (c) 2009-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,6 +18,7 @@
#include "feature/client/entrynodes.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dlstatus.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dircommon/directory.h"
#include "feature/dirparse/microdesc_parse.h"
#include "feature/nodelist/dirlist.h"
@@ -89,10 +90,10 @@ microdesc_eq_(microdesc_t *a, microdesc_t *b)
}
HT_PROTOTYPE(microdesc_map, microdesc_t, node,
- microdesc_hash_, microdesc_eq_)
+ microdesc_hash_, microdesc_eq_);
HT_GENERATE2(microdesc_map, microdesc_t, node,
microdesc_hash_, microdesc_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
/************************* md fetch fail cache *****************************/
@@ -997,7 +998,7 @@ update_microdesc_downloads(time_t now)
if (should_delay_dir_fetches(options, NULL))
return;
- if (directory_too_idle_to_fetch_descriptors(options, now))
+ if (dirclient_too_idle_to_fetch_descriptors(options, now))
return;
/* Give up if we don't have a reasonably live consensus. */
diff --git a/src/feature/nodelist/microdesc.h b/src/feature/nodelist/microdesc.h
index c18099d540..b352f58e34 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e017c46c79..410403e965 100644
--- a/src/feature/nodelist/microdesc_st.h
+++ b/src/feature/nodelist/microdesc_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file microdesc_st.h
+ * @brief Microdescriptor structure
+ **/
+
#ifndef MICRODESC_ST_H
#define MICRODESC_ST_H
@@ -12,6 +17,8 @@ struct ed25519_public_key_t;
struct nodefamily_t;
struct short_policy_t;
+#include "ext/ht.h"
+
/** A microdescriptor is the smallest amount of information needed to build a
* circuit through a router. They are generated by the directory authorities,
* using information from the uploaded routerinfo documents. They are not
diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c
index 496bafb865..e07d58c91c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -63,9 +63,10 @@
#include "feature/dircache/consdiffmgr.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirparse/ns_parse.h"
#include "feature/hibernate/hibernate.h"
#include "feature/hs/hs_dos.h"
@@ -101,6 +102,7 @@
#include "feature/nodelist/routerlist_st.h"
#include "feature/dirauth/vote_microdesc_hash_st.h"
#include "feature/nodelist/vote_routerstatus_st.h"
+#include "feature/nodelist/routerstatus_st.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -216,10 +218,10 @@ networkstatus_reset_download_failures(void)
}
/** Return the filename used to cache the consensus of a given flavor */
-static char *
-networkstatus_get_cache_fname(int flav,
- const char *flavorname,
- int unverified_consensus)
+MOCK_IMPL(char *,
+networkstatus_get_cache_fname,(int flav,
+ const char *flavorname,
+ int unverified_consensus))
{
char buf[128];
const char *prefix;
@@ -1162,7 +1164,7 @@ update_consensus_networkstatus_fetch_time_impl(time_t now, int flav)
}
}
- if (directory_fetches_dir_info_early(options)) {
+ if (dirclient_fetches_dir_info_early(options)) {
/* We want to cache the next one at some point after this one
* is no longer fresh... */
start = (time_t)(c->fresh_until + min_sec_before_caching);
@@ -1184,7 +1186,7 @@ update_consensus_networkstatus_fetch_time_impl(time_t now, int flav)
/* If we're a bridge user, make use of the numbers we just computed
* to choose the rest of the interval *after* them. */
- if (directory_fetches_dir_info_later(options)) {
+ if (dirclient_fetches_dir_info_later(options)) {
/* Give all the *clients* enough time to download the consensus. */
start = (time_t)(start + dl_interval + min_sec_before_caching);
/* But try to get it before ours actually expires. */
@@ -1537,7 +1539,7 @@ networkstatus_consensus_can_use_extra_fallbacks,(const or_options_t *options))
>= smartlist_len(router_get_trusted_dir_servers()));
/* If we don't fetch from the authorities, and we have additional mirrors,
* we can use them. */
- return (!directory_fetches_from_authorities(options)
+ return (!dirclient_fetches_from_authorities(options)
&& (smartlist_len(router_get_fallback_dir_servers())
> smartlist_len(router_get_trusted_dir_servers())));
}
@@ -1577,36 +1579,16 @@ networkstatus_consensus_is_already_downloading(const char *resource)
return answer;
}
-/* Does the current, reasonably live consensus have IPv6 addresses?
- * Returns 1 if there is a reasonably live consensus and its consensus method
- * includes IPv6 addresses in the consensus.
- * Otherwise, if there is no consensus, or the method does not include IPv6
- * addresses, returns 0. */
-int
-networkstatus_consensus_has_ipv6(const or_options_t* options)
-{
- const networkstatus_t *cons = networkstatus_get_reasonably_live_consensus(
- approx_time(),
- usable_consensus_flavor());
-
- /* If we have no consensus, we have no IPv6 in it */
- if (!cons) {
- return 0;
- }
-
- /* Different flavours of consensus gained IPv6 at different times */
- if (we_use_microdescriptors_for_circuits(options)) {
- return
- cons->consensus_method >= MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
- } else {
- return 1;
- }
-}
-
-/** Given two router status entries for the same router identity, return 1 if
- * if the contents have changed between them. Otherwise, return 0. */
-static int
-routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b)
+/** Given two router status entries for the same router identity, return 1
+ * if the contents have changed between them. Otherwise, return 0.
+ * It only checks for fields that are output by control port.
+ * This should be kept in sync with the struct routerstatus_t
+ * and the printing function routerstatus_format_entry in
+ * NS_CONTROL_PORT mode.
+ **/
+STATIC int
+routerstatus_has_visibly_changed(const routerstatus_t *a,
+ const routerstatus_t *b)
{
tor_assert(tor_memeq(a->identity_digest, b->identity_digest, DIGEST_LEN));
@@ -1625,9 +1607,14 @@ routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b)
a->is_valid != b->is_valid ||
a->is_possible_guard != b->is_possible_guard ||
a->is_bad_exit != b->is_bad_exit ||
- a->is_hs_dir != b->is_hs_dir;
- // XXXX this function needs a huge refactoring; it has gotten out
- // XXXX of sync with routerstatus_t, and it will do so again.
+ a->is_hs_dir != b->is_hs_dir ||
+ a->is_staledesc != b->is_staledesc ||
+ a->has_bandwidth != b->has_bandwidth ||
+ a->published_on != b->published_on ||
+ a->ipv6_orport != b->ipv6_orport ||
+ a->is_v2_dir != b->is_v2_dir ||
+ a->bandwidth_kb != b->bandwidth_kb ||
+ tor_addr_compare(&a->ipv6_addr, &b->ipv6_addr, CMP_EXACT);
}
/** Notify controllers of any router status entries that changed between
@@ -1659,7 +1646,7 @@ notify_control_networkstatus_changed(const networkstatus_t *old_c,
tor_memcmp(rs_old->identity_digest,
rs_new->identity_digest, DIGEST_LEN),
smartlist_add(changed, (void*) rs_new)) {
- if (routerstatus_has_changed(rs_old, rs_new))
+ if (routerstatus_has_visibly_changed(rs_old, rs_new))
smartlist_add(changed, (void*)rs_new);
} SMARTLIST_FOREACH_JOIN_END(rs_old, rs_new);
@@ -2133,7 +2120,7 @@ networkstatus_set_current_consensus(const char *consensus,
* the first thing we need to do is recalculate the voting schedule static
* object so we can use the timings in there needed by some subsystems
* such as hidden service and shared random. */
- voting_schedule_recalculate_timing(options, now);
+ dirauth_sched_recalculate_timing(options, now);
reschedule_dirvote(options);
nodelist_set_consensus(c);
@@ -2180,7 +2167,7 @@ networkstatus_set_current_consensus(const char *consensus,
warn_early_consensus(c, flavor, now);
- /* We got a new consesus. Reset our md fetch fail cache */
+ /* We got a new consensus. Reset our md fetch fail cache */
microdesc_reset_outdated_dirservers_list();
router_dir_info_changed();
@@ -2364,7 +2351,6 @@ char *
networkstatus_getinfo_helper_single(const routerstatus_t *rs)
{
return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT,
- ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD,
NULL);
}
@@ -2779,3 +2765,47 @@ networkstatus_free_all(void)
}
}
}
+
+/** Return the start of the next interval of size <b>interval</b> (in
+ * seconds) after <b>now</b>, plus <b>offset</b>. Midnight always
+ * starts a fresh interval, and if the last interval of a day would be
+ * truncated to less than half its size, it is rolled into the
+ * previous interval. */
+time_t
+voting_sched_get_start_of_interval_after(time_t now, int interval,
+ int offset)
+{
+ struct tm tm;
+ time_t midnight_today=0;
+ time_t midnight_tomorrow;
+ time_t next;
+
+ tor_gmtime_r(&now, &tm);
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+
+ if (tor_timegm(&tm, &midnight_today) < 0) {
+ // LCOV_EXCL_START
+ log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight.");
+ // LCOV_EXCL_STOP
+ }
+ midnight_tomorrow = midnight_today + (24*60*60);
+
+ next = midnight_today + ((now-midnight_today)/interval + 1)*interval;
+
+ /* Intervals never cross midnight. */
+ if (next > midnight_tomorrow)
+ next = midnight_tomorrow;
+
+ /* If the interval would only last half as long as it's supposed to, then
+ * skip over to the next day. */
+ if (next + interval/2 > midnight_tomorrow)
+ next = midnight_tomorrow;
+
+ next += offset;
+ if (next - interval > now)
+ next -= interval;
+
+ return next;
+}
diff --git a/src/feature/nodelist/networkstatus.h b/src/feature/nodelist/networkstatus.h
index 600fd7fbd5..ce050aeadc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,6 +16,9 @@
void networkstatus_reset_warnings(void);
void networkstatus_reset_download_failures(void);
+MOCK_DECL(char *,networkstatus_get_cache_fname,(int flav,
+ const char *flavorname,
+ int unverified_consensus));
tor_mmap_t *networkstatus_map_cached_consensus(const char *flavorname);
int router_reload_consensus_networkstatus(void);
void routerstatus_free_(routerstatus_t *rs);
@@ -101,7 +104,6 @@ int networkstatus_consensus_can_use_multiple_directories(
MOCK_DECL(int, networkstatus_consensus_can_use_extra_fallbacks,(
const or_options_t *options));
int networkstatus_consensus_is_already_downloading(const char *resource);
-int networkstatus_consensus_has_ipv6(const or_options_t* options);
#define NSSET_FROM_CACHE 1
#define NSSET_WAS_WAITING_FOR_CERTS 2
@@ -151,6 +153,9 @@ void vote_routerstatus_free_(vote_routerstatus_t *rs);
void set_routerstatus_from_routerinfo(routerstatus_t *rs,
const node_t *node,
const routerinfo_t *ri);
+time_t voting_sched_get_start_of_interval_after(time_t now,
+ int interval,
+ int offset);
#ifdef NETWORKSTATUS_PRIVATE
#ifdef TOR_UNIT_TESTS
@@ -161,6 +166,8 @@ STATIC void warn_early_consensus(const networkstatus_t *c, const char *flavor,
extern networkstatus_t *current_ns_consensus;
extern networkstatus_t *current_md_consensus;
#endif /* defined(TOR_UNIT_TESTS) */
+STATIC int routerstatus_has_visibly_changed(const routerstatus_t *a,
+ const routerstatus_t *b);
#endif /* defined(NETWORKSTATUS_PRIVATE) */
#endif /* !defined(TOR_NETWORKSTATUS_H) */
diff --git a/src/feature/nodelist/networkstatus_sr_info_st.h b/src/feature/nodelist/networkstatus_sr_info_st.h
index 420c3d61e4..04d0dfe8f6 100644
--- a/src/feature/nodelist/networkstatus_sr_info_st.h
+++ b/src/feature/nodelist/networkstatus_sr_info_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file networkstatus_sr_info_st.h
+ * @brief Shared-randomness structure.
+ **/
+
#ifndef NETWORKSTATUS_SR_INFO_ST_H
#define NETWORKSTATUS_SR_INFO_ST_H
@@ -20,4 +25,3 @@ struct networkstatus_sr_info_t {
};
#endif /* !defined(NETWORKSTATUS_SR_INFO_ST_H) */
-
diff --git a/src/feature/nodelist/networkstatus_st.h b/src/feature/nodelist/networkstatus_st.h
index 6e84c170d6..021168d3ca 100644
--- a/src/feature/nodelist/networkstatus_st.h
+++ b/src/feature/nodelist/networkstatus_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file networkstatus_st.h
+ * @brief Networkstatus consensus/vote structure.
+ **/
+
#ifndef NETWORKSTATUS_ST_H
#define NETWORKSTATUS_ST_H
diff --git a/src/feature/nodelist/networkstatus_voter_info_st.h b/src/feature/nodelist/networkstatus_voter_info_st.h
index 66af82a8e3..b4d0b1dd17 100644
--- a/src/feature/nodelist/networkstatus_voter_info_st.h
+++ b/src/feature/nodelist/networkstatus_voter_info_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file networkstatus_voter_info_st.h
+ * @brief Single consensus voter structure.
+ **/
+
#ifndef NETWORKSTATUS_VOTER_INFO_ST_H
#define NETWORKSTATUS_VOTER_INFO_ST_H
diff --git a/src/feature/nodelist/nickname.c b/src/feature/nodelist/nickname.c
index 5378b749ca..c022dd6bc4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/nickname.h b/src/feature/nodelist/nickname.h
index 78db2a5f91..11c6416f3a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 719b4b1b27..e831248413 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,6 +19,7 @@
#include "core/or/reasons.h"
#include "feature/client/entrynodes.h"
#include "feature/dirclient/dirclient.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/describe.h"
#include "feature/nodelist/dirlist.h"
@@ -147,7 +148,7 @@ router_pick_dirserver_generic(smartlist_t *sourcelist,
try_ip_pref = 0; \
goto retry_label; \
} \
- STMT_END \
+ STMT_END
/* Common retry code for router_pick_directory_server_impl and
* router_pick_trusteddirserver_impl. Retry without excluding nodes, but with
@@ -322,7 +323,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref);
const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref);
- const int must_have_or = directory_must_use_begindir(options);
+ const int must_have_or = dirclient_must_use_begindir(options);
/* Find all the running dirservers we know about. */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
@@ -541,6 +542,51 @@ bridge_get_advertised_bandwidth_bounded(routerinfo_t *router)
return result;
}
+/**
+ * We have found an instance of bug 32868: log our best guess about where the
+ * routerstatus was found.
+ **/
+static void
+log_buggy_rs_source(const routerstatus_t *rs)
+{
+ static ratelim_t buggy_rs_ratelim = RATELIM_INIT(1200);
+ char *m;
+ if ((m = rate_limit_log(&buggy_rs_ratelim, approx_time()))) {
+ log_warn(LD_BUG,
+ "Found a routerstatus %p with has_guardfraction=%u "
+ " and guardfraction_percentage=%u, but is_possible_guard=%u.%s",
+ rs,
+ rs->has_guardfraction,
+ rs->guardfraction_percentage,
+ rs->is_possible_guard,
+ m);
+ tor_free(m);
+ networkstatus_t *ns;
+ int in_ns_count = 0;
+ if ((ns = networkstatus_get_latest_consensus_by_flavor(FLAV_NS))) {
+ int pos = smartlist_pos(ns->routerstatus_list, rs);
+ if (pos >= 0) {
+ ++in_ns_count;
+ log_warn(LD_BUG, "Found the routerstatus at position %d of the "
+ "NS consensus.", pos);
+ }
+ }
+ if ((ns = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC))) {
+ int pos = smartlist_pos(ns->routerstatus_list, rs);
+ if (pos >= 0) {
+ ++in_ns_count;
+ log_warn(LD_BUG, "Found the routerstatus at position %d of the "
+ "MD consensus.", pos);
+ }
+ }
+ if (in_ns_count == 0) {
+ log_warn(LD_BUG, "Could not find the routerstatus in any "
+ "latest consensus.");
+ }
+ tor_assert_nonfatal_unreached();
+ }
+}
+
/** Given a list of routers and a weighting rule as in
* smartlist_choose_node_by_bandwidth_weights, compute weighted bandwidth
* values for each node and store them in a freshly allocated
@@ -717,10 +763,11 @@ compute_weighted_bandwidths(const smartlist_t *sl,
* choose N proportionally to F*Wpf*B + (1-F)*Wpn*B.
*/
if (node->rs && node->rs->has_guardfraction && rule != WEIGHT_FOR_GUARD) {
- /* XXX The assert should actually check for is_guard. However,
- * that crashes dirauths because of #13297. This should be
- * equivalent: */
- tor_assert(node->rs->is_possible_guard);
+ /* We should only have guardfraction set if the node has the Guard
+ flag. */
+ if (! node->rs->is_possible_guard) {
+ log_buggy_rs_source(node->rs);
+ }
guard_get_guardfraction_bandwidth(&guardfraction_bw,
this_bw,
@@ -1075,7 +1122,7 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref);
const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref);
- const int must_have_or = directory_must_use_begindir(options);
+ const int must_have_or = dirclient_must_use_begindir(options);
SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d)
{
diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h
index d8b4aca5c1..2e67f990f6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 c63a535a19..b1ec4db202 100644
--- a/src/feature/nodelist/node_st.h
+++ b/src/feature/nodelist/node_st.h
@@ -1,14 +1,20 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file node_st.h
+ * @brief Node information structure.
+ **/
+
#ifndef NODE_ST_H
#define NODE_ST_H
#include "feature/hs/hsdir_index_st.h"
#include "lib/crypt_ops/crypto_ed25519.h"
+#include "ext/ht.h"
/** A node_t represents a Tor router.
*
diff --git a/src/feature/nodelist/nodefamily.c b/src/feature/nodelist/nodefamily.c
index 2ec9d5fa40..feaa3730dc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -69,9 +69,9 @@ static HT_HEAD(nodefamily_map, nodefamily_t) the_node_families
= HT_INITIALIZER();
HT_PROTOTYPE(nodefamily_map, nodefamily_t, ht_ent, nodefamily_hash,
- nodefamily_eq)
+ nodefamily_eq);
HT_GENERATE2(nodefamily_map, nodefamily_t, ht_ent, nodefamily_hash,
- node_family_eq, 0.6, tor_reallocarray_, tor_free_)
+ node_family_eq, 0.6, tor_reallocarray_, tor_free_);
/**
* Parse the family declaration in <b>s</b>, returning the canonical
diff --git a/src/feature/nodelist/nodefamily.h b/src/feature/nodelist/nodefamily.h
index 31b71e77a0..16e161ba82 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 20390c9308..c581c917a9 100644
--- a/src/feature/nodelist/nodefamily_st.h
+++ b/src/feature/nodelist/nodefamily_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file nodefamily_st.h
+ * @brief Compact node-family structure
+ **/
+
#ifndef TOR_NODEFAMILY_ST_H
#define TOR_NODEFAMILY_ST_H
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index 9191173c3b..7454f342f9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -51,7 +51,7 @@
#include "feature/client/entrynodes.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/process_descs.h"
-#include "feature/dircache/dirserv.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
#include "feature/nodelist/describe.h"
@@ -153,9 +153,9 @@ node_id_eq(const node_t *node1, const node_t *node2)
return tor_memeq(node1->identity, node2->identity, DIGEST_LEN);
}
-HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq)
+HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq);
HT_GENERATE2(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
static inline unsigned int
node_ed_id_hash(const node_t *node)
@@ -170,9 +170,9 @@ node_ed_id_eq(const node_t *node1, const node_t *node2)
}
HT_PROTOTYPE(nodelist_ed_map, node_t, ed_ht_ent, node_ed_id_hash,
- node_ed_id_eq)
+ node_ed_id_eq);
HT_GENERATE2(nodelist_ed_map, node_t, ed_ht_ent, node_ed_id_hash,
- node_ed_id_eq, 0.6, tor_reallocarray_, tor_free_)
+ node_ed_id_eq, 0.6, tor_reallocarray_, tor_free_);
/** The global nodelist. */
static nodelist_t *the_nodelist=NULL;
@@ -1074,8 +1074,8 @@ node_get_by_nickname,(const char *nickname, unsigned flags))
/** Return the Ed25519 identity key for the provided node, or NULL if it
* doesn't have one. */
-const ed25519_public_key_t *
-node_get_ed25519_id(const node_t *node)
+MOCK_IMPL(const ed25519_public_key_t *,
+node_get_ed25519_id,(const node_t *node))
{
const ed25519_public_key_t *ri_pk = NULL;
const ed25519_public_key_t *md_pk = NULL;
@@ -1158,9 +1158,9 @@ node_get_protover_summary_flags(const node_t *node)
* by ed25519 ID during the link handshake. If <b>compatible_with_us</b>,
* it needs to be using a link authentication method that we understand.
* If not, any plausible link authentication method will do. */
-int
-node_supports_ed25519_link_authentication(const node_t *node,
- int compatible_with_us)
+MOCK_IMPL(int,
+node_supports_ed25519_link_authentication,(const node_t *node,
+ int compatible_with_us))
{
if (! node_get_ed25519_id(node))
return 0;
@@ -1240,8 +1240,8 @@ node_get_rsa_id_digest(const node_t *node)
* If node is NULL, returns an empty smartlist.
*
* The smartlist must be freed using link_specifier_smartlist_free(). */
-smartlist_t *
-node_get_link_specifier_smartlist(const node_t *node, bool direct_conn)
+MOCK_IMPL(smartlist_t *,
+node_get_link_specifier_smartlist,(const node_t *node, bool direct_conn))
{
link_specifier_t *ls;
tor_addr_port_t ap;
@@ -2779,7 +2779,7 @@ update_router_have_minimum_dir_info(void)
/* If paths have just become unavailable in this update. */
if (!res && have_min_dir_info) {
- int quiet = directory_too_idle_to_fetch_descriptors(options, now);
+ int quiet = dirclient_too_idle_to_fetch_descriptors(options, now);
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);
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index 87cfa48e25..57ab2d5913 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -70,18 +70,20 @@ const char *node_get_platform(const node_t *node);
uint32_t node_get_prim_addr_ipv4h(const node_t *node);
void node_get_address_string(const node_t *node, char *cp, size_t len);
long node_get_declared_uptime(const node_t *node);
-const struct ed25519_public_key_t *node_get_ed25519_id(const node_t *node);
+MOCK_DECL(const struct ed25519_public_key_t *,node_get_ed25519_id,
+ (const node_t *node));
int node_ed25519_id_matches(const node_t *node,
const struct ed25519_public_key_t *id);
-int node_supports_ed25519_link_authentication(const node_t *node,
- int compatible_with_us);
+MOCK_DECL(int,node_supports_ed25519_link_authentication,
+ (const node_t *node,
+ int compatible_with_us));
int node_supports_v3_hsdir(const node_t *node);
int node_supports_ed25519_hs_intro(const node_t *node);
int node_supports_v3_rendezvous_point(const node_t *node);
int node_supports_establish_intro_dos_extension(const node_t *node);
const uint8_t *node_get_rsa_id_digest(const node_t *node);
-smartlist_t *node_get_link_specifier_smartlist(const node_t *node,
- bool direct_conn);
+MOCK_DECL(smartlist_t *,node_get_link_specifier_smartlist,(const node_t *node,
+ bool direct_conn));
void link_specifier_smartlist_free_(smartlist_t *ls_list);
#define link_specifier_smartlist_free(ls_list) \
FREE_AND_NULL(smartlist_t, link_specifier_smartlist_free_, (ls_list))
diff --git a/src/feature/nodelist/routerinfo.c b/src/feature/nodelist/routerinfo.c
index 975b503615..0bf2a977f5 100644
--- a/src/feature/nodelist/routerinfo.c
+++ b/src/feature/nodelist/routerinfo.c
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerinfo.c
+ * @brief Manipulate full router descriptors.
+ **/
+
#include "core/or/or.h"
#include "feature/nodelist/nodelist.h"
diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h
index 8465060f93..604e478999 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 59fd56d0a0..36ead50e33 100644
--- a/src/feature/nodelist/routerinfo_st.h
+++ b/src/feature/nodelist/routerinfo_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerinfo_st.h
+ * @brief Router descriptor structure.
+ **/
+
#ifndef ROUTERINFO_ST_H
#define ROUTERINFO_ST_H
@@ -21,9 +26,6 @@ struct routerinfo_t {
uint16_t dir_port; /**< Port for HTTP directory connections. */
/** A router's IPv6 address, if it has one. */
- /* XXXXX187 Actually these should probably be part of a list of addresses,
- * not just a special case. Use abstractions to access these; don't do it
- * directly. */
tor_addr_t ipv6_addr;
uint16_t ipv6_orport;
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index b3cf3e2394..96bea5a670 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -73,6 +73,7 @@
#include "feature/dirauth/reachability.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/authcert.h"
@@ -116,9 +117,9 @@
/* Typed wrappers for different digestmap types; used to avoid type
* confusion. */
-DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
-DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
-DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
+DECLARE_TYPED_DIGESTMAP_FNS(sdmap, digest_sd_map_t, signed_descriptor_t)
+DECLARE_TYPED_DIGESTMAP_FNS(rimap, digest_ri_map_t, routerinfo_t)
+DECLARE_TYPED_DIGESTMAP_FNS(eimap, digest_ei_map_t, extrainfo_t)
#define SDMAP_FOREACH(map, keyvar, valvar) \
DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
valvar)
@@ -1940,9 +1941,7 @@ routerlist_descriptors_added(smartlist_t *sl, int from_cache)
learned_bridge_descriptor(ri, from_cache);
if (ri->needs_retest_if_added) {
ri->needs_retest_if_added = 0;
-#ifdef HAVE_MODULE_DIRAUTH
dirserv_single_reachability_test(approx_time(), ri);
-#endif
}
} SMARTLIST_FOREACH_END(ri);
}
@@ -2410,7 +2409,7 @@ max_dl_per_request(const or_options_t *options, int purpose)
}
/* If we're going to tunnel our connections, we can ask for a lot more
* in a request. */
- if (directory_must_use_begindir(options)) {
+ if (dirclient_must_use_begindir(options)) {
max = 500;
}
return max;
@@ -2453,7 +2452,7 @@ launch_descriptor_downloads(int purpose,
if (!n_downloadable)
return;
- if (!directory_fetches_dir_info_early(options)) {
+ if (!dirclient_fetches_dir_info_early(options)) {
if (n_downloadable >= MAX_DL_TO_DELAY) {
log_debug(LD_DIR,
"There are enough downloadable %ss to launch requests.",
@@ -2544,7 +2543,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
int n_delayed=0, n_have=0, n_would_reject=0, n_wouldnt_use=0,
n_inprogress=0, n_in_oldrouters=0;
- if (directory_too_idle_to_fetch_descriptors(options, now))
+ if (dirclient_too_idle_to_fetch_descriptors(options, now))
goto done;
if (!consensus)
goto done;
@@ -2564,8 +2563,15 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
map = digestmap_new();
list_pending_descriptor_downloads(map, 0);
SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, void *, rsp) {
- routerstatus_t *rs =
- is_vote ? &(((vote_routerstatus_t *)rsp)->status) : rsp;
+ routerstatus_t *rs;
+ vote_routerstatus_t *vrs;
+ if (is_vote) {
+ rs = &(((vote_routerstatus_t *)rsp)->status);
+ vrs = rsp;
+ } else {
+ rs = rsp;
+ vrs = NULL;
+ }
signed_descriptor_t *sd;
if ((sd = router_get_by_descriptor_digest(rs->descriptor_digest))) {
const routerinfo_t *ri;
@@ -2590,7 +2596,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
++n_delayed; /* Not ready for retry. */
continue;
}
- if (authdir && dirserv_would_reject_router(rs)) {
+ if (authdir && is_vote && dirserv_would_reject_router(rs, vrs)) {
++n_would_reject;
continue; /* We would throw it out immediately. */
}
@@ -2920,7 +2926,7 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
(r1->bandwidthburst != r2->bandwidthburst))
return 0;
- /* Did more than 12 hours pass? */
+ /* Has enough time passed between the publication times? */
if (r1->cache_info.published_on + ROUTER_MAX_COSMETIC_TIME_DIFFERENCE
< r2->cache_info.published_on)
return 0;
diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h
index dc9203e015..81a2343540 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/routerlist_st.h b/src/feature/nodelist/routerlist_st.h
index 10b919a1bf..ec8933c7cb 100644
--- a/src/feature/nodelist/routerlist_st.h
+++ b/src/feature/nodelist/routerlist_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerlist_st.h
+ * @brief Router descriptor list structure.
+ **/
+
#ifndef ROUTERLIST_ST_H
#define ROUTERLIST_ST_H
@@ -37,4 +42,3 @@ struct routerlist_t {
};
#endif /* !defined(ROUTERLIST_ST_H) */
-
diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c
index 9a205d39b7..2e06ecbf04 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,7 +17,7 @@
*
* Routersets are typically used for user-specified restrictions, and
* are created by invoking routerset_new and routerset_parse from
- * config.c and confparse.c. To use a routerset, invoke one of
+ * config.c and confmgt.c. To use a routerset, invoke one of
* routerset_contains_...() functions , or use
* routerstatus_get_all_nodes() / routerstatus_subtract_nodes() to
* manipulate a smartlist of node_t pointers.
diff --git a/src/feature/nodelist/routerset.h b/src/feature/nodelist/routerset.h
index f3bf4a1f7c..0e4fedf64e 100644
--- a/src/feature/nodelist/routerset.h
+++ b/src/feature/nodelist/routerset.h
@@ -1,10 +1,10 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file routerlist.h
+ * \file routerset.h
* \brief Header file for routerset.c
**/
@@ -46,6 +46,7 @@ int routerset_len(const routerset_t *set);
struct var_type_def_t;
extern const struct var_type_def_t ROUTERSET_type_defn;
+typedef routerset_t *config_decl_ROUTERSET;
#ifdef ROUTERSET_PRIVATE
#include "lib/container/bitarray.h"
diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h
index 46337c9e52..735c754b31 100644
--- a/src/feature/nodelist/routerstatus_st.h
+++ b/src/feature/nodelist/routerstatus_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerstatus_st.h
+ * @brief Routerstatus (consensus entry) structure
+ **/
+
#ifndef ROUTERSTATUS_ST_H
#define ROUTERSTATUS_ST_H
@@ -12,6 +17,10 @@
/** Contents of a single router entry in a network status object.
*/
struct routerstatus_t {
+ /* This should be kept in sync with the function
+ * routerstatus_has_visibly_changed and the printing function
+ * routerstatus_format_entry in NS_CONTROL_PORT mode.
+ */
time_t published_on; /**< When was this router published? */
char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it
* has. */
@@ -79,4 +88,3 @@ struct routerstatus_t {
};
#endif /* !defined(ROUTERSTATUS_ST_H) */
-
diff --git a/src/feature/nodelist/signed_descriptor_st.h b/src/feature/nodelist/signed_descriptor_st.h
index 64c28f7440..068f2a733c 100644
--- a/src/feature/nodelist/signed_descriptor_st.h
+++ b/src/feature/nodelist/signed_descriptor_st.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file signed_descriptor_st.h
+ * @brief Descriptor/extrainfo signature structure
+ **/
+
#ifndef SIGNED_DESCRIPTOR_ST_H
#define SIGNED_DESCRIPTOR_ST_H
@@ -58,4 +63,3 @@ struct signed_descriptor_t {
};
#endif /* !defined(SIGNED_DESCRIPTOR_ST_H) */
-
diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c
index 270c14eb1c..89cc9c88fb 100644
--- a/src/feature/nodelist/torcert.c
+++ b/src/feature/nodelist/torcert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h
index 03d5bdca93..f8fba2b794 100644
--- a/src/feature/nodelist/torcert.h
+++ b/src/feature/nodelist/torcert.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file torcert.h
+ * @brief Header for torcert.c
+ **/
+
#ifndef TORCERT_H_INCLUDED
#define TORCERT_H_INCLUDED
diff --git a/src/feature/nodelist/vote_routerstatus_st.h b/src/feature/nodelist/vote_routerstatus_st.h
index 0d909da260..ad0ee3f23b 100644
--- a/src/feature/nodelist/vote_routerstatus_st.h
+++ b/src/feature/nodelist/vote_routerstatus_st.h
@@ -1,9 +1,13 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file vote_routerstatus_st.h
+ * @brief Routerstatus (vote entry) structure
+ **/
#ifndef VOTE_ROUTERSTATUS_ST_H
#define VOTE_ROUTERSTATUS_ST_H
diff --git a/src/feature/relay/.may_include b/src/feature/relay/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/relay/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
new file mode 100644
index 0000000000..b89866b477
--- /dev/null
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -0,0 +1,549 @@
+/* Copyright (c) 2001 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 circuitbuild_relay.c
+ * @brief Implements the details of exteding circuits (by relaying extend
+ * cells as create cells, and answering create cells).
+ *
+ * On the server side, this module handles the logic of responding to
+ * RELAY_EXTEND requests, using circuit_extend() and onionskin_answer().
+ *
+ * The shared client and server code is in core/or/circuitbuild.c.
+ **/
+
+#include "orconfig.h"
+#include "feature/relay/circuitbuild_relay.h"
+
+#include "lib/crypt_ops/crypto_rand.h"
+
+#include "core/or/or.h"
+#include "app/config/config.h"
+
+#include "core/crypto/relay_crypto.h"
+
+#include "core/or/cell_st.h"
+#include "core/or/circuit_st.h"
+#include "core/or/extend_info_st.h"
+#include "core/or/or_circuit_st.h"
+
+#include "core/or/channel.h"
+#include "core/or/circuitbuild.h"
+#include "core/or/circuitlist.h"
+#include "core/or/onion.h"
+#include "core/or/relay.h"
+
+#include "feature/nodelist/nodelist.h"
+
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+#include "feature/relay/selftest.h"
+
+/* Before replying to an extend cell, check the state of the circuit
+ * <b>circ</b>, and the configured tor mode.
+ *
+ * <b>circ</b> must not be NULL.
+ *
+ * If the state and mode are valid, return 0.
+ * Otherwise, if they are invalid, log a protocol warning, and return -1.
+ */
+STATIC int
+circuit_extend_state_valid_helper(const struct circuit_t *circ)
+{
+ if (!server_mode(get_options())) {
+ circuitbuild_warn_client_extend();
+ return -1;
+ }
+
+ IF_BUG_ONCE(!circ) {
+ return -1;
+ }
+
+ if (circ->n_chan) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "n_chan already set. Bug/attack. Closing.");
+ return -1;
+ }
+
+ if (circ->n_hop) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "conn to next hop already launched. Bug/attack. Closing.");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Make sure the extend cell <b>ec</b> has an ed25519 link specifier.
+ *
+ * First, check that the RSA node id is valid.
+ * If the node id is valid, add the ed25519 link specifier (if required),
+ * and return 0.
+ *
+ * Otherwise, if the node id is invalid, log a protocol warning,
+ * and return -1.(And do not modify the extend cell.)
+ *
+ * Must be called before circuit_extend_lspec_valid_helper().
+ */
+STATIC int
+circuit_extend_add_ed25519_helper(struct extend_cell_t *ec)
+{
+ IF_BUG_ONCE(!ec) {
+ return -1;
+ }
+
+ /* Check if they asked us for 0000..0000. We support using
+ * an empty fingerprint for the first hop (e.g. for a bridge relay),
+ * but we don't want to let clients send us extend cells for empty
+ * fingerprints -- a) because it opens the user up to a mitm attack,
+ * and b) because it lets an attacker force the relay to hold open a
+ * new TLS connection for each extend request. */
+ if (tor_digest_is_zero((const char*)ec->node_id)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Client asked me to extend without specifying an id_digest.");
+ return -1;
+ }
+
+ /* Fill in ed_pubkey if it was not provided and we can infer it from
+ * our networkstatus */
+ if (ed25519_public_key_is_zero(&ec->ed_pubkey)) {
+ const node_t *node = node_get_by_id((const char*)ec->node_id);
+ const ed25519_public_key_t *node_ed_id = NULL;
+ if (node &&
+ node_supports_ed25519_link_authentication(node, 1) &&
+ (node_ed_id = node_get_ed25519_id(node))) {
+ ed25519_pubkey_copy(&ec->ed_pubkey, node_ed_id);
+ }
+ }
+
+ return 0;
+}
+
+/* Check if the address and port in the tor_addr_port_t <b>ap</b> are valid,
+ * and are allowed by the current ExtendAllowPrivateAddresses config.
+ *
+ * If they are valid, return true.
+ * Otherwise, if they are invalid, return false.
+ *
+ * If <b>log_zero_addrs</b> is true, log warnings about zero addresses at
+ * <b>log_level</b>. If <b>log_internal_addrs</b> is true, log warnings about
+ * internal addresses at <b>log_level</b>.
+ */
+static bool
+circuit_extend_addr_port_is_valid(const struct tor_addr_port_t *ap,
+ bool log_zero_addrs, bool log_internal_addrs,
+ int log_level)
+{
+ /* It's safe to print the family. But we don't want to print the address,
+ * unless specifically configured to do so. (Zero addresses aren't sensitive,
+ * But some internal addresses might be.)*/
+
+ if (!tor_addr_port_is_valid_ap(ap, 0)) {
+ if (log_zero_addrs) {
+ log_fn(log_level, LD_PROTOCOL,
+ "Client asked me to extend to a zero destination port or "
+ "%s address '%s'.",
+ fmt_addr_family(&ap->addr), safe_str(fmt_addrport_ap(ap)));
+ }
+ return false;
+ }
+
+ if (tor_addr_is_internal(&ap->addr, 0) &&
+ !get_options()->ExtendAllowPrivateAddresses) {
+ if (log_internal_addrs) {
+ log_fn(log_level, LD_PROTOCOL,
+ "Client asked me to extend to a private %s address '%s'.",
+ fmt_addr_family(&ap->addr),
+ safe_str(fmt_and_decorate_addr(&ap->addr)));
+ }
+ return false;
+ }
+
+ return true;
+}
+
+/* Before replying to an extend cell, check the link specifiers in the extend
+ * cell <b>ec</b>, which was received on the circuit <b>circ</b>.
+ *
+ * If they are valid, return 0.
+ * Otherwise, if they are invalid, log a protocol warning, and return -1.
+ *
+ * Must be called after circuit_extend_add_ed25519_helper().
+ */
+STATIC int
+circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
+ const struct circuit_t *circ)
+{
+ IF_BUG_ONCE(!ec) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!circ) {
+ return -1;
+ }
+
+ /* Check the addresses, without logging */
+ const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
+ false, false, 0);
+ const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
+ false, false, 0);
+ /* We need at least one valid address */
+ if (!ipv4_valid && !ipv6_valid) {
+ /* Now, log the invalid addresses at protocol warning level */
+ circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
+ true, true, LOG_PROTOCOL_WARN);
+ circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
+ true, true, LOG_PROTOCOL_WARN);
+ /* And fail */
+ return -1;
+ } else if (!ipv4_valid) {
+ /* Always log unexpected internal addresses, but go on to use the other
+ * valid address */
+ circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
+ false, true, LOG_PROTOCOL_WARN);
+ } else if (!ipv6_valid) {
+ circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
+ false, true, LOG_PROTOCOL_WARN);
+ }
+
+ IF_BUG_ONCE(circ->magic != OR_CIRCUIT_MAGIC) {
+ return -1;
+ }
+
+ const channel_t *p_chan = CONST_TO_OR_CIRCUIT(circ)->p_chan;
+
+ IF_BUG_ONCE(!p_chan) {
+ return -1;
+ }
+
+ /* Next, check if we're being asked to connect to the hop that the
+ * extend cell came from. There isn't any reason for that, and it can
+ * assist circular-path attacks. */
+ if (tor_memeq(ec->node_id, p_chan->identity_digest, DIGEST_LEN)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Client asked me to extend back to the previous hop.");
+ return -1;
+ }
+
+ /* Check the previous hop Ed25519 ID too */
+ if (! ed25519_public_key_is_zero(&ec->ed_pubkey) &&
+ ed25519_pubkey_eq(&ec->ed_pubkey, &p_chan->ed25519_identity)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Client asked me to extend back to the previous hop "
+ "(by Ed25519 ID).");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* If possible, return a supported, non-NULL IP address.
+ *
+ * If both addresses are supported and non-NULL, choose one uniformly at
+ * random.
+ *
+ * If we have an IPv6-only extend, but IPv6 is not supported, returns NULL.
+ * If both addresses are NULL, also returns NULL. */
+STATIC const tor_addr_port_t *
+circuit_choose_ip_ap_for_extend(const tor_addr_port_t *ipv4_ap,
+ const tor_addr_port_t *ipv6_ap)
+{
+ const bool ipv6_supported = router_can_extend_over_ipv6(get_options());
+
+ /* If IPv6 is not supported, we can't use the IPv6 address. */
+ if (!ipv6_supported) {
+ ipv6_ap = NULL;
+ }
+
+ /* If there is no IPv6 address, IPv4 is always supported.
+ * Until clients include IPv6 ORPorts, and most relays support IPv6,
+ * this is the most common case. */
+ if (!ipv6_ap) {
+ return ipv4_ap;
+ }
+
+ /* If there is no IPv4 address, return the (possibly NULL) IPv6 address. */
+ if (!ipv4_ap) {
+ return ipv6_ap;
+ }
+
+ /* Now we have an IPv4 and an IPv6 address, and IPv6 is supported.
+ * So make an IPv6 connection at random, with probability 1 in N.
+ * 1 means "always IPv6 (and no IPv4)"
+ * 2 means "equal probability of IPv4 or IPv6"
+ * ... (and so on) ...
+ * (UINT_MAX - 1) means "almost always IPv4 (and almost never IPv6)"
+ * To disable IPv6, set ipv6_supported to 0.
+ */
+#define IPV6_CONNECTION_ONE_IN_N 2
+
+ bool choose_ipv6 = crypto_fast_rng_one_in_n(get_thread_fast_rng(),
+ IPV6_CONNECTION_ONE_IN_N);
+ if (choose_ipv6) {
+ return ipv6_ap;
+ } else {
+ return ipv4_ap;
+ }
+}
+
+/* When there is no open channel for an extend cell <b>ec</b>, set up the
+ * circuit <b>circ</b> to wait for a new connection.
+ *
+ * If <b>should_launch</b> is true, open a new connection. (Otherwise, we are
+ * already waiting for a new connection to the same relay.)
+ *
+ * Check if IPv6 extends are supported by our current configuration. If they
+ * are, new connections may be made over IPv4 or IPv6. (IPv4 connections are
+ * always supported.)
+ */
+STATIC void
+circuit_open_connection_for_extend(const struct extend_cell_t *ec,
+ struct circuit_t *circ,
+ int should_launch)
+{
+ /* We have to check circ first, so we can close it on all other failures */
+ IF_BUG_ONCE(!circ) {
+ /* We can't mark a NULL circuit for close. */
+ return;
+ }
+
+ /* Now we know that circ is not NULL */
+ IF_BUG_ONCE(!ec) {
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+
+ /* Check the addresses, without logging */
+ const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
+ false, false, 0);
+ const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
+ false, false, 0);
+
+ IF_BUG_ONCE(!ipv4_valid && !ipv6_valid) {
+ /* circuit_extend_lspec_valid_helper() should have caught this */
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+
+ const tor_addr_port_t *chosen_ap = circuit_choose_ip_ap_for_extend(
+ ipv4_valid ? &ec->orport_ipv4 : NULL,
+ ipv6_valid ? &ec->orport_ipv6 : NULL);
+ if (!chosen_ap) {
+ /* An IPv6-only extend, but IPv6 is not supported */
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received IPv6-only extend, but we don't have an IPv6 ORPort.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+
+ circ->n_hop = extend_info_new(NULL /*nickname*/,
+ (const char*)ec->node_id,
+ &ec->ed_pubkey,
+ NULL, /*onion_key*/
+ NULL, /*curve25519_key*/
+ &chosen_ap->addr,
+ chosen_ap->port);
+
+ circ->n_chan_create_cell = tor_memdup(&ec->create_cell,
+ sizeof(ec->create_cell));
+
+ circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
+
+ if (should_launch) {
+ /* we should try to open a connection */
+ channel_t *n_chan = channel_connect_for_circuit(
+ &circ->n_hop->addr,
+ circ->n_hop->port,
+ circ->n_hop->identity_digest,
+ &circ->n_hop->ed_identity);
+ if (!n_chan) {
+ log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+ log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
+ }
+}
+
+/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion
+ * skin and identity digest for the next hop. If we're already connected,
+ * pass the onion skin to the next hop using a create cell; otherwise
+ * launch a new OR connection, and <b>circ</b> will notice when the
+ * connection succeeds or fails.
+ *
+ * Return -1 if we want to warn and tear down the circuit, else return 0.
+ */
+int
+circuit_extend(struct cell_t *cell, struct circuit_t *circ)
+{
+ channel_t *n_chan;
+ relay_header_t rh;
+ extend_cell_t ec;
+ const char *msg = NULL;
+ int should_launch = 0;
+
+ IF_BUG_ONCE(!cell) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!circ) {
+ return -1;
+ }
+
+ if (circuit_extend_state_valid_helper(circ) < 0)
+ return -1;
+
+ relay_header_unpack(&rh, cell->payload);
+
+ if (extend_cell_parse(&ec, rh.command,
+ cell->payload+RELAY_HEADER_SIZE,
+ rh.length) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Can't parse extend cell. Closing circuit.");
+ return -1;
+ }
+
+ if (circuit_extend_add_ed25519_helper(&ec) < 0)
+ return -1;
+
+ if (circuit_extend_lspec_valid_helper(&ec, circ) < 0)
+ return -1;
+
+ /* Check the addresses, without logging */
+ const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec.orport_ipv4,
+ false, false, 0);
+ const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec.orport_ipv6,
+ false, false, 0);
+ IF_BUG_ONCE(!ipv4_valid && !ipv6_valid) {
+ /* circuit_extend_lspec_valid_helper() should have caught this */
+ return -1;
+ }
+
+ n_chan = channel_get_for_extend((const char*)ec.node_id,
+ &ec.ed_pubkey,
+ ipv4_valid ? &ec.orport_ipv4.addr : NULL,
+ ipv6_valid ? &ec.orport_ipv6.addr : NULL,
+ &msg,
+ &should_launch);
+
+ if (!n_chan) {
+ /* We can't use fmt_addr*() twice in the same function call,
+ * because it uses a static buffer. */
+ log_debug(LD_CIRC|LD_OR, "Next router IPv4 (%s): %s.",
+ fmt_addrport_ap(&ec.orport_ipv4),
+ msg ? msg : "????");
+ log_debug(LD_CIRC|LD_OR, "Next router IPv6 (%s).",
+ fmt_addrport_ap(&ec.orport_ipv6));
+
+ circuit_open_connection_for_extend(&ec, circ, should_launch);
+
+ /* return success. The onion/circuit/etc will be taken care of
+ * automatically (may already have been) whenever n_chan reaches
+ * OR_CONN_STATE_OPEN.
+ */
+ return 0;
+ } else {
+ /* Connection is already established.
+ * So we need to extend the circuit to the next hop. */
+ tor_assert(!circ->n_hop);
+ circ->n_chan = n_chan;
+ log_debug(LD_CIRC,
+ "n_chan is %s.",
+ channel_get_canonical_remote_descr(n_chan));
+
+ if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
+ return -1;
+
+ return 0;
+ }
+}
+
+/** On a relay, accept a create cell, initialise a circuit, and send a
+ * created cell back.
+ *
+ * Given:
+ * - a response payload consisting of:
+ * - the <b>created_cell</b> and
+ * - an optional <b>rend_circ_nonce</b>, and
+ * - <b>keys</b> of length <b>keys_len</b>, which must be
+ * CPATH_KEY_MATERIAL_LEN;
+ * then:
+ * - initialize the circuit <b>circ</b>'s cryptographic material,
+ * - set the circuit's state to open, and
+ * - send a created cell back on that circuit.
+ *
+ * If we haven't found our ORPorts reachable yet, and the channel meets the
+ * necessary conditions, mark the relevant ORPorts as reachable.
+ *
+ * Returns -1 if cell or circuit initialisation fails.
+ */
+int
+onionskin_answer(struct or_circuit_t *circ,
+ const created_cell_t *created_cell,
+ const char *keys, size_t keys_len,
+ const uint8_t *rend_circ_nonce)
+{
+ cell_t cell;
+
+ IF_BUG_ONCE(!circ) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!created_cell) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!keys) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!rend_circ_nonce) {
+ return -1;
+ }
+
+ tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
+
+ if (created_cell_format(&cell, created_cell) < 0) {
+ log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d).",
+ (int)created_cell->cell_type, (int)created_cell->handshake_len);
+ return -1;
+ }
+ cell.circ_id = circ->p_circ_id;
+
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
+
+ log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
+ (unsigned int)get_uint32(keys),
+ (unsigned int)get_uint32(keys+20));
+ if (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) {
+ log_warn(LD_BUG,"Circuit initialization failed.");
+ return -1;
+ }
+
+ memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
+
+ int used_create_fast = (created_cell->cell_type == CELL_CREATED_FAST);
+
+ append_cell_to_circuit_queue(TO_CIRCUIT(circ),
+ circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
+ log_debug(LD_CIRC,"Finished sending '%s' cell.",
+ used_create_fast ? "created_fast" : "created");
+
+ /* Ignore the local bit when ExtendAllowPrivateAddresses is set:
+ * it violates the assumption that private addresses are local.
+ * Also, many test networks run on local addresses, and
+ * TestingTorNetwork sets ExtendAllowPrivateAddresses. */
+ if ((!channel_is_local(circ->p_chan)
+ || get_options()->ExtendAllowPrivateAddresses)
+ && !channel_is_outgoing(circ->p_chan)) {
+ /* record that we could process create cells from a non-local conn
+ * that we didn't initiate; presumably this means that create cells
+ * can reach us too. */
+ router_orport_found_reachable();
+ }
+
+ return 0;
+}
diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h
new file mode 100644
index 0000000000..0783161538
--- /dev/null
+++ b/src/feature/relay/circuitbuild_relay.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2001 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 circuitbuild_relay.h
+ * @brief Header for feature/relay/circuitbuild_relay.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H
+#define TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H
+
+#include "lib/cc/torint.h"
+#include "lib/log/log.h"
+
+#include "app/config/config.h"
+
+struct cell_t;
+struct created_cell_t;
+
+struct circuit_t;
+struct or_circuit_t;
+struct extend_cell_t;
+
+/* Log a protocol warning about getting an extend cell on a client. */
+static inline void
+circuitbuild_warn_client_extend(void)
+{
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Got an extend cell, but running as a client. Closing.");
+}
+
+#ifdef HAVE_MODULE_RELAY
+
+int circuit_extend(struct cell_t *cell, struct circuit_t *circ);
+
+int onionskin_answer(struct or_circuit_t *circ,
+ const struct created_cell_t *created_cell,
+ const char *keys, size_t keys_len,
+ const uint8_t *rend_circ_nonce);
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+static inline int
+circuit_extend(struct cell_t *cell, struct circuit_t *circ)
+{
+ (void)cell;
+ (void)circ;
+ circuitbuild_warn_client_extend();
+ return -1;
+}
+
+static inline int
+onionskin_answer(struct or_circuit_t *circ,
+ const struct created_cell_t *created_cell,
+ const char *keys, size_t keys_len,
+ const uint8_t *rend_circ_nonce)
+{
+ (void)circ;
+ (void)created_cell;
+ (void)keys;
+ (void)keys_len;
+ (void)rend_circ_nonce;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
+#ifdef TOR_UNIT_TESTS
+
+STATIC int circuit_extend_state_valid_helper(const struct circuit_t *circ);
+STATIC int circuit_extend_add_ed25519_helper(struct extend_cell_t *ec);
+STATIC int circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
+ const struct circuit_t *circ);
+STATIC const tor_addr_port_t * circuit_choose_ip_ap_for_extend(
+ const tor_addr_port_t *ipv4_ap,
+ const tor_addr_port_t *ipv6_ap);
+STATIC void circuit_open_connection_for_extend(const struct extend_cell_t *ec,
+ struct circuit_t *circ,
+ int should_launch);
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* !defined(TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H) */
diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c
index d62598d46f..b83bd9b758 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -146,9 +146,9 @@ cached_resolve_hash(cached_resolve_t *a)
}
HT_PROTOTYPE(cache_map, cached_resolve_t, node, cached_resolve_hash,
- cached_resolves_eq)
+ cached_resolves_eq);
HT_GENERATE2(cache_map, cached_resolve_t, node, cached_resolve_hash,
- cached_resolves_eq, 0.6, tor_reallocarray_, tor_free_)
+ cached_resolves_eq, 0.6, tor_reallocarray_, tor_free_);
/** Initialize the DNS cache. */
static void
@@ -268,22 +268,6 @@ has_dns_init_failed(void)
return nameserver_config_failed;
}
-/** Helper: Given a TTL from a DNS response, determine what TTL to give the
- * OP that asked us to resolve it, and how long to cache that record
- * ourselves. */
-uint32_t
-dns_clip_ttl(uint32_t ttl)
-{
- /* This logic is a defense against "DefectTor" DNS-based traffic
- * confirmation attacks, as in https://nymity.ch/tor-dns/tor-dns.pdf .
- * We only give two values: a "low" value and a "high" value.
- */
- if (ttl < MIN_DNS_TTL_AT_EXIT)
- return MIN_DNS_TTL_AT_EXIT;
- else
- return MAX_DNS_TTL_AT_EXIT;
-}
-
/** Helper: free storage held by an entry in the DNS cache. */
static void
free_cached_resolve_(cached_resolve_t *r)
@@ -521,7 +505,7 @@ send_resolved_cell,(edge_connection_t *conn, uint8_t answer_type,
uint32_t ttl;
buf[0] = answer_type;
- ttl = dns_clip_ttl(conn->address_ttl);
+ ttl = clip_dns_ttl(conn->address_ttl);
switch (answer_type)
{
@@ -593,7 +577,7 @@ send_resolved_hostname_cell,(edge_connection_t *conn,
size_t namelen = strlen(hostname);
tor_assert(namelen < 256);
- ttl = dns_clip_ttl(conn->address_ttl);
+ ttl = clip_dns_ttl(conn->address_ttl);
buf[0] = RESOLVED_TYPE_HOSTNAME;
buf[1] = (uint8_t)namelen;
@@ -987,25 +971,6 @@ assert_connection_edge_not_dns_pending(edge_connection_t *conn)
#endif /* 1 */
}
-/** Log an error and abort if any connection waiting for a DNS resolve is
- * corrupted. */
-void
-assert_all_pending_dns_resolves_ok(void)
-{
- pending_connection_t *pend;
- cached_resolve_t **resolve;
-
- HT_FOREACH(resolve, cache_map, &cache_root) {
- for (pend = (*resolve)->pending_connections;
- pend;
- pend = pend->next) {
- assert_connection_ok(TO_CONN(pend->conn), 0);
- tor_assert(!SOCKET_OK(pend->conn->base_.s));
- tor_assert(!connection_in_array(TO_CONN(pend->conn)));
- }
- }
-}
-
/** Remove <b>conn</b> from the list of connections waiting for conn-\>address.
*/
void
@@ -1063,7 +1028,7 @@ connection_dns_remove(edge_connection_t *conn)
* the resolve for <b>address</b> itself, and remove any cached results for
* <b>address</b> from the cache.
*/
-MOCK_IMPL(void,
+MOCK_IMPL(STATIC void,
dns_cancel_pending_resolve,(const char *address))
{
pending_connection_t *pend;
@@ -1338,7 +1303,7 @@ make_pending_resolve_cached(cached_resolve_t *resolve)
resolve->ttl_hostname < ttl)
ttl = resolve->ttl_hostname;
- set_expiry(new_resolve, time(NULL) + dns_clip_ttl(ttl));
+ set_expiry(new_resolve, time(NULL) + clip_dns_ttl(ttl));
}
assert_cache_ok();
@@ -1626,12 +1591,17 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
} else if (type == DNS_IPv6_AAAA && count) {
char answer_buf[TOR_ADDR_BUF_LEN];
char *escaped_address;
+ const char *ip_str;
struct in6_addr *addrs = addresses;
tor_addr_from_in6(&addr, &addrs[0]);
- tor_inet_ntop(AF_INET6, &addrs[0], answer_buf, sizeof(answer_buf));
+ ip_str = tor_inet_ntop(AF_INET6, &addrs[0], answer_buf,
+ sizeof(answer_buf));
escaped_address = esc_for_log(string_address);
- if (answer_is_wildcarded(answer_buf)) {
+ if (BUG(ip_str == NULL)) {
+ log_warn(LD_EXIT, "tor_inet_ntop() failed!");
+ result = DNS_ERR_NOTEXIST;
+ } else if (answer_is_wildcarded(answer_buf)) {
log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked "
"address %s; treating as a failure.",
safe_str(escaped_address),
@@ -1898,6 +1868,7 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl,
void *addresses, void *arg)
{
(void)ttl;
+ const char *ip_str;
++n_wildcard_requests;
if (result == DNS_ERR_NONE && count) {
char *string_address = arg;
@@ -1907,16 +1878,22 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl,
for (i = 0; i < count; ++i) {
char answer_buf[INET_NTOA_BUF_LEN+1];
struct in_addr in;
+ int ntoa_res;
in.s_addr = addrs[i];
- tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
- wildcard_increment_answer(answer_buf);
+ ntoa_res = tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
+ tor_assert_nonfatal(ntoa_res >= 0);
+ if (ntoa_res > 0)
+ wildcard_increment_answer(answer_buf);
}
} else if (type == DNS_IPv6_AAAA) {
const struct in6_addr *addrs = addresses;
for (i = 0; i < count; ++i) {
char answer_buf[TOR_ADDR_BUF_LEN+1];
- tor_inet_ntop(AF_INET6, &addrs[i], answer_buf, sizeof(answer_buf));
- wildcard_increment_answer(answer_buf);
+ ip_str = tor_inet_ntop(AF_INET6, &addrs[i], answer_buf,
+ sizeof(answer_buf));
+ tor_assert_nonfatal(ip_str);
+ if (ip_str)
+ wildcard_increment_answer(answer_buf);
}
}
@@ -2051,12 +2028,12 @@ dns_launch_correctness_checks(void)
/* Wait a while before launching requests for test addresses, so we can
* get the results from checking for wildcarding. */
- if (! launch_event)
+ if (!launch_event)
launch_event = tor_evtimer_new(tor_libevent_get_base(),
launch_test_addresses, NULL);
timeout.tv_sec = 30;
timeout.tv_usec = 0;
- if (evtimer_add(launch_event, &timeout)<0) {
+ if (evtimer_add(launch_event, &timeout) < 0) {
log_warn(LD_BUG, "Couldn't add timer for checking for dns hijacking");
}
}
@@ -2188,7 +2165,7 @@ dns_cache_handle_oom(time_t now, size_t min_remove_bytes)
total_bytes_removed += bytes_removed;
/* Increase time_inc by a reasonable fraction. */
- time_inc += (MAX_DNS_TTL_AT_EXIT / 4);
+ time_inc += (MAX_DNS_TTL / 4);
} while (total_bytes_removed < min_remove_bytes);
return total_bytes_removed;
diff --git a/src/feature/relay/dns.h b/src/feature/relay/dns.h
index 7b2a31a311..120b75bf8d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,29 +12,14 @@
#ifndef TOR_DNS_H
#define TOR_DNS_H
-/** Lowest value for DNS ttl that a server will give. */
-#define MIN_DNS_TTL_AT_EXIT (5*60)
-/** Highest value for DNS ttl that a server will give. */
-#define MAX_DNS_TTL_AT_EXIT (60*60)
-
-/** How long do we keep DNS cache entries before purging them (regardless of
- * their TTL)? */
-#define MAX_DNS_ENTRY_AGE (3*60*60)
-/** How long do we cache/tell clients to cache DNS records when no TTL is
- * known? */
-#define DEFAULT_DNS_TTL (30*60)
+#ifdef HAVE_MODULE_RELAY
int dns_init(void);
int has_dns_init_failed(void);
-void dns_free_all(void);
-uint32_t dns_clip_ttl(uint32_t ttl);
int dns_reset(void);
void connection_dns_remove(edge_connection_t *conn);
void assert_connection_edge_not_dns_pending(edge_connection_t *conn);
-void assert_all_pending_dns_resolves_ok(void);
-MOCK_DECL(void,dns_cancel_pending_resolve,(const char *question));
int dns_resolve(edge_connection_t *exitconn);
-void dns_launch_correctness_checks(void);
int dns_seems_to_be_broken(void);
int dns_seems_to_be_broken_for_ipv6(void);
void dns_reset_correctness_checks(void);
@@ -42,6 +27,48 @@ 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);
+/* These functions are only used within the feature/relay module, and don't
+ * need stubs. */
+void dns_free_all(void);
+void dns_launch_correctness_checks(void);
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#define dns_init() (0)
+#define dns_seems_to_be_broken() (0)
+#define has_dns_init_failed() (0)
+#define dns_cache_total_allocation() (0)
+
+#define dns_reset_correctness_checks() STMT_NIL
+
+#define assert_connection_edge_not_dns_pending(conn) \
+ ((void)(conn))
+#define dump_dns_mem_usage(severity)\
+ ((void)(severity))
+#define dns_cache_handle_oom(now, bytes) \
+ ((void)(now), (void)(bytes), 0)
+
+#define connection_dns_remove(conn) \
+ STMT_BEGIN \
+ (void)(conn); \
+ tor_assert_nonfatal_unreached(); \
+ STMT_END
+
+static inline int
+dns_reset(void)
+{
+ return 0;
+}
+static inline int
+dns_resolve(edge_connection_t *exitconn)
+{
+ (void)exitconn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
#ifdef DNS_PRIVATE
#include "feature/relay/dns_structs.h"
@@ -50,6 +77,7 @@ size_t number_of_configured_nameservers(void);
tor_addr_t *configured_nameserver_address(const size_t idx);
#endif
+MOCK_DECL(STATIC void,dns_cancel_pending_resolve,(const char *question));
MOCK_DECL(STATIC int,dns_resolve_impl,(edge_connection_t *exitconn,
int is_resolve,or_circuit_t *oncirc, char **hostname_out,
int *made_connection_pending_out, cached_resolve_t **resolve_out));
@@ -74,4 +102,3 @@ launch_resolve,(cached_resolve_t *resolve));
#endif /* defined(DNS_PRIVATE) */
#endif /* !defined(TOR_DNS_H) */
-
diff --git a/src/feature/relay/dns_structs.h b/src/feature/relay/dns_structs.h
index e128746f81..27a791b9b3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,8 @@
#ifndef TOR_DNS_STRUCTS_H
#define TOR_DNS_STRUCTS_H
+#include "ext/ht.h"
+
/** Longest hostname we're willing to resolve. */
#define MAX_ADDRESSLEN 256
@@ -99,4 +101,3 @@ typedef struct cached_resolve_t {
} cached_resolve_t;
#endif /* !defined(TOR_DNS_STRUCTS_H) */
-
diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c
index c343d19b8d..2cf30262f5 100644
--- a/src/feature/relay/ext_orport.c
+++ b/src/feature/relay/ext_orport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -494,6 +494,10 @@ connection_ext_or_handle_cmd_useraddr(connection_t *conn,
}
conn->address = tor_addr_to_str_dup(&addr);
+ /* Now that we know the address, we don't have to manually override rate
+ * limiting. */
+ conn->always_rate_limit_as_remote = 0;
+
return 0;
}
@@ -602,7 +606,7 @@ connection_ext_or_process_inbuf(or_connection_t *or_conn)
command->body, command->len) < 0)
goto err;
} else {
- log_notice(LD_NET,"Got Extended ORPort command we don't regognize (%u).",
+ log_notice(LD_NET,"Got Extended ORPort command we don't recognize (%u).",
command->cmd);
}
@@ -652,6 +656,77 @@ 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 7313ebd03d..416c358397 100644
--- a/src/feature/relay/ext_orport.h
+++ b/src/feature/relay/ext_orport.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file ext_orport.h
+ * @brief Header for ext_orport.c
+ **/
+
#ifndef EXT_ORPORT_H
#define EXT_ORPORT_H
@@ -26,26 +31,56 @@
#define EXT_OR_CONN_STATE_FLUSHING 5
#define EXT_OR_CONN_STATE_MAX_ 5
-int connection_ext_or_start_auth(or_connection_t *or_conn);
-
-ext_or_cmd_t *ext_or_cmd_new(uint16_t len);
+#ifdef HAVE_MODULE_RELAY
-#define ext_or_cmd_free(cmd) \
- FREE_AND_NULL(ext_or_cmd_t, ext_or_cmd_free_, (cmd))
+int connection_ext_or_start_auth(or_connection_t *or_conn);
-void ext_or_cmd_free_(ext_or_cmd_t *cmd);
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);
-or_connection_t *connection_or_get_by_ext_or_id(const char *id);
-
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);
+/* (No stub needed for these: they are only called within feature/relay.) */
int init_ext_or_cookie_authentication(int is_enabled);
-char *get_ext_or_auth_cookie_file_name(void);
void ext_orport_free_all(void);
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+static inline int
+connection_ext_or_start_auth(or_connection_t *conn)
+{
+ (void)conn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+static inline int
+connection_ext_or_finished_flushing(or_connection_t *conn)
+{
+ (void)conn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+static inline int
+connection_ext_or_process_inbuf(or_connection_t *conn)
+{
+ (void)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)
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
#ifdef EXT_ORPORT_PRIVATE
STATIC int connection_write_ext_or_command(connection_t *conn,
uint16_t command,
@@ -55,9 +90,11 @@ STATIC int handle_client_auth_nonce(const char *client_nonce,
size_t client_nonce_len,
char **client_hash_out,
char **reply_out, size_t *reply_len_out);
+
#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/feature_relay.md b/src/feature/relay/feature_relay.md
new file mode 100644
index 0000000000..a7f0c2153a
--- /dev/null
+++ b/src/feature/relay/feature_relay.md
@@ -0,0 +1,4 @@
+@dir /feature/relay
+@brief feature/relay: Relay-specific code
+
+(There is also a bunch of relay-specific code in other modules.)
diff --git a/src/feature/relay/include.am b/src/feature/relay/include.am
new file mode 100644
index 0000000000..84bb1ff35e
--- /dev/null
+++ b/src/feature/relay/include.am
@@ -0,0 +1,46 @@
+
+# Legacy shared relay code: migrate to the relay module over time
+LIBTOR_APP_A_SOURCES += \
+ src/feature/relay/onion_queue.c \
+ src/feature/relay/relay_find_addr.c \
+ src/feature/relay/router.c
+
+# The Relay module.
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+MODULE_RELAY_SOURCES = \
+ src/feature/relay/circuitbuild_relay.c \
+ src/feature/relay/dns.c \
+ src/feature/relay/ext_orport.c \
+ src/feature/relay/routermode.c \
+ src/feature/relay/relay_config.c \
+ src/feature/relay/relay_handshake.c \
+ src/feature/relay/relay_periodic.c \
+ src/feature/relay/relay_sys.c \
+ src/feature/relay/routerkeys.c \
+ src/feature/relay/selftest.c \
+ src/feature/relay/transport_config.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/relay/circuitbuild_relay.h \
+ src/feature/relay/dns.h \
+ src/feature/relay/dns_structs.h \
+ src/feature/relay/ext_orport.h \
+ src/feature/relay/onion_queue.h \
+ src/feature/relay/relay_config.h \
+ src/feature/relay/relay_handshake.h \
+ src/feature/relay/relay_periodic.h \
+ src/feature/relay/relay_sys.h \
+ src/feature/relay/relay_find_addr.h \
+ src/feature/relay/router.h \
+ src/feature/relay/routerkeys.h \
+ src/feature/relay/routermode.h \
+ src/feature/relay/selftest.h \
+ src/feature/relay/transport_config.h
+
+if BUILD_MODULE_RELAY
+LIBTOR_APP_A_SOURCES += $(MODULE_RELAY_SOURCES)
+else
+LIBTOR_APP_A_STUB_SOURCES += src/feature/relay/relay_stub.c
+endif
diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c
index c37745cf33..3cbaa65d28 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -49,10 +49,12 @@ typedef struct 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;
+
/** Array of queues of circuits waiting for CPU workers. An element is NULL
* if that queue is empty.*/
-static TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t)
- ol_list[MAX_ONION_HANDSHAKE_TYPE+1] =
+static onion_queue_head_t ol_list[MAX_ONION_HANDSHAKE_TYPE+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 */
diff --git a/src/feature/relay/onion_queue.h b/src/feature/relay/onion_queue.h
index cf478bc1a0..08379b2c00 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
new file mode 100644
index 0000000000..fac6a2f577
--- /dev/null
+++ b/src/feature/relay/relay_config.c
@@ -0,0 +1,1444 @@
+/* Copyright (c) 2001 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 relay_config.c
+ * @brief Code to interpret the user's configuration of Tor's relay module.
+ **/
+
+#include "orconfig.h"
+#define RELAY_CONFIG_PRIVATE
+#include "feature/relay/relay_config.h"
+
+#include "lib/encoding/confline.h"
+#include "lib/confmgt/confmgt.h"
+
+#include "lib/container/smartlist.h"
+#include "lib/geoip/geoip.h"
+#include "lib/meminfo/meminfo.h"
+#include "lib/osinfo/uname.h"
+#include "lib/process/setuid.h"
+
+/* Required for dirinfo_type_t in or_options_t */
+#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/or/connection_or.h"
+#include "core/or/port_cfg_st.h"
+
+#include "feature/hibernate/hibernate.h"
+#include "feature/nodelist/nickname.h"
+#include "feature/stats/geoip_stats.h"
+#include "feature/stats/predict_ports.h"
+#include "feature/stats/rephist.h"
+
+#include "feature/dirauth/authmode.h"
+
+#include "feature/dircache/consdiffmgr.h"
+#include "feature/relay/dns.h"
+#include "feature/relay/routermode.h"
+#include "feature/relay/selftest.h"
+
+/** Contents of most recently read DirPortFrontPage file. */
+static char *global_dirfrontpagecontents = NULL;
+
+/* Copied from config.c, we will refactor later in 29211. */
+#define REJECT(arg) \
+ STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
+#if defined(__GNUC__) && __GNUC__ <= 3
+#define COMPLAIN(args...) \
+ STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END
+#else
+#define COMPLAIN(args, ...) \
+ STMT_BEGIN log_warn(LD_CONFIG, args, ##__VA_ARGS__); STMT_END
+#endif /* defined(__GNUC__) && __GNUC__ <= 3 */
+
+/* Used in the various options_transition_affects* functions. */
+#define YES_IF_CHANGED_BOOL(opt) \
+ if (!CFG_EQ_BOOL(old_options, new_options, opt)) return 1;
+#define YES_IF_CHANGED_INT(opt) \
+ if (!CFG_EQ_INT(old_options, new_options, opt)) return 1;
+#define YES_IF_CHANGED_STRING(opt) \
+ if (!CFG_EQ_STRING(old_options, new_options, opt)) return 1;
+#define YES_IF_CHANGED_LINELIST(opt) \
+ if (!CFG_EQ_LINELIST(old_options, new_options, opt)) return 1;
+
+/** Return the contents of our frontpage string, or NULL if not configured. */
+MOCK_IMPL(const char*,
+relay_get_dirportfrontpage, (void))
+{
+ return global_dirfrontpagecontents;
+}
+
+/** Release all memory and resources held by global relay configuration
+ * structures.
+ */
+void
+relay_config_free_all(void)
+{
+ tor_free(global_dirfrontpagecontents);
+}
+
+/** Return the bandwidthrate that we are going to report to the authorities
+ * based on the config options. */
+uint32_t
+relay_get_effective_bwrate(const or_options_t *options)
+{
+ uint64_t bw = options->BandwidthRate;
+ if (bw > options->MaxAdvertisedBandwidth)
+ bw = options->MaxAdvertisedBandwidth;
+ if (options->RelayBandwidthRate > 0 && bw > options->RelayBandwidthRate)
+ bw = options->RelayBandwidthRate;
+ /* config_ensure_bandwidth_cap() makes sure that this cast can't overflow. */
+ return (uint32_t)bw;
+}
+
+/** Return the bandwidthburst that we are going to report to the authorities
+ * based on the config options. */
+uint32_t
+relay_get_effective_bwburst(const or_options_t *options)
+{
+ uint64_t bw = options->BandwidthBurst;
+ if (options->RelayBandwidthBurst > 0 && bw > options->RelayBandwidthBurst)
+ bw = options->RelayBandwidthBurst;
+ /* config_ensure_bandwidth_cap() makes sure that this cast can't overflow. */
+ return (uint32_t)bw;
+}
+
+/** Warn for every Extended ORPort port in <b>ports</b> that is on a
+ * publicly routable address. */
+void
+port_warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname)
+{
+ SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
+ if (port->type != CONN_TYPE_EXT_OR_LISTENER)
+ continue;
+ if (port->is_unix_addr)
+ continue;
+ /* XXX maybe warn even if address is RFC1918? */
+ if (!tor_addr_is_internal(&port->addr, 1)) {
+ log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. "
+ "This is not advised; this address is supposed to only be "
+ "exposed on localhost so that your pluggable transport "
+ "proxies can connect to it.",
+ fmt_addrport(&port->addr, port->port), portname);
+ }
+ } SMARTLIST_FOREACH_END(port);
+}
+
+/** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal
+ * consistency and warn as appropriate. On Unix-based OSes, set
+ * *<b>n_low_ports_out</b> to the number of sub-1024 ports we will be
+ * binding, and warn if we may be unable to re-bind after hibernation. */
+static int
+check_server_ports(const smartlist_t *ports,
+ const or_options_t *options,
+ int *n_low_ports_out)
+{
+ if (BUG(!ports))
+ return -1;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!n_low_ports_out))
+ return -1;
+
+ int n_orport_advertised = 0;
+ int n_orport_advertised_ipv4 = 0;
+ int n_orport_listeners = 0;
+ int n_dirport_advertised = 0;
+ int n_dirport_listeners = 0;
+ int n_low_port = 0;
+ int r = 0;
+
+ SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
+ if (port->type == CONN_TYPE_DIR_LISTENER) {
+ if (! port->server_cfg.no_advertise)
+ ++n_dirport_advertised;
+ if (! port->server_cfg.no_listen)
+ ++n_dirport_listeners;
+ } else if (port->type == CONN_TYPE_OR_LISTENER) {
+ if (! port->server_cfg.no_advertise) {
+ ++n_orport_advertised;
+ if (port_binds_ipv4(port))
+ ++n_orport_advertised_ipv4;
+ }
+ if (! port->server_cfg.no_listen)
+ ++n_orport_listeners;
+ } else {
+ continue;
+ }
+#ifndef _WIN32
+ if (!port->server_cfg.no_listen && port->port < 1024)
+ ++n_low_port;
+#endif
+ } SMARTLIST_FOREACH_END(port);
+
+ if (n_orport_advertised && !n_orport_listeners) {
+ log_warn(LD_CONFIG, "We are advertising an ORPort, but not actually "
+ "listening on one.");
+ r = -1;
+ }
+ if (n_orport_listeners && !n_orport_advertised) {
+ log_warn(LD_CONFIG, "We are listening on an ORPort, but not advertising "
+ "any ORPorts. This will keep us from building a %s "
+ "descriptor, and make us impossible to use.",
+ options->BridgeRelay ? "bridge" : "router");
+ r = -1;
+ }
+ if (n_dirport_advertised && !n_dirport_listeners) {
+ log_warn(LD_CONFIG, "We are advertising a DirPort, but not actually "
+ "listening on one.");
+ r = -1;
+ }
+ if (n_dirport_advertised > 1) {
+ log_warn(LD_CONFIG, "Can't advertise more than one DirPort.");
+ r = -1;
+ }
+ if (n_orport_advertised && !n_orport_advertised_ipv4 &&
+ !options->BridgeRelay) {
+ log_warn(LD_CONFIG, "Configured public relay to listen only on an IPv6 "
+ "address. Tor needs to listen on an IPv4 address too.");
+ r = -1;
+ }
+
+ if (n_low_port && options->AccountingMax &&
+ (!have_capability_support() || options->KeepBindCapabilities == 0)) {
+ const char *extra = "";
+ if (options->KeepBindCapabilities == 0 && have_capability_support())
+ extra = ", and you have disabled KeepBindCapabilities.";
+ log_warn(LD_CONFIG,
+ "You have set AccountingMax to use hibernation. You have also "
+ "chosen a low DirPort or OrPort%s."
+ "This combination can make Tor stop "
+ "working when it tries to re-attach the port after a period of "
+ "hibernation. Please choose a different port or turn off "
+ "hibernation unless you know this combination will work on your "
+ "platform.", extra);
+ }
+
+ if (n_low_ports_out)
+ *n_low_ports_out = n_low_port;
+
+ return r;
+}
+
+/** Parse all relay ports from <b>options</b>. On success, add parsed ports to
+ * <b>ports</b>, and return 0. On failure, set *<b>msg</b> to a newly
+ * allocated string describing the problem, and return -1.
+ **/
+int
+port_parse_ports_relay(or_options_t *options,
+ char **msg,
+ smartlist_t *ports_out,
+ int *have_low_ports_out)
+{
+ int retval = -1;
+ smartlist_t *ports = smartlist_new();
+ int n_low_ports = 0;
+
+ if (BUG(!options))
+ goto err;
+
+ if (BUG(!msg))
+ goto err;
+
+ if (BUG(!ports_out))
+ goto err;
+
+ if (BUG(!have_low_ports_out))
+ goto err;
+
+ if (options->ClientOnly) {
+ retval = 0;
+ goto err;
+ }
+
+ if (port_parse_config(ports,
+ options->ORPort_lines,
+ "OR", CONN_TYPE_OR_LISTENER,
+ "0.0.0.0", 0,
+ CL_PORT_SERVER_OPTIONS) < 0) {
+ *msg = tor_strdup("Invalid ORPort configuration");
+ goto err;
+ }
+ if (port_parse_config(ports,
+ options->ExtORPort_lines,
+ "ExtOR", CONN_TYPE_EXT_OR_LISTENER,
+ "127.0.0.1", 0,
+ CL_PORT_SERVER_OPTIONS|CL_PORT_WARN_NONLOCAL) < 0) {
+ *msg = tor_strdup("Invalid ExtORPort configuration");
+ goto err;
+ }
+ if (port_parse_config(ports,
+ options->DirPort_lines,
+ "Dir", CONN_TYPE_DIR_LISTENER,
+ "0.0.0.0", 0,
+ CL_PORT_SERVER_OPTIONS) < 0) {
+ *msg = tor_strdup("Invalid DirPort configuration");
+ goto err;
+ }
+
+ if (check_server_ports(ports, options, &n_low_ports) < 0) {
+ *msg = tor_strdup("Misconfigured server ports");
+ goto err;
+ }
+
+ smartlist_add_all(ports_out, ports);
+ smartlist_free(ports);
+ ports = NULL;
+ retval = 0;
+
+ err:
+ if (*have_low_ports_out < 0)
+ *have_low_ports_out = (n_low_ports > 0);
+ if (ports) {
+ SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p));
+ smartlist_free(ports);
+ }
+ return retval;
+}
+
+/** Update the relay *Port_set values in <b>options</b> from <b>ports</b>. */
+void
+port_update_port_set_relay(or_options_t *options,
+ const smartlist_t *ports)
+{
+ if (BUG(!options))
+ return;
+
+ if (BUG(!ports))
+ return;
+
+ if (options->ClientOnly)
+ return;
+
+ /* Update the relay *Port_set options. The !! here is to force a boolean
+ * out of an integer. */
+ options->ORPort_set =
+ !! port_count_real_listeners(ports, CONN_TYPE_OR_LISTENER, 0);
+ options->DirPort_set =
+ !! port_count_real_listeners(ports, CONN_TYPE_DIR_LISTENER, 0);
+ options->ExtORPort_set =
+ !! port_count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER, 0);
+}
+
+/**
+ * Legacy validation function, which checks that the current OS is usable in
+ * relay mode, if options is set to a relay mode.
+ *
+ * Warns about OSes with potential issues. Does not set *<b>msg</b>.
+ * Always returns 0.
+ */
+int
+options_validate_relay_os(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (!server_mode(options))
+ return 0;
+
+ const char *uname = get_uname();
+
+ if (!strcmpstart(uname, "Windows 95") ||
+ !strcmpstart(uname, "Windows 98") ||
+ !strcmpstart(uname, "Windows Me")) {
+ log_warn(LD_CONFIG, "Tor is running as a server, but you are "
+ "running %s; this probably won't work. See "
+ "https://www.torproject.org/docs/faq.html#BestOSForRelay "
+ "for details.", uname);
+ }
+
+ return 0;
+}
+
+/**
+ * Legacy validation/normalization function for the relay info options.
+ * Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_relay_info(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (options->Nickname == NULL) {
+ if (server_mode(options)) {
+ options->Nickname = tor_strdup(UNNAMED_ROUTER_NICKNAME);
+ }
+ } else {
+ if (!is_legal_nickname(options->Nickname)) {
+ tor_asprintf(msg,
+ "Nickname '%s', nicknames must be between 1 and 19 characters "
+ "inclusive, and must contain only the characters [a-zA-Z0-9].",
+ options->Nickname);
+ return -1;
+ }
+ }
+
+ if (server_mode(options) && !options->ContactInfo) {
+ log_warn(LD_CONFIG,
+ "Your ContactInfo config option is not set. Please strongly "
+ "consider setting it, so we can contact you if your relay is "
+ "misconfigured, end-of-life, or something else goes wrong. "
+ "It is also possible that your relay might get rejected from "
+ "the network due to a missing valid contact address.");
+ }
+
+ const char *ContactInfo = options->ContactInfo;
+ if (ContactInfo && !string_is_utf8(ContactInfo, strlen(ContactInfo)))
+ REJECT("ContactInfo config option must be UTF-8.");
+
+ return 0;
+}
+
+/** Parse an authority type from <b>options</b>-\>PublishServerDescriptor
+ * and write it to <b>options</b>-\>PublishServerDescriptor_. Treat "1"
+ * as "v3" unless BridgeRelay is 1, in which case treat it as "bridge".
+ * Treat "0" as "".
+ * Return 0 on success or -1 if not a recognized authority type (in which
+ * case the value of PublishServerDescriptor_ is undefined). */
+static int
+compute_publishserverdescriptor(or_options_t *options)
+{
+ smartlist_t *list = options->PublishServerDescriptor;
+ dirinfo_type_t *auth = &options->PublishServerDescriptor_;
+ *auth = NO_DIRINFO;
+ if (!list) /* empty list, answer is none */
+ return 0;
+ SMARTLIST_FOREACH_BEGIN(list, const char *, string) {
+ if (!strcasecmp(string, "v1"))
+ log_warn(LD_CONFIG, "PublishServerDescriptor v1 has no effect, because "
+ "there are no v1 directory authorities anymore.");
+ else if (!strcmp(string, "1"))
+ if (options->BridgeRelay)
+ *auth |= BRIDGE_DIRINFO;
+ else
+ *auth |= V3_DIRINFO;
+ else if (!strcasecmp(string, "v2"))
+ log_warn(LD_CONFIG, "PublishServerDescriptor v2 has no effect, because "
+ "there are no v2 directory authorities anymore.");
+ else if (!strcasecmp(string, "v3"))
+ *auth |= V3_DIRINFO;
+ else if (!strcasecmp(string, "bridge"))
+ *auth |= BRIDGE_DIRINFO;
+ else if (!strcasecmp(string, "hidserv"))
+ log_warn(LD_CONFIG,
+ "PublishServerDescriptor hidserv is invalid. See "
+ "PublishHidServDescriptors.");
+ else if (!strcasecmp(string, "") || !strcmp(string, "0"))
+ /* no authority */;
+ else
+ return -1;
+ } SMARTLIST_FOREACH_END(string);
+ return 0;
+}
+
+/**
+ * Validate the configured bridge distribution method from a BridgeDistribution
+ * config line.
+ *
+ * The input <b>bd</b>, is a string taken from the BridgeDistribution config
+ * line (if present). If the option wasn't set, return 0 immediately. The
+ * BridgeDistribution option is then validated. Currently valid, recognised
+ * options are:
+ *
+ * - "none"
+ * - "any"
+ * - "https"
+ * - "email"
+ * - "moat"
+ *
+ * If the option string is unrecognised, a warning will be logged and 0 is
+ * returned. If the option string contains an invalid character, -1 is
+ * returned.
+ **/
+STATIC int
+check_bridge_distribution_setting(const char *bd)
+{
+ if (bd == NULL)
+ return 0;
+
+ const char *RECOGNIZED[] = {
+ "none", "any", "https", "email", "moat"
+ };
+ unsigned i;
+ for (i = 0; i < ARRAY_LENGTH(RECOGNIZED); ++i) {
+ if (!strcasecmp(bd, RECOGNIZED[i]))
+ return 0;
+ }
+
+ const char *cp = bd;
+ // Method = (KeywordChar | "_") +
+ while (TOR_ISALNUM(*cp) || *cp == '-' || *cp == '_')
+ ++cp;
+
+ if (*cp == 0) {
+ log_warn(LD_CONFIG, "Unrecognized BridgeDistribution value %s. I'll "
+ "assume you know what you are doing...", escaped(bd));
+ return 0; // we reached the end of the string; all is well
+ } else {
+ return -1; // we found a bad character in the string.
+ }
+}
+
+/**
+ * Legacy validation/normalization function for the bridge relay options.
+ * Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_publish_server(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (compute_publishserverdescriptor(options) < 0) {
+ tor_asprintf(msg, "Unrecognized value in PublishServerDescriptor");
+ return -1;
+ }
+
+ if ((options->BridgeRelay
+ || options->PublishServerDescriptor_ & BRIDGE_DIRINFO)
+ && (options->PublishServerDescriptor_ & V3_DIRINFO)) {
+ REJECT("Bridges are not supposed to publish router descriptors to the "
+ "directory authorities. Please correct your "
+ "PublishServerDescriptor line.");
+ }
+
+ if (options->BridgeDistribution) {
+ if (!options->BridgeRelay) {
+ REJECT("You set BridgeDistribution, but you didn't set BridgeRelay!");
+ }
+ if (check_bridge_distribution_setting(options->BridgeDistribution) < 0) {
+ REJECT("Invalid BridgeDistribution value.");
+ }
+ }
+
+ if (options->PublishServerDescriptor)
+ SMARTLIST_FOREACH(options->PublishServerDescriptor, const char *, pubdes, {
+ if (!strcmp(pubdes, "1") || !strcmp(pubdes, "0"))
+ if (smartlist_len(options->PublishServerDescriptor) > 1) {
+ COMPLAIN("You have passed a list of multiple arguments to the "
+ "PublishServerDescriptor option that includes 0 or 1. "
+ "0 or 1 should only be used as the sole argument. "
+ "This configuration will be rejected in a future release.");
+ break;
+ }
+ });
+
+ return 0;
+}
+
+/**
+ * Legacy validation/normalization function for the relay padding options.
+ * Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_relay_padding(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (!server_mode(options))
+ return 0;
+
+ if (options->ConnectionPadding != -1) {
+ REJECT("Relays must use 'auto' for the ConnectionPadding setting.");
+ }
+
+ if (options->ReducedConnectionPadding != 0) {
+ REJECT("Relays cannot set ReducedConnectionPadding. ");
+ }
+
+ if (options->CircuitPadding == 0) {
+ REJECT("Relays cannot set CircuitPadding to 0. ");
+ }
+
+ if (options->ReducedCircuitPadding == 1) {
+ REJECT("Relays cannot set ReducedCircuitPadding. ");
+ }
+
+ return 0;
+}
+
+/**
+ * Legacy validation/normalization function for the relay bandwidth options.
+ * Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_relay_bandwidth(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ /* 31851: the tests expect us to validate bandwidths, even when we are not
+ * in relay mode. */
+ if (config_ensure_bandwidth_cap(&options->MaxAdvertisedBandwidth,
+ "MaxAdvertisedBandwidth", msg) < 0)
+ return -1;
+ if (config_ensure_bandwidth_cap(&options->RelayBandwidthRate,
+ "RelayBandwidthRate", msg) < 0)
+ return -1;
+ if (config_ensure_bandwidth_cap(&options->RelayBandwidthBurst,
+ "RelayBandwidthBurst", msg) < 0)
+ return -1;
+ if (config_ensure_bandwidth_cap(&options->PerConnBWRate,
+ "PerConnBWRate", msg) < 0)
+ return -1;
+ if (config_ensure_bandwidth_cap(&options->PerConnBWBurst,
+ "PerConnBWBurst", msg) < 0)
+ return -1;
+
+ if (options->RelayBandwidthRate && !options->RelayBandwidthBurst)
+ options->RelayBandwidthBurst = options->RelayBandwidthRate;
+ if (options->RelayBandwidthBurst && !options->RelayBandwidthRate)
+ options->RelayBandwidthRate = options->RelayBandwidthBurst;
+
+ if (server_mode(options)) {
+ const unsigned required_min_bw =
+ public_server_mode(options) ?
+ RELAY_REQUIRED_MIN_BANDWIDTH : BRIDGE_REQUIRED_MIN_BANDWIDTH;
+ const char * const optbridge =
+ public_server_mode(options) ? "" : "bridge ";
+ if (options->BandwidthRate < required_min_bw) {
+ tor_asprintf(msg,
+ "BandwidthRate is set to %d bytes/second. "
+ "For %sservers, it must be at least %u.",
+ (int)options->BandwidthRate, optbridge,
+ required_min_bw);
+ return -1;
+ } else if (options->MaxAdvertisedBandwidth <
+ required_min_bw/2) {
+ tor_asprintf(msg,
+ "MaxAdvertisedBandwidth is set to %d bytes/second. "
+ "For %sservers, it must be at least %u.",
+ (int)options->MaxAdvertisedBandwidth, optbridge,
+ required_min_bw/2);
+ return -1;
+ }
+ if (options->RelayBandwidthRate &&
+ options->RelayBandwidthRate < required_min_bw) {
+ tor_asprintf(msg,
+ "RelayBandwidthRate is set to %d bytes/second. "
+ "For %sservers, it must be at least %u.",
+ (int)options->RelayBandwidthRate, optbridge,
+ required_min_bw);
+ return -1;
+ }
+ }
+
+ /* 31851: the tests expect us to validate bandwidths, even when we are not
+ * in relay mode. */
+ if (options->RelayBandwidthRate > options->RelayBandwidthBurst)
+ REJECT("RelayBandwidthBurst must be at least equal "
+ "to RelayBandwidthRate.");
+
+ /* if they set relaybandwidth* really high but left bandwidth*
+ * at the default, raise the defaults. */
+ if (options->RelayBandwidthRate > options->BandwidthRate)
+ options->BandwidthRate = options->RelayBandwidthRate;
+ if (options->RelayBandwidthBurst > options->BandwidthBurst)
+ options->BandwidthBurst = options->RelayBandwidthBurst;
+
+ return 0;
+}
+
+/**
+ * Legacy validation/normalization function for the relay bandwidth accounting
+ * options. Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_relay_accounting(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ /* 31851: the tests expect us to validate accounting, even when we are not
+ * in relay mode. */
+ if (accounting_parse_options(options, 1)<0)
+ REJECT("Failed to parse accounting options. See logs for details.");
+
+ if (options->AccountingMax) {
+ if (options->RendConfigLines && server_mode(options)) {
+ log_warn(LD_CONFIG, "Using accounting with a hidden service and an "
+ "ORPort is risky: your hidden service(s) and your public "
+ "address will all turn off at the same time, which may alert "
+ "observers that they are being run by the same party.");
+ } else if (config_count_key(options->RendConfigLines,
+ "HiddenServiceDir") > 1) {
+ log_warn(LD_CONFIG, "Using accounting with multiple hidden services is "
+ "risky: they will all turn off at the same time, which may "
+ "alert observers that they are being run by the same party.");
+ }
+ }
+
+ options->AccountingRule = ACCT_MAX;
+ if (options->AccountingRule_option) {
+ if (!strcmp(options->AccountingRule_option, "sum"))
+ options->AccountingRule = ACCT_SUM;
+ else if (!strcmp(options->AccountingRule_option, "max"))
+ options->AccountingRule = ACCT_MAX;
+ else if (!strcmp(options->AccountingRule_option, "in"))
+ options->AccountingRule = ACCT_IN;
+ else if (!strcmp(options->AccountingRule_option, "out"))
+ options->AccountingRule = ACCT_OUT;
+ else
+ REJECT("AccountingRule must be 'sum', 'max', 'in', or 'out'");
+ }
+
+ return 0;
+}
+
+/** Verify whether lst is a list of strings containing valid-looking
+ * comma-separated nicknames, or NULL. Will normalise <b>lst</b> to prefix '$'
+ * to any nickname or fingerprint that needs it. Also splits comma-separated
+ * list elements into multiple elements. Return 0 on success.
+ * Warn and return -1 on failure.
+ */
+static int
+normalize_nickname_list(config_line_t **normalized_out,
+ const config_line_t *lst, const char *name,
+ char **msg)
+{
+ if (!lst)
+ return 0;
+
+ config_line_t *new_nicknames = NULL;
+ config_line_t **new_nicknames_next = &new_nicknames;
+
+ const config_line_t *cl;
+ for (cl = lst; cl; cl = cl->next) {
+ const char *line = cl->value;
+ if (!line)
+ continue;
+
+ int valid_line = 1;
+ smartlist_t *sl = smartlist_new();
+ smartlist_split_string(sl, line, ",",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK|SPLIT_STRIP_SPACE, 0);
+ SMARTLIST_FOREACH_BEGIN(sl, char *, s)
+ {
+ char *normalized = NULL;
+ if (!is_legal_nickname_or_hexdigest(s)) {
+ // check if first char is dollar
+ if (s[0] != '$') {
+ // Try again but with a dollar symbol prepended
+ char *prepended;
+ tor_asprintf(&prepended, "$%s", s);
+
+ if (is_legal_nickname_or_hexdigest(prepended)) {
+ // The nickname is valid when it's prepended, set it as the
+ // normalized version
+ normalized = prepended;
+ } else {
+ // Still not valid, free and fallback to error message
+ tor_free(prepended);
+ }
+ }
+
+ if (!normalized) {
+ tor_asprintf(msg, "Invalid nickname '%s' in %s line", s, name);
+ valid_line = 0;
+ break;
+ }
+ } else {
+ normalized = tor_strdup(s);
+ }
+
+ config_line_t *next = tor_malloc_zero(sizeof(*next));
+ next->key = tor_strdup(cl->key);
+ next->value = normalized;
+ next->next = NULL;
+
+ *new_nicknames_next = next;
+ new_nicknames_next = &next->next;
+ } SMARTLIST_FOREACH_END(s);
+
+ SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
+ smartlist_free(sl);
+
+ if (!valid_line) {
+ config_free_lines(new_nicknames);
+ return -1;
+ }
+ }
+
+ *normalized_out = new_nicknames;
+
+ return 0;
+}
+
+#define ONE_MEGABYTE (UINT64_C(1) << 20)
+
+/* If we have less than 300 MB suggest disabling dircache */
+#define DIRCACHE_MIN_MEM_MB 300
+#define DIRCACHE_MIN_MEM_BYTES (DIRCACHE_MIN_MEM_MB*ONE_MEGABYTE)
+#define STRINGIFY(val) #val
+
+/** Create a warning message for emitting if we are a dircache but may not have
+ * enough system memory, or if we are not a dircache but probably should be.
+ * Return -1 when a message is returned in *msg*, else return 0. */
+STATIC int
+have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem,
+ char **msg)
+{
+ *msg = NULL;
+ /* XXX We should possibly be looking at MaxMemInQueues here
+ * unconditionally. Or we should believe total_mem unconditionally. */
+ if (total_mem == 0) {
+ if (get_total_system_memory(&total_mem) < 0) {
+ total_mem = options->MaxMemInQueues >= SIZE_MAX ?
+ SIZE_MAX : (size_t)options->MaxMemInQueues;
+ }
+ }
+ if (options->DirCache) {
+ if (total_mem < DIRCACHE_MIN_MEM_BYTES) {
+ if (options->BridgeRelay) {
+ tor_asprintf(msg, "Running a Bridge with less than %d MB of memory "
+ "is not recommended.", DIRCACHE_MIN_MEM_MB);
+ } else {
+ tor_asprintf(msg, "Being a directory cache (default) with less than "
+ "%d MB of memory is not recommended and may consume "
+ "most of the available resources. Consider disabling "
+ "this functionality by setting the DirCache option "
+ "to 0.", DIRCACHE_MIN_MEM_MB);
+ }
+ }
+ } else {
+ if (total_mem >= DIRCACHE_MIN_MEM_BYTES) {
+ *msg = tor_strdup("DirCache is disabled and we are configured as a "
+ "relay. We will not become a Guard.");
+ }
+ }
+ return *msg == NULL ? 0 : -1;
+}
+#undef STRINGIFY
+
+/**
+ * Legacy validation/normalization function for the relay mode options.
+ * Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_relay_mode(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (server_mode(options) && options->RendConfigLines)
+ log_warn(LD_CONFIG,
+ "Tor is currently configured as a relay and a hidden service. "
+ "That's not very secure: you should probably run your hidden service "
+ "in a separate Tor process, at least -- see "
+ "https://trac.torproject.org/8742");
+
+ if (options->BridgeRelay && options->DirPort_set) {
+ log_warn(LD_CONFIG, "Can't set a DirPort on a bridge relay; disabling "
+ "DirPort");
+ config_free_lines(options->DirPort_lines);
+ options->DirPort_lines = NULL;
+ options->DirPort_set = 0;
+ }
+
+ if (options->DirPort_set && !options->DirCache) {
+ REJECT("DirPort configured but DirCache disabled. DirPort requires "
+ "DirCache.");
+ }
+
+ if (options->BridgeRelay && !options->DirCache) {
+ REJECT("We're a bridge but DirCache is disabled. BridgeRelay requires "
+ "DirCache.");
+ }
+
+ if (options->BridgeRelay == 1 && ! options->ORPort_set)
+ REJECT("BridgeRelay is 1, ORPort is not set. This is an invalid "
+ "combination.");
+
+ if (server_mode(options)) {
+ char *dircache_msg = NULL;
+ if (have_enough_mem_for_dircache(options, 0, &dircache_msg)) {
+ log_warn(LD_CONFIG, "%s", dircache_msg);
+ tor_free(dircache_msg);
+ }
+ }
+
+ if (options->MyFamily_lines && options->BridgeRelay) {
+ log_warn(LD_CONFIG, "Listing a family for a bridge relay is not "
+ "supported: it can reveal bridge fingerprints to censors. "
+ "You should also make sure you aren't listing this bridge's "
+ "fingerprint in any other MyFamily.");
+ }
+ if (options->MyFamily_lines && !options->ContactInfo) {
+ log_warn(LD_CONFIG, "MyFamily is set but ContactInfo is not configured. "
+ "ContactInfo should always be set when MyFamily option is too.");
+ }
+ if (normalize_nickname_list(&options->MyFamily,
+ options->MyFamily_lines, "MyFamily", msg))
+ return -1;
+
+ if (options->ConstrainedSockets) {
+ if (options->DirPort_set) {
+ /* Providing cached directory entries while system TCP buffers are scarce
+ * will exacerbate the socket errors. Suggest that this be disabled. */
+ COMPLAIN("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.");
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Legacy validation/normalization function for the relay testing options
+ * in options. Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_relay_testing(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ if (options->SigningKeyLifetime < options->TestingSigningKeySlop*2)
+ REJECT("SigningKeyLifetime is too short.");
+ if (options->TestingLinkCertLifetime < options->TestingAuthKeySlop*2)
+ REJECT("LinkCertLifetime is too short.");
+ if (options->TestingAuthKeyLifetime < options->TestingLinkKeySlop*2)
+ REJECT("TestingAuthKeyLifetime is too short.");
+
+ return 0;
+}
+
+/** Return 1 if any change from <b>old_options</b> to <b>new_options</b>
+ * will require us to rotate the CPU and DNS workers; else return 0. */
+static int
+options_transition_affects_workers(const or_options_t *old_options,
+ const or_options_t *new_options)
+{
+ YES_IF_CHANGED_STRING(DataDirectory);
+ YES_IF_CHANGED_INT(NumCPUs);
+ YES_IF_CHANGED_LINELIST(ORPort_lines);
+ YES_IF_CHANGED_BOOL(ServerDNSSearchDomains);
+ YES_IF_CHANGED_BOOL(SafeLogging_);
+ YES_IF_CHANGED_BOOL(ClientOnly);
+ YES_IF_CHANGED_BOOL(LogMessageDomains);
+ YES_IF_CHANGED_LINELIST(Logs);
+
+ if (server_mode(old_options) != server_mode(new_options) ||
+ public_server_mode(old_options) != public_server_mode(new_options) ||
+ dir_server_mode(old_options) != dir_server_mode(new_options))
+ return 1;
+
+ /* Nothing that changed matters. */
+ return 0;
+}
+
+/** Return 1 if any change from <b>old_options</b> to <b>new_options</b>
+ * will require us to generate a new descriptor; else return 0. */
+static int
+options_transition_affects_descriptor(const or_options_t *old_options,
+ const or_options_t *new_options)
+{
+ /* XXX We can be smarter here. If your DirPort isn't being
+ * published and you just turned it off, no need to republish. Etc. */
+
+ YES_IF_CHANGED_STRING(DataDirectory);
+ YES_IF_CHANGED_STRING(Nickname);
+ YES_IF_CHANGED_STRING(Address);
+ YES_IF_CHANGED_LINELIST(ExitPolicy);
+ YES_IF_CHANGED_BOOL(ExitRelay);
+ YES_IF_CHANGED_BOOL(ExitPolicyRejectPrivate);
+ YES_IF_CHANGED_BOOL(ExitPolicyRejectLocalInterfaces);
+ YES_IF_CHANGED_BOOL(IPv6Exit);
+ YES_IF_CHANGED_LINELIST(ORPort_lines);
+ YES_IF_CHANGED_LINELIST(DirPort_lines);
+ YES_IF_CHANGED_LINELIST(DirPort_lines);
+ YES_IF_CHANGED_BOOL(ClientOnly);
+ YES_IF_CHANGED_BOOL(DisableNetwork);
+ YES_IF_CHANGED_BOOL(PublishServerDescriptor_);
+ YES_IF_CHANGED_STRING(ContactInfo);
+ YES_IF_CHANGED_STRING(BridgeDistribution);
+ YES_IF_CHANGED_LINELIST(MyFamily);
+ YES_IF_CHANGED_STRING(AccountingStart);
+ YES_IF_CHANGED_INT(AccountingMax);
+ YES_IF_CHANGED_INT(AccountingRule);
+ YES_IF_CHANGED_BOOL(DirCache);
+ YES_IF_CHANGED_BOOL(AssumeReachable);
+
+ if (relay_get_effective_bwrate(old_options) !=
+ relay_get_effective_bwrate(new_options) ||
+ relay_get_effective_bwburst(old_options) !=
+ relay_get_effective_bwburst(new_options) ||
+ public_server_mode(old_options) != public_server_mode(new_options))
+ return 1;
+
+ return 0;
+}
+
+/** Fetch the active option list, and take relay actions based on it. All of
+ * the things we do should survive being done repeatedly. If present,
+ * <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_relay(const or_options_t *old_options)
+{
+ const or_options_t *options = get_options();
+
+ const int transition_affects_workers =
+ old_options && options_transition_affects_workers(old_options, options);
+
+ /* We want to reinit keys as needed before we do much of anything else:
+ keys are important, and other things can depend on them. */
+ if (transition_affects_workers ||
+ (authdir_mode_v3(options) && (!old_options ||
+ !authdir_mode_v3(old_options)))) {
+ if (init_keys() < 0) {
+ log_warn(LD_BUG,"Error initializing keys; exiting");
+ return -1;
+ }
+ }
+
+ if (server_mode(options)) {
+ static int cdm_initialized = 0;
+ if (cdm_initialized == 0) {
+ cdm_initialized = 1;
+ consdiffmgr_configure(NULL);
+ consdiffmgr_validate();
+ }
+ }
+
+ /* Check for transitions that need action. */
+ if (old_options) {
+ if (transition_affects_workers) {
+ log_info(LD_GENERAL,
+ "Worker-related options changed. Rotating workers.");
+ const int server_mode_turned_on =
+ server_mode(options) && !server_mode(old_options);
+ const int dir_server_mode_turned_on =
+ dir_server_mode(options) && !dir_server_mode(old_options);
+
+ if (server_mode_turned_on || dir_server_mode_turned_on) {
+ cpu_init();
+ }
+
+ if (server_mode_turned_on) {
+ ip_address_changed(0);
+ if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL)))
+ inform_testing_reachability();
+ }
+ cpuworkers_rotate_keyinfo();
+ }
+ }
+
+ return 0;
+}
+
+/** Fetch the active option list, and take relay accounting actions based on
+ * it. All of the things we do should survive being done repeatedly. If
+ * present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_relay_accounting(const or_options_t *old_options)
+{
+ (void)old_options;
+
+ const or_options_t *options = get_options();
+
+ /* Set up accounting */
+ if (accounting_parse_options(options, 0)<0) {
+ // LCOV_EXCL_START
+ log_warn(LD_BUG,"Error in previously validated accounting options");
+ return -1;
+ // LCOV_EXCL_STOP
+ }
+ if (accounting_is_enabled(options))
+ configure_accounting(time(NULL));
+
+ return 0;
+}
+
+/** Fetch the active option list, and take relay bandwidth actions based on
+ * it. All of the things we do should survive being done repeatedly. If
+ * present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_relay_bandwidth(const or_options_t *old_options)
+{
+ const or_options_t *options = get_options();
+
+ /* Check for transitions that need action. */
+ if (old_options) {
+ if (options->PerConnBWRate != old_options->PerConnBWRate ||
+ options->PerConnBWBurst != old_options->PerConnBWBurst)
+ connection_or_update_token_buckets(get_connection_array(), options);
+
+ if (options->RelayBandwidthRate != old_options->RelayBandwidthRate ||
+ options->RelayBandwidthBurst != old_options->RelayBandwidthBurst)
+ connection_bucket_adjust(options);
+ }
+
+ return 0;
+}
+
+/** Fetch the active option list, and take bridge statistics actions based on
+ * it. All of the things we do should survive being done repeatedly. If
+ * present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_bridge_stats(const or_options_t *old_options)
+{
+ const or_options_t *options = get_options();
+
+/* How long should we delay counting bridge stats after becoming a bridge?
+ * We use this so we don't count clients who used our bridge thinking it is
+ * a relay. If you change this, don't forget to change the log message
+ * below. It's 4 hours (the time it takes to stop being used by clients)
+ * plus some extra time for clock skew. */
+#define RELAY_BRIDGE_STATS_DELAY (6 * 60 * 60)
+
+ /* Check for transitions that need action. */
+ if (old_options) {
+ if (! bool_eq(options->BridgeRelay, old_options->BridgeRelay)) {
+ int was_relay = 0;
+ if (options->BridgeRelay) {
+ time_t int_start = time(NULL);
+ if (config_lines_eq(old_options->ORPort_lines,options->ORPort_lines)) {
+ int_start += RELAY_BRIDGE_STATS_DELAY;
+ was_relay = 1;
+ }
+ geoip_bridge_stats_init(int_start);
+ log_info(LD_CONFIG, "We are acting as a bridge now. Starting new "
+ "GeoIP stats interval%s.", was_relay ? " in 6 "
+ "hours from now" : "");
+ } else {
+ geoip_bridge_stats_term();
+ log_info(LD_GENERAL, "We are no longer acting as a bridge. "
+ "Forgetting GeoIP stats.");
+ }
+ }
+ }
+
+ return 0;
+}
+
+/** Fetch the active option list, and take relay statistics actions based on
+ * it. All of the things we do should survive being done repeatedly. If
+ * present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Sets <b>*print_notice_out</b> if we enabled stats, and need to print
+ * a stats log using options_act_relay_stats_msg().
+ *
+ * If loading the GeoIP file failed, sets DirReqStatistics and
+ * EntryStatistics to 0. This breaks the normalization/act ordering
+ * introduced in 29211.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_relay_stats(const or_options_t *old_options,
+ bool *print_notice_out)
+{
+ if (BUG(!print_notice_out))
+ return -1;
+
+ or_options_t *options = get_options_mutable();
+
+ if (options->CellStatistics || options->DirReqStatistics ||
+ options->EntryStatistics || options->ExitPortStatistics ||
+ options->ConnDirectionStatistics ||
+ options->HiddenServiceStatistics) {
+ time_t now = time(NULL);
+ int print_notice = 0;
+
+ if ((!old_options || !old_options->CellStatistics) &&
+ options->CellStatistics) {
+ rep_hist_buffer_stats_init(now);
+ print_notice = 1;
+ }
+ if ((!old_options || !old_options->DirReqStatistics) &&
+ options->DirReqStatistics) {
+ if (geoip_is_loaded(AF_INET)) {
+ geoip_dirreq_stats_init(now);
+ print_notice = 1;
+ } else {
+ /* disable statistics collection since we have no geoip file */
+ /* 29211: refactor to avoid the normalisation/act inversion */
+ options->DirReqStatistics = 0;
+ if (options->ORPort_set)
+ log_notice(LD_CONFIG, "Configured to measure directory request "
+ "statistics, but no GeoIP database found. "
+ "Please specify a GeoIP database using the "
+ "GeoIPFile option.");
+ }
+ }
+ if ((!old_options || !old_options->EntryStatistics) &&
+ options->EntryStatistics && !should_record_bridge_info(options)) {
+ /* If we get here, we've started recording bridge info when we didn't
+ * do so before. Note that "should_record_bridge_info()" will
+ * always be false at this point, because of the earlier block
+ * that cleared EntryStatistics when public_server_mode() was false.
+ * We're leaving it in as defensive programming. */
+ if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) {
+ geoip_entry_stats_init(now);
+ print_notice = 1;
+ } else {
+ options->EntryStatistics = 0;
+ log_notice(LD_CONFIG, "Configured to measure entry node "
+ "statistics, but no GeoIP database found. "
+ "Please specify a GeoIP database using the "
+ "GeoIPFile option.");
+ }
+ }
+ if ((!old_options || !old_options->ExitPortStatistics) &&
+ options->ExitPortStatistics) {
+ rep_hist_exit_stats_init(now);
+ print_notice = 1;
+ }
+ if ((!old_options || !old_options->ConnDirectionStatistics) &&
+ options->ConnDirectionStatistics) {
+ rep_hist_conn_stats_init(now);
+ }
+ if ((!old_options || !old_options->HiddenServiceStatistics) &&
+ options->HiddenServiceStatistics) {
+ log_info(LD_CONFIG, "Configured to measure hidden service statistics.");
+ rep_hist_hs_stats_init(now);
+ }
+ if (print_notice)
+ *print_notice_out = 1;
+ }
+
+ /* If we used to have statistics enabled but we just disabled them,
+ stop gathering them. */
+ if (old_options && old_options->CellStatistics &&
+ !options->CellStatistics)
+ rep_hist_buffer_stats_term();
+ if (old_options && old_options->DirReqStatistics &&
+ !options->DirReqStatistics)
+ geoip_dirreq_stats_term();
+ if (old_options && old_options->EntryStatistics &&
+ !options->EntryStatistics)
+ geoip_entry_stats_term();
+ if (old_options && old_options->HiddenServiceStatistics &&
+ !options->HiddenServiceStatistics)
+ rep_hist_hs_stats_term();
+ if (old_options && old_options->ExitPortStatistics &&
+ !options->ExitPortStatistics)
+ rep_hist_exit_stats_term();
+ if (old_options && old_options->ConnDirectionStatistics &&
+ !options->ConnDirectionStatistics)
+ rep_hist_conn_stats_term();
+
+ return 0;
+}
+
+/** Print a notice about relay/dirauth stats being enabled. */
+void
+options_act_relay_stats_msg(void)
+{
+ log_notice(LD_CONFIG, "Configured to measure statistics. Look for "
+ "the *-stats files that will first be written to the "
+ "data directory in 24 hours from now.");
+}
+
+/** Fetch the active option list, and take relay descriptor actions based on
+ * it. All of the things we do should survive being done repeatedly. If
+ * present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_relay_desc(const or_options_t *old_options)
+{
+ const or_options_t *options = get_options();
+
+ /* Since our options changed, we might need to regenerate and upload our
+ * server descriptor.
+ */
+ if (!old_options ||
+ options_transition_affects_descriptor(old_options, options))
+ mark_my_descriptor_dirty("config change");
+
+ return 0;
+}
+
+/** Fetch the active option list, and take relay DoS actions based on
+ * it. All of the things we do should survive being done repeatedly. If
+ * present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_relay_dos(const or_options_t *old_options)
+{
+ const or_options_t *options = get_options();
+
+ /* DoS mitigation subsystem only applies to public relay. */
+ if (public_server_mode(options)) {
+ /* If we are configured as a relay, initialize the subsystem. Even on HUP,
+ * this is safe to call as it will load data from the current options
+ * or/and the consensus. */
+ dos_init();
+ } else if (old_options && public_server_mode(old_options)) {
+ /* Going from relay to non relay, clean it up. */
+ dos_free_all();
+ }
+
+ return 0;
+}
+
+/** Fetch the active option list, and take dirport actions based on
+ * it. All of the things we do should survive being done repeatedly. If
+ * present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_relay_dir(const or_options_t *old_options)
+{
+ (void)old_options;
+
+ const or_options_t *options = get_options();
+
+ if (!public_server_mode(options))
+ return 0;
+
+ /* Load the webpage we're going to serve every time someone asks for '/' on
+ our DirPort. */
+ tor_free(global_dirfrontpagecontents);
+ if (options->DirPortFrontPage) {
+ global_dirfrontpagecontents =
+ read_file_to_str(options->DirPortFrontPage, 0, NULL);
+ if (!global_dirfrontpagecontents) {
+ log_warn(LD_CONFIG,
+ "DirPortFrontPage file '%s' not found. Continuing anyway.",
+ options->DirPortFrontPage);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/feature/relay/relay_config.h b/src/feature/relay/relay_config.h
new file mode 100644
index 0000000000..c70c322d88
--- /dev/null
+++ b/src/feature/relay/relay_config.h
@@ -0,0 +1,196 @@
+/* Copyright (c) 2001 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 relay_config.h
+ * @brief Header for feature/relay/relay_config.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_RELAY_CONFIG_H
+#define TOR_FEATURE_RELAY_RELAY_CONFIG_H
+
+struct or_options_t;
+
+#ifdef HAVE_MODULE_RELAY
+
+#include "lib/cc/torint.h"
+#include "lib/testsupport/testsupport.h"
+
+struct smartlist_t;
+
+int options_validate_relay_mode(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+MOCK_DECL(const char*, relay_get_dirportfrontpage, (void));
+void relay_config_free_all(void);
+
+uint32_t relay_get_effective_bwrate(const struct or_options_t *options);
+uint32_t relay_get_effective_bwburst(const struct or_options_t *options);
+
+void port_warn_nonlocal_ext_orports(const struct smartlist_t *ports,
+ const char *portname);
+
+int port_parse_ports_relay(struct or_options_t *options,
+ char **msg,
+ struct smartlist_t *ports_out,
+ int *have_low_ports_out);
+void port_update_port_set_relay(struct or_options_t *options,
+ const struct smartlist_t *ports);
+
+int options_validate_relay_os(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_validate_relay_info(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_validate_publish_server(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_validate_relay_padding(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_validate_relay_bandwidth(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_validate_relay_accounting(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_validate_relay_testing(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+int options_act_relay(const struct or_options_t *old_options);
+int options_act_relay_accounting(const struct or_options_t *old_options);
+int options_act_relay_bandwidth(const struct or_options_t *old_options);
+int options_act_bridge_stats(const struct or_options_t *old_options);
+
+int options_act_relay_stats(const struct or_options_t *old_options,
+ bool *print_notice_out);
+void options_act_relay_stats_msg(void);
+
+int options_act_relay_desc(const struct or_options_t *old_options);
+int options_act_relay_dos(const struct or_options_t *old_options);
+int options_act_relay_dir(const struct or_options_t *old_options);
+
+#ifdef RELAY_CONFIG_PRIVATE
+
+STATIC int check_bridge_distribution_setting(const char *bd);
+STATIC int have_enough_mem_for_dircache(const struct or_options_t *options,
+ size_t total_mem, char **msg);
+
+#endif /* defined(RELAY_CONFIG_PRIVATE) */
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#include "lib/cc/compat_compiler.h"
+
+/** When tor is compiled with the relay module disabled, it can't be
+ * configured as a relay or bridge.
+ *
+ * Always sets ClientOnly to 1.
+ *
+ * Returns -1 and sets msg to a newly allocated string, if ORPort, DirPort,
+ * DirCache, or BridgeRelay are set in options. Otherwise returns 0. */
+static inline int
+options_validate_relay_mode(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ /* Only check the primary options for now, #29211 will disable more
+ * options. These ORPort and DirPort checks are too strict, and will
+ * reject valid configs that disable ports, like "ORPort 0". */
+ if (options->DirCache ||
+ options->BridgeRelay ||
+ options->ORPort_lines ||
+ options->DirPort_lines) {
+ /* REJECT() this configuration */
+ *msg = tor_strdup("This tor was built with relay mode disabled. "
+ "It can not be configured with an ORPort, a DirPort, "
+ "DirCache 1, or BridgeRelay 1.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int
+port_parse_ports_relay(or_options_t *options,
+ char **msg,
+ smartlist_t *ports_out,
+ int *have_low_ports_out)
+{
+ (void)options;
+ (void)msg;
+ (void)ports_out;
+ if (*have_low_ports_out < 0)
+ *have_low_ports_out = 0;
+ return 0;
+}
+
+#define relay_get_dirportfrontpage() \
+ (NULL)
+#define relay_config_free_all() \
+ STMT_BEGIN STMT_END
+
+#define relay_get_effective_bwrate(options) \
+ (((void)(options)),0)
+#define relay_get_effective_bwburst(options) \
+ (((void)(options)),0)
+
+#define port_warn_nonlocal_ext_orports(ports, portname) \
+ (((void)(ports)),((void)(portname)))
+
+#define port_update_port_set_relay(options, ports) \
+ (((void)(options)),((void)(ports)))
+
+#define options_validate_relay_os(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+#define options_validate_relay_info(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+#define options_validate_publish_server(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+#define options_validate_relay_padding(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+#define options_validate_relay_bandwidth(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+#define options_validate_relay_accounting(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+#define options_validate_relay_testing(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+
+#define options_act_relay(old_options) \
+ (((void)(old_options)),0)
+#define options_act_relay_accounting(old_options) \
+ (((void)(old_options)),0)
+#define options_act_relay_bandwidth(old_options) \
+ (((void)(old_options)),0)
+#define options_act_bridge_stats(old_options) \
+ (((void)(old_options)),0)
+
+#define options_act_relay_stats(old_options, print_notice_out) \
+ (((void)(old_options)),((void)(print_notice_out)),0)
+#define options_act_relay_stats_msg() \
+ STMT_BEGIN STMT_END
+
+#define options_act_relay_desc(old_options) \
+ (((void)(old_options)),0)
+#define options_act_relay_dos(old_options) \
+ (((void)(old_options)),0)
+#define options_act_relay_dir(old_options) \
+ (((void)(old_options)),0)
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
+#endif /* !defined(TOR_FEATURE_RELAY_RELAY_CONFIG_H) */
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
new file mode 100644
index 0000000000..86cd799d42
--- /dev/null
+++ b/src/feature/relay/relay_find_addr.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2001-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay_find_addr.c
+ * \brief Implement mechanism for a relay to find its address.
+ **/
+
+#include "core/or/or.h"
+
+#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
+
+#include "core/mainloop/mainloop.h"
+
+#include "feature/control/control_events.h"
+#include "feature/dircommon/dir_connection_st.h"
+#include "feature/relay/relay_find_addr.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+
+/** The most recently guessed value of our IP address, based on directory
+ * headers. */
+static tor_addr_t last_guessed_ip = TOR_ADDR_NULL;
+
+/** We failed to resolve our address locally, but we'd like to build
+ * a descriptor and publish / test reachability. If we have a guess
+ * about our address based on directory headers, answer it and return
+ * 0; else return -1. */
+static int
+router_guess_address_from_dir_headers(uint32_t *guess)
+{
+ if (!tor_addr_is_null(&last_guessed_ip)) {
+ *guess = tor_addr_to_ipv4h(&last_guessed_ip);
+ return 0;
+ }
+ return -1;
+}
+
+/** A directory server <b>d_conn</b> told us our IP address is
+ * <b>suggestion</b>.
+ * If this address is different from the one we think we are now, and
+ * if our computer doesn't actually know its IP address, then switch. */
+void
+router_new_address_suggestion(const char *suggestion,
+ const dir_connection_t *d_conn)
+{
+ tor_addr_t addr;
+ uint32_t cur = 0; /* Current IPv4 address. */
+ const or_options_t *options = get_options();
+
+ /* first, learn what the IP address actually is */
+ if (tor_addr_parse(&addr, suggestion) == -1) {
+ log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
+ escaped(suggestion));
+ return;
+ }
+
+ log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
+
+ if (!server_mode(options)) {
+ tor_addr_copy(&last_guessed_ip, &addr);
+ return;
+ }
+
+ /* XXXX ipv6 */
+ cur = get_last_resolved_addr();
+ if (cur ||
+ resolve_my_address(LOG_INFO, options, &cur, NULL, NULL) >= 0) {
+ /* We're all set -- we already know our address. Great. */
+ tor_addr_from_ipv4h(&last_guessed_ip, cur); /* store it in case we
+ need it later */
+ return;
+ }
+ if (tor_addr_is_internal(&addr, 0)) {
+ /* Don't believe anybody who says our IP is, say, 127.0.0.1. */
+ return;
+ }
+ if (tor_addr_eq(&d_conn->base_.addr, &addr)) {
+ /* Don't believe anybody who says our IP is their IP. */
+ log_debug(LD_DIR, "A directory server told us our IP address is %s, "
+ "but they are just reporting their own IP address. Ignoring.",
+ suggestion);
+ return;
+ }
+
+ /* Okay. We can't resolve our own address, and X-Your-Address-Is is giving
+ * us an answer different from what we had the last time we managed to
+ * resolve it. */
+ if (!tor_addr_eq(&last_guessed_ip, &addr)) {
+ control_event_server_status(LOG_NOTICE,
+ "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
+ suggestion);
+ log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr,
+ d_conn->base_.address);
+ ip_address_changed(0);
+ tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
+ will fetch it */
+ }
+}
+
+/** Make a current best guess at our address, either because
+ * it's configured in torrc, or because we've learned it from
+ * dirserver headers. Place the answer in *<b>addr</b> and return
+ * 0 on success, else return -1 if we have no guess.
+ *
+ * If <b>cache_only</b> is true, just return any cached answers, and
+ * don't try to get any new answers.
+ */
+MOCK_IMPL(int,
+router_pick_published_address, (const or_options_t *options, uint32_t *addr,
+ int cache_only))
+{
+ /* First, check the cached output from resolve_my_address(). */
+ *addr = get_last_resolved_addr();
+ if (*addr)
+ return 0;
+
+ /* Second, consider doing a resolve attempt right here. */
+ if (!cache_only) {
+ if (resolve_my_address(LOG_INFO, options, addr, NULL, NULL) >= 0) {
+ log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr));
+ return 0;
+ }
+ }
+
+ /* Third, check the cached output from router_new_address_suggestion(). */
+ if (router_guess_address_from_dir_headers(addr) >= 0)
+ return 0;
+
+ /* We have no useful cached answers. Return failure. */
+ return -1;
+}
diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h
new file mode 100644
index 0000000000..ac51a977e6
--- /dev/null
+++ b/src/feature/relay/relay_find_addr.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay_find_addr.h
+ * \brief Header file for relay_find_addr.c.
+ **/
+
+#ifndef TOR_RELAY_FIND_ADDR_H
+#define TOR_RELAY_FIND_ADDR_H
+
+MOCK_DECL(int, router_pick_published_address,
+ (const or_options_t *options, uint32_t *addr, int cache_only));
+
+void router_new_address_suggestion(const char *suggestion,
+ const dir_connection_t *d_conn);
+
+#ifdef RELAY_FIND_ADDR_PRIVATE
+
+#endif /* RELAY_FIND_ADDR_PRIVATE */
+
+#endif /* TOR_RELAY_FIND_ADDR_H */
+
diff --git a/src/feature/relay/relay_handshake.c b/src/feature/relay/relay_handshake.c
new file mode 100644
index 0000000000..030dc94956
--- /dev/null
+++ b/src/feature/relay/relay_handshake.c
@@ -0,0 +1,565 @@
+/* Copyright (c) 2001 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 relay_handshake.c
+ * @brief Functions to implement the relay-only parts of our
+ * connection handshake.
+ *
+ * Some parts of our TLS link handshake are only done by relays (including
+ * bridges). Specifically, only relays need to send CERTS cells; only
+ * relays need to send or receive AUTHCHALLENGE cells, and only relays need to
+ * send or receive AUTHENTICATE cells.
+ **/
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "feature/relay/relay_handshake.h"
+
+#include "app/config/config.h"
+#include "core/or/connection_or.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "trunnel/link_handshake.h"
+#include "feature/relay/routerkeys.h"
+#include "feature/nodelist/torcert.h"
+
+#include "core/or/or_connection_st.h"
+#include "core/or/or_handshake_certs_st.h"
+#include "core/or/or_handshake_state_st.h"
+#include "core/or/var_cell_st.h"
+
+#include "lib/tls/tortls.h"
+#include "lib/tls/x509.h"
+
+/** Helper used to add an encoded certs to a cert cell */
+static void
+add_certs_cell_cert_helper(certs_cell_t *certs_cell,
+ uint8_t cert_type,
+ const uint8_t *cert_encoded,
+ size_t cert_len)
+{
+ tor_assert(cert_len <= UINT16_MAX);
+ certs_cell_cert_t *ccc = certs_cell_cert_new();
+ ccc->cert_type = cert_type;
+ ccc->cert_len = cert_len;
+ certs_cell_cert_setlen_body(ccc, cert_len);
+ memcpy(certs_cell_cert_getarray_body(ccc), cert_encoded, cert_len);
+
+ certs_cell_add_certs(certs_cell, ccc);
+}
+
+/** Add an encoded X509 cert (stored as <b>cert_len</b> bytes at
+ * <b>cert_encoded</b>) to the trunnel certs_cell_t object that we are
+ * building in <b>certs_cell</b>. Set its type field to <b>cert_type</b>.
+ * (If <b>cert</b> is NULL, take no action.) */
+static void
+add_x509_cert(certs_cell_t *certs_cell,
+ uint8_t cert_type,
+ const tor_x509_cert_t *cert)
+{
+ if (NULL == cert)
+ return;
+
+ const uint8_t *cert_encoded = NULL;
+ size_t cert_len;
+ tor_x509_cert_get_der(cert, &cert_encoded, &cert_len);
+
+ add_certs_cell_cert_helper(certs_cell, cert_type, cert_encoded, cert_len);
+}
+
+/** Add an Ed25519 cert from <b>cert</b> to the trunnel certs_cell_t object
+ * that we are building in <b>certs_cell</b>. Set its type field to
+ * <b>cert_type</b>. (If <b>cert</b> is NULL, take no action.) */
+static void
+add_ed25519_cert(certs_cell_t *certs_cell,
+ uint8_t cert_type,
+ const tor_cert_t *cert)
+{
+ if (NULL == cert)
+ return;
+
+ add_certs_cell_cert_helper(certs_cell, cert_type,
+ cert->encoded, cert->encoded_len);
+}
+
+#ifdef TOR_UNIT_TESTS
+int certs_cell_ed25519_disabled_for_testing = 0;
+#else
+#define certs_cell_ed25519_disabled_for_testing 0
+#endif
+
+/** Send a CERTS cell on the connection <b>conn</b>. Return 0 on success, -1
+ * on failure. */
+int
+connection_or_send_certs_cell(or_connection_t *conn)
+{
+ const tor_x509_cert_t *global_link_cert = NULL, *id_cert = NULL;
+ tor_x509_cert_t *own_link_cert = NULL;
+ var_cell_t *cell;
+
+ certs_cell_t *certs_cell = NULL;
+
+ tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
+
+ if (! conn->handshake_state)
+ return -1;
+
+ const int conn_in_server_mode = ! conn->handshake_state->started_here;
+
+ /* Get the encoded values of the X509 certificates */
+ if (tor_tls_get_my_certs(conn_in_server_mode,
+ &global_link_cert, &id_cert) < 0)
+ return -1;
+
+ if (conn_in_server_mode) {
+ own_link_cert = tor_tls_get_own_cert(conn->tls);
+ }
+ tor_assert(id_cert);
+
+ certs_cell = certs_cell_new();
+
+ /* Start adding certs. First the link cert or auth1024 cert. */
+ if (conn_in_server_mode) {
+ tor_assert_nonfatal(own_link_cert);
+ add_x509_cert(certs_cell,
+ OR_CERT_TYPE_TLS_LINK, own_link_cert);
+ } else {
+ tor_assert(global_link_cert);
+ add_x509_cert(certs_cell,
+ OR_CERT_TYPE_AUTH_1024, global_link_cert);
+ }
+
+ /* Next the RSA->RSA ID cert */
+ add_x509_cert(certs_cell,
+ OR_CERT_TYPE_ID_1024, id_cert);
+
+ /* Next the Ed25519 certs */
+ add_ed25519_cert(certs_cell,
+ CERTTYPE_ED_ID_SIGN,
+ get_master_signing_key_cert());
+ if (conn_in_server_mode) {
+ tor_assert_nonfatal(conn->handshake_state->own_link_cert ||
+ certs_cell_ed25519_disabled_for_testing);
+ add_ed25519_cert(certs_cell,
+ CERTTYPE_ED_SIGN_LINK,
+ conn->handshake_state->own_link_cert);
+ } else {
+ add_ed25519_cert(certs_cell,
+ CERTTYPE_ED_SIGN_AUTH,
+ get_current_auth_key_cert());
+ }
+
+ /* And finally the crosscert. */
+ {
+ const uint8_t *crosscert=NULL;
+ size_t crosscert_len;
+ get_master_rsa_crosscert(&crosscert, &crosscert_len);
+ if (crosscert) {
+ add_certs_cell_cert_helper(certs_cell,
+ CERTTYPE_RSA1024_ID_EDID,
+ crosscert, crosscert_len);
+ }
+ }
+
+ /* We've added all the certs; make the cell. */
+ certs_cell->n_certs = certs_cell_getlen_certs(certs_cell);
+
+ ssize_t alloc_len = certs_cell_encoded_len(certs_cell);
+ tor_assert(alloc_len >= 0 && alloc_len <= UINT16_MAX);
+ cell = var_cell_new(alloc_len);
+ cell->command = CELL_CERTS;
+ ssize_t enc_len = certs_cell_encode(cell->payload, alloc_len, certs_cell);
+ tor_assert(enc_len > 0 && enc_len <= alloc_len);
+ cell->payload_len = enc_len;
+
+ connection_or_write_var_cell_to_buf(cell, conn);
+ var_cell_free(cell);
+ certs_cell_free(certs_cell);
+ tor_x509_cert_free(own_link_cert);
+
+ return 0;
+}
+
+#ifdef TOR_UNIT_TESTS
+int testing__connection_or_pretend_TLSSECRET_is_supported = 0;
+#else
+#define testing__connection_or_pretend_TLSSECRET_is_supported 0
+#endif
+
+/** Return true iff <b>challenge_type</b> is an AUTHCHALLENGE type that
+ * we can send and receive. */
+int
+authchallenge_type_is_supported(uint16_t challenge_type)
+{
+ switch (challenge_type) {
+ case AUTHTYPE_RSA_SHA256_TLSSECRET:
+#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
+ return 1;
+#else
+ return testing__connection_or_pretend_TLSSECRET_is_supported;
+#endif
+ case AUTHTYPE_ED25519_SHA256_RFC5705:
+ return 1;
+ case AUTHTYPE_RSA_SHA256_RFC5705:
+ default:
+ return 0;
+ }
+}
+
+/** Return true iff <b>challenge_type_a</b> is one that we would rather
+ * use than <b>challenge_type_b</b>. */
+int
+authchallenge_type_is_better(uint16_t challenge_type_a,
+ uint16_t challenge_type_b)
+{
+ /* Any supported type is better than an unsupported one;
+ * all unsupported types are equally bad. */
+ if (!authchallenge_type_is_supported(challenge_type_a))
+ return 0;
+ if (!authchallenge_type_is_supported(challenge_type_b))
+ return 1;
+ /* It happens that types are superior in numerically ascending order.
+ * If that ever changes, this must change too. */
+ return (challenge_type_a > challenge_type_b);
+}
+
+/** Send an AUTH_CHALLENGE cell on the connection <b>conn</b>. Return 0
+ * on success, -1 on failure. */
+int
+connection_or_send_auth_challenge_cell(or_connection_t *conn)
+{
+ var_cell_t *cell = NULL;
+ int r = -1;
+ tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
+
+ if (! conn->handshake_state)
+ return -1;
+
+ auth_challenge_cell_t *ac = auth_challenge_cell_new();
+
+ tor_assert(sizeof(ac->challenge) == 32);
+ crypto_rand((char*)ac->challenge, sizeof(ac->challenge));
+
+ if (authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET))
+ auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
+ /* Disabled, because everything that supports this method also supports
+ * the much-superior ED25519_SHA256_RFC5705 */
+ /* auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_RFC5705); */
+ if (authchallenge_type_is_supported(AUTHTYPE_ED25519_SHA256_RFC5705))
+ auth_challenge_cell_add_methods(ac, AUTHTYPE_ED25519_SHA256_RFC5705);
+ auth_challenge_cell_set_n_methods(ac,
+ auth_challenge_cell_getlen_methods(ac));
+
+ cell = var_cell_new(auth_challenge_cell_encoded_len(ac));
+ ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len,
+ ac);
+ if (len != cell->payload_len) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Encoded auth challenge cell length not as expected");
+ goto done;
+ /* LCOV_EXCL_STOP */
+ }
+ cell->command = CELL_AUTH_CHALLENGE;
+
+ connection_or_write_var_cell_to_buf(cell, conn);
+ r = 0;
+
+ done:
+ var_cell_free(cell);
+ auth_challenge_cell_free(ac);
+
+ return r;
+}
+
+/** Compute the main body of an AUTHENTICATE cell that a client can use
+ * to authenticate itself on a v3 handshake for <b>conn</b>. Return it
+ * in a var_cell_t.
+ *
+ * If <b>server</b> is true, only calculate the first
+ * V3_AUTH_FIXED_PART_LEN bytes -- the part of the authenticator that's
+ * determined by the rest of the handshake, and which match the provided value
+ * exactly.
+ *
+ * If <b>server</b> is false and <b>signing_key</b> is NULL, calculate the
+ * first V3_AUTH_BODY_LEN bytes of the authenticator (that is, everything
+ * that should be signed), but don't actually sign it.
+ *
+ * If <b>server</b> is false and <b>signing_key</b> is provided, calculate the
+ * entire authenticator, signed with <b>signing_key</b>.
+ *
+ * Return the length of the cell body on success, and -1 on failure.
+ */
+var_cell_t *
+connection_or_compute_authenticate_cell_body(or_connection_t *conn,
+ const int authtype,
+ crypto_pk_t *signing_key,
+ const ed25519_keypair_t *ed_signing_key,
+ int server)
+{
+ auth1_t *auth = NULL;
+ auth_ctx_t *ctx = auth_ctx_new();
+ var_cell_t *result = NULL;
+ int old_tlssecrets_algorithm = 0;
+ const char *authtype_str = NULL;
+
+ int is_ed = 0;
+
+ /* assert state is reasonable XXXX */
+ switch (authtype) {
+ case AUTHTYPE_RSA_SHA256_TLSSECRET:
+ authtype_str = "AUTH0001";
+ old_tlssecrets_algorithm = 1;
+ break;
+ case AUTHTYPE_RSA_SHA256_RFC5705:
+ authtype_str = "AUTH0002";
+ break;
+ case AUTHTYPE_ED25519_SHA256_RFC5705:
+ authtype_str = "AUTH0003";
+ is_ed = 1;
+ break;
+ default:
+ tor_assert(0);
+ break;
+ }
+
+ auth = auth1_new();
+ ctx->is_ed = is_ed;
+
+ /* Type: 8 bytes. */
+ memcpy(auth1_getarray_type(auth), authtype_str, 8);
+
+ {
+ const tor_x509_cert_t *id_cert=NULL;
+ const common_digests_t *my_digests, *their_digests;
+ const uint8_t *my_id, *their_id, *client_id, *server_id;
+ if (tor_tls_get_my_certs(server, NULL, &id_cert))
+ goto err;
+ my_digests = tor_x509_cert_get_id_digests(id_cert);
+ their_digests =
+ tor_x509_cert_get_id_digests(conn->handshake_state->certs->id_cert);
+ tor_assert(my_digests);
+ tor_assert(their_digests);
+ my_id = (uint8_t*)my_digests->d[DIGEST_SHA256];
+ their_id = (uint8_t*)their_digests->d[DIGEST_SHA256];
+
+ client_id = server ? their_id : my_id;
+ server_id = server ? my_id : their_id;
+
+ /* Client ID digest: 32 octets. */
+ memcpy(auth->cid, client_id, 32);
+
+ /* Server ID digest: 32 octets. */
+ memcpy(auth->sid, server_id, 32);
+ }
+
+ if (is_ed) {
+ const ed25519_public_key_t *my_ed_id, *their_ed_id;
+ if (!conn->handshake_state->certs->ed_id_sign) {
+ log_warn(LD_OR, "Ed authenticate without Ed ID cert from peer.");
+ goto err;
+ }
+ my_ed_id = get_master_identity_key();
+ their_ed_id = &conn->handshake_state->certs->ed_id_sign->signing_key;
+
+ const uint8_t *cid_ed = (server ? their_ed_id : my_ed_id)->pubkey;
+ const uint8_t *sid_ed = (server ? my_ed_id : their_ed_id)->pubkey;
+
+ memcpy(auth->u1_cid_ed, cid_ed, ED25519_PUBKEY_LEN);
+ memcpy(auth->u1_sid_ed, sid_ed, ED25519_PUBKEY_LEN);
+ }
+
+ {
+ crypto_digest_t *server_d, *client_d;
+ if (server) {
+ server_d = conn->handshake_state->digest_sent;
+ client_d = conn->handshake_state->digest_received;
+ } else {
+ client_d = conn->handshake_state->digest_sent;
+ server_d = conn->handshake_state->digest_received;
+ }
+
+ /* Server log digest : 32 octets */
+ crypto_digest_get_digest(server_d, (char*)auth->slog, 32);
+
+ /* Client log digest : 32 octets */
+ crypto_digest_get_digest(client_d, (char*)auth->clog, 32);
+ }
+
+ {
+ /* Digest of cert used on TLS link : 32 octets. */
+ tor_x509_cert_t *cert = NULL;
+ if (server) {
+ cert = tor_tls_get_own_cert(conn->tls);
+ } else {
+ cert = tor_tls_get_peer_cert(conn->tls);
+ }
+ if (!cert) {
+ log_warn(LD_OR, "Unable to find cert when making %s data.",
+ authtype_str);
+ goto err;
+ }
+
+ memcpy(auth->scert,
+ tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
+
+ tor_x509_cert_free(cert);
+ }
+
+ /* HMAC of clientrandom and serverrandom using master key : 32 octets */
+ if (old_tlssecrets_algorithm) {
+ if (tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR, "Somebody asked us for an older TLS "
+ "authentication method (AUTHTYPE_RSA_SHA256_TLSSECRET) "
+ "which we don't support.");
+ }
+ } else {
+ char label[128];
+ tor_snprintf(label, sizeof(label),
+ "EXPORTER FOR TOR TLS CLIENT BINDING %s", authtype_str);
+ int r = tor_tls_export_key_material(conn->tls, auth->tlssecrets,
+ auth->cid, sizeof(auth->cid),
+ label);
+ if (r < 0) {
+ if (r != -2)
+ log_warn(LD_BUG, "TLS key export failed for unknown reason.");
+ // If r == -2, this was openssl bug 7712.
+ goto err;
+ }
+ }
+
+ /* 8 octets were reserved for the current time, but we're trying to get out
+ * of the habit of sending time around willynilly. Fortunately, nothing
+ * checks it. That's followed by 16 bytes of nonce. */
+ crypto_rand((char*)auth->rand, 24);
+
+ ssize_t maxlen = auth1_encoded_len(auth, ctx);
+ if (ed_signing_key && is_ed) {
+ maxlen += ED25519_SIG_LEN;
+ } else if (signing_key && !is_ed) {
+ maxlen += crypto_pk_keysize(signing_key);
+ }
+
+ const int AUTH_CELL_HEADER_LEN = 4; /* 2 bytes of type, 2 bytes of length */
+ result = var_cell_new(AUTH_CELL_HEADER_LEN + maxlen);
+ uint8_t *const out = result->payload + AUTH_CELL_HEADER_LEN;
+ const size_t outlen = maxlen;
+ ssize_t len;
+
+ result->command = CELL_AUTHENTICATE;
+ set_uint16(result->payload, htons(authtype));
+
+ if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Unable to encode signed part of AUTH1 data.");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+
+ if (server) {
+ auth1_t *tmp = NULL;
+ ssize_t len2 = auth1_parse(&tmp, out, len, ctx);
+ if (!tmp) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Unable to parse signed part of AUTH1 data that "
+ "we just encoded");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+ result->payload_len = (tmp->end_of_signed - result->payload);
+
+ auth1_free(tmp);
+ if (len2 != len) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Mismatched length when re-parsing AUTH1 data.");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+ goto done;
+ }
+
+ if (ed_signing_key && is_ed) {
+ ed25519_signature_t sig;
+ if (ed25519_sign(&sig, out, len, ed_signing_key) < 0) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Unable to sign ed25519 authentication data");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+ auth1_setlen_sig(auth, ED25519_SIG_LEN);
+ memcpy(auth1_getarray_sig(auth), sig.sig, ED25519_SIG_LEN);
+
+ } else if (signing_key && !is_ed) {
+ auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
+
+ char d[32];
+ crypto_digest256(d, (char*)out, len, DIGEST_SHA256);
+ int siglen = crypto_pk_private_sign(signing_key,
+ (char*)auth1_getarray_sig(auth),
+ auth1_getlen_sig(auth),
+ d, 32);
+ if (siglen < 0) {
+ log_warn(LD_OR, "Unable to sign AUTH1 data.");
+ goto err;
+ }
+
+ auth1_setlen_sig(auth, siglen);
+ }
+
+ len = auth1_encode(out, outlen, auth, ctx);
+ if (len < 0) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Unable to encode signed AUTH1 data.");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+ tor_assert(len + AUTH_CELL_HEADER_LEN <= result->payload_len);
+ result->payload_len = len + AUTH_CELL_HEADER_LEN;
+ set_uint16(result->payload+2, htons(len));
+
+ goto done;
+
+ err:
+ var_cell_free(result);
+ result = NULL;
+ done:
+ auth1_free(auth);
+ auth_ctx_free(ctx);
+ return result;
+}
+
+/** Send an AUTHENTICATE cell on the connection <b>conn</b>. Return 0 on
+ * success, -1 on failure */
+MOCK_IMPL(int,
+connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype))
+{
+ var_cell_t *cell;
+ crypto_pk_t *pk = tor_tls_get_my_client_auth_key();
+ /* XXXX make sure we're actually supposed to send this! */
+
+ if (!pk) {
+ log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key");
+ return -1;
+ }
+ if (! authchallenge_type_is_supported(authtype)) {
+ log_warn(LD_BUG, "Tried to send authenticate cell with unknown "
+ "authentication type %d", authtype);
+ return -1;
+ }
+
+ cell = connection_or_compute_authenticate_cell_body(conn,
+ authtype,
+ pk,
+ get_current_auth_keypair(),
+ 0 /* not server */);
+ if (! cell) {
+ log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unable to compute authenticate cell!");
+ return -1;
+ }
+ connection_or_write_var_cell_to_buf(cell, conn);
+ var_cell_free(cell);
+
+ return 0;
+}
diff --git a/src/feature/relay/relay_handshake.h b/src/feature/relay/relay_handshake.h
new file mode 100644
index 0000000000..99a658cbcc
--- /dev/null
+++ b/src/feature/relay/relay_handshake.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 2001 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 relay_handshake.h
+ * @brief Header for feature/relay/relay_handshake.c
+ **/
+
+#ifndef TOR_CORE_OR_RELAY_HANDSHAKE_H
+#define TOR_CORE_OR_RELAY_HANDSHAKE_H
+
+#ifdef HAVE_MODULE_RELAY
+struct ed25519_keypair_t;
+
+int connection_or_send_certs_cell(or_connection_t *conn);
+int connection_or_send_auth_challenge_cell(or_connection_t *conn);
+
+var_cell_t *connection_or_compute_authenticate_cell_body(
+ or_connection_t *conn,
+ const int authtype,
+ crypto_pk_t *signing_key,
+ const struct ed25519_keypair_t *ed_signing_key,
+ int server);
+
+int authchallenge_type_is_supported(uint16_t challenge_type);
+int authchallenge_type_is_better(uint16_t challenge_type_a,
+ uint16_t challenge_type_b);
+
+MOCK_DECL(int,connection_or_send_authenticate_cell,
+ (or_connection_t *conn, int type));
+
+#ifdef TOR_UNIT_TESTS
+extern int certs_cell_ed25519_disabled_for_testing;
+#endif
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+static inline int
+connection_or_send_certs_cell(or_connection_t *conn)
+{
+ (void)conn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+static inline int
+connection_or_send_auth_challenge_cell(or_connection_t *conn)
+{
+ (void)conn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+
+static inline var_cell_t *
+connection_or_compute_authenticate_cell_body(
+ or_connection_t *conn,
+ const int authtype,
+ crypto_pk_t *signing_key,
+ const struct ed25519_keypair_t *ed_signing_key,
+ int server)
+{
+ (void)conn;
+ (void)authtype;
+ (void)signing_key;
+ (void)ed_signing_key;
+ (void)server;
+ tor_assert_nonfatal_unreached();
+ return NULL;
+}
+
+#define authchallenge_type_is_supported(t) (0)
+#define authchallenge_type_is_better(a, b) (0)
+
+static inline int
+connection_or_send_authenticate_cell(or_connection_t *conn, int type)
+{
+ (void)conn;
+ (void)type;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+
+#ifdef TOR_UNIT_TESTS
+extern int certs_cell_ed25519_disabled_for_testing;
+#endif
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
+#endif /* !defined(TOR_CORE_OR_RELAY_HANDSHAKE_H) */
diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c
index 8a93118f11..bfe12cd0b0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -31,11 +31,13 @@
#include "feature/nodelist/routerinfo_st.h"
#include "feature/control/control_events.h"
+#ifndef COCCI
#define DECLARE_EVENT(name, roles, flags) \
static periodic_event_item_t name ## _event = \
PERIODIC_EVENT(name, \
PERIODIC_EVENT_ROLE_##roles, \
flags)
+#endif /* !defined(COCCI) */
#define FL(name) (PERIODIC_EVENT_FLAG_##name)
@@ -204,29 +206,34 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
const routerinfo_t *me = router_get_my_routerinfo();
if (me && !check_whether_orport_reachable(options)) {
char *address = tor_dup_ip(me->addr);
- log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that "
- "its ORPort is reachable. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- address, me->or_port);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED ORADDRESS=%s:%d",
- address, me->or_port);
- tor_free(address);
+ if (address) {
+ log_warn(LD_CONFIG,
+ "Your server (%s:%d) has not managed to confirm that "
+ "its ORPort is reachable. Relays do not publish descriptors "
+ "until their ORPort and DirPort are reachable. Please check "
+ "your firewalls, ports, address, /etc/hosts file, etc.",
+ address, me->or_port);
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED ORADDRESS=%s:%d",
+ address, me->or_port);
+ tor_free(address);
+ }
}
if (me && !check_whether_dirport_reachable(options)) {
char *address = tor_dup_ip(me->addr);
- log_warn(LD_CONFIG,
- "Your server (%s:%d) has not managed to confirm that its "
- "DirPort is reachable. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- address, me->dir_port);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED DIRADDRESS=%s:%d",
- address, me->dir_port);
- tor_free(address);
+ if (address) {
+ log_warn(LD_CONFIG,
+ "Your server (%s:%d) has not managed to confirm that its "
+ "DirPort is reachable. Relays do not publish descriptors "
+ "until their ORPort and DirPort are reachable. Please check "
+ "your firewalls, ports, address, /etc/hosts file, etc.",
+ address, me->dir_port);
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED DIRADDRESS=%s:%d",
+ address, me->dir_port);
+ tor_free(address);
+ }
}
}
diff --git a/src/feature/relay/relay_periodic.h b/src/feature/relay/relay_periodic.h
index b6ea83c749..ccda9a440b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,7 +12,20 @@
#ifndef TOR_FEATURE_RELAY_RELAY_PERIODIC_H
#define TOR_FEATURE_RELAY_RELAY_PERIODIC_H
+#ifdef HAVE_MODULE_RELAY
+
void relay_register_periodic_events(void);
void reschedule_descriptor_update_check(void);
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#include "lib/cc/compat_compiler.h"
+
+#define relay_register_periodic_events() \
+ STMT_NIL
+#define reschedule_descriptor_update_check() \
+ STMT_NIL
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
#endif /* !defined(TOR_FEATURE_RELAY_RELAY_PERIODIC_H) */
diff --git a/src/feature/relay/relay_stub.c b/src/feature/relay/relay_stub.c
new file mode 100644
index 0000000000..283aaf6e49
--- /dev/null
+++ b/src/feature/relay/relay_stub.c
@@ -0,0 +1,21 @@
+/* Copyright (c) 2001 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 relay_stub.c
+ * @brief Stub declarations for use when relay module is disabled.
+ **/
+
+#include "orconfig.h"
+#include "feature/relay/relay_sys.h"
+#include "lib/subsys/subsys.h"
+
+const struct subsys_fns_t sys_relay = {
+ .name = "relay",
+ SUBSYS_DECLARE_LOCATION(),
+ .supported = false,
+ .level = RELAY_SUBSYS_LEVEL,
+};
diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c
index 106e88b2a5..2e90740925 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -41,8 +41,9 @@ subsys_relay_shutdown(void)
const struct subsys_fns_t sys_relay = {
.name = "relay",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
- .level = 50,
+ .level = RELAY_SUBSYS_LEVEL,
.initialize = subsys_relay_initialize,
.shutdown = subsys_relay_shutdown,
};
diff --git a/src/feature/relay/relay_sys.h b/src/feature/relay/relay_sys.h
index 32e21d90d8..9bad93a6c9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,4 +14,12 @@
extern const struct subsys_fns_t sys_relay;
+/**
+ * Subsystem level for the relay system.
+ *
+ * Defined here so that it can be shared between the real and stub
+ * definitions.
+ **/
+#define RELAY_SUBSYS_LEVEL 50
+
#endif /* !defined(TOR_FEATURE_RELAY_RELAY_SYS_H) */
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index a46b522bd6..34d8163c36 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -1,13 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTER_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "app/config/statefile.h"
#include "app/main/main.h"
#include "core/mainloop/connection.h"
@@ -35,6 +36,8 @@
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/torcert.h"
#include "feature/relay/dns.h"
+#include "feature/relay/relay_config.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routerkeys.h"
#include "feature/relay/routermode.h"
@@ -372,6 +375,8 @@ assert_identity_keys_ok(void)
}
}
+#ifdef HAVE_MODULE_RELAY
+
/** Returns the current server identity key; requires that the key has
* been set, and that we are running as a Tor server.
*/
@@ -384,6 +389,8 @@ get_server_identity_key,(void))
return server_identitykey;
}
+#endif /* defined(HAVE_MODULE_RELAY) */
+
/** Return true iff we are a server and the server identity key
* has been set. */
int
@@ -743,8 +750,8 @@ v3_authority_check_key_expiry(void)
}
/** Get the lifetime of an onion key in days. This value is defined by the
- * network consesus parameter "onion-key-rotation-days". Always returns a value
- * between <b>MIN_ONION_KEY_LIFETIME_DAYS</b> and
+ * network consensus parameter "onion-key-rotation-days". Always returns a
+ * value between <b>MIN_ONION_KEY_LIFETIME_DAYS</b> and
* <b>MAX_ONION_KEY_LIFETIME_DAYS</b>.
*/
static int
@@ -758,7 +765,7 @@ get_onion_key_rotation_days_(void)
}
/** Get the current lifetime of an onion key in seconds. This value is defined
- * by the network consesus parameter "onion-key-rotation-days", but the value
+ * by the network consensus parameter "onion-key-rotation-days", but the value
* is converted to seconds.
*/
int
@@ -768,7 +775,7 @@ get_onion_key_lifetime(void)
}
/** Get the grace period of an onion key in seconds. This value is defined by
- * the network consesus parameter "onion-key-grace-period-days", but the value
+ * the network consensus parameter "onion-key-grace-period-days", but the value
* is converted to seconds.
*/
int
@@ -882,15 +889,6 @@ init_keys_common(void)
if (!key_lock)
key_lock = tor_mutex_new();
- /* There are a couple of paths that put us here before we've asked
- * openssl to initialize itself. */
- if (crypto_global_init(get_options()->HardwareAccel,
- get_options()->AccelName,
- get_options()->AccelDir)) {
- log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting.");
- return -1;
- }
-
return 0;
}
@@ -1078,8 +1076,10 @@ init_keys(void)
if (authdir_mode_v3(options)) {
const char *m = NULL;
routerinfo_t *ri;
- /* We need to add our own fingerprint so it gets recognized. */
- if (dirserv_add_own_fingerprint(get_server_identity_key())) {
+ /* We need to add our own fingerprint and ed25519 key so it gets
+ * recognized. */
+ if (dirserv_add_own_fingerprint(get_server_identity_key(),
+ get_master_identity_key())) {
log_err(LD_GENERAL,"Error adding own fingerprint to set of relays");
return -1;
}
@@ -1218,7 +1218,7 @@ router_should_be_dirserver(const or_options_t *options, int dir_port)
* much larger effect on output than input so there is no reason to turn it
* off if using AccountingRule in. */
int interval_length = accounting_get_interval_length();
- uint32_t effective_bw = get_effective_bwrate(options);
+ uint32_t effective_bw = relay_get_effective_bwrate(options);
uint64_t acc_bytes;
if (!interval_length) {
log_warn(LD_BUG, "An accounting interval is not allowed to be zero "
@@ -1400,7 +1400,7 @@ consider_publishable_server(int force)
}
/** Return the port of the first active listener of type
- * <b>listener_type</b>. */
+ * <b>listener_type</b>. Returns 0 if no port is found. */
/** XXX not a very good interface. it's not reliable when there are
multiple listeners. */
uint16_t
@@ -1422,8 +1422,7 @@ router_get_active_listener_port_by_type_af(int listener_type,
/** Return the port that we should advertise as our ORPort; this is either
* the one configured in the ORPort option, or the one we actually bound to
- * if ORPort is "auto".
- */
+ * if ORPort is "auto". Returns 0 if no port is found. */
uint16_t
router_get_advertised_or_port(const or_options_t *options)
{
@@ -1449,6 +1448,68 @@ router_get_advertised_or_port_by_af(const or_options_t *options,
return port;
}
+/** As router_get_advertised_or_port(), but returns the IPv6 address and
+ * port in ipv6_ap_out, which must not be NULL. Returns a null address and
+ * zero port, if no ORPort is found. */
+void
+router_get_advertised_ipv6_or_ap(const or_options_t *options,
+ tor_addr_port_t *ipv6_ap_out)
+{
+ /* Bug in calling function, we can't return a sensible result, and it
+ * shouldn't use the NULL pointer once we return. */
+ tor_assert(ipv6_ap_out);
+
+ /* If there is no valid IPv6 ORPort, return a null address and port. */
+ tor_addr_make_null(&ipv6_ap_out->addr, AF_INET6);
+ ipv6_ap_out->port = 0;
+
+ const tor_addr_t *addr = get_first_advertised_addr_by_type_af(
+ CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ const uint16_t port = router_get_advertised_or_port_by_af(
+ options,
+ AF_INET6);
+
+ if (!addr || port == 0) {
+ log_debug(LD_CONFIG, "There is no advertised IPv6 ORPort.");
+ return;
+ }
+
+ /* If the relay is configured using the default authorities, disallow
+ * internal IPs. Otherwise, allow them. For IPv4 ORPorts and DirPorts,
+ * this check is done in resolve_my_address(). See #33681. */
+ const int default_auth = using_default_dir_authorities(options);
+ if (tor_addr_is_internal(addr, 0) && default_auth) {
+ log_warn(LD_CONFIG,
+ "Unable to use configured IPv6 ORPort \"%s\" in a "
+ "descriptor. Skipping it. "
+ "Try specifying a globally reachable address explicitly.",
+ fmt_addrport(addr, port));
+ return;
+ }
+
+ tor_addr_copy(&ipv6_ap_out->addr, addr);
+ ipv6_ap_out->port = port;
+}
+
+/** Returns true if this router has an advertised IPv6 ORPort. */
+bool
+router_has_advertised_ipv6_orport(const or_options_t *options)
+{
+ tor_addr_port_t ipv6_ap;
+ router_get_advertised_ipv6_or_ap(options, &ipv6_ap);
+ return tor_addr_port_is_valid_ap(&ipv6_ap, 0);
+}
+
+/** Returns true if this router has an advertised IPv6 ORPort. */
+MOCK_IMPL(bool,
+router_can_extend_over_ipv6,(const or_options_t *options))
+{
+ /* We might add some extra checks here, such as ExtendAllowIPv6Addresses
+ * from ticket 33818. */
+ return router_has_advertised_ipv6_orport(options);
+}
+
/** Return the port that we should advertise as our DirPort;
* this is one of three possibilities:
* The one that is passed as <b>dirport</b> if the DirPort option is 0, or
@@ -1704,41 +1765,6 @@ router_get_descriptor_gen_reason(void)
return desc_gen_reason;
}
-static int router_guess_address_from_dir_headers(uint32_t *guess);
-
-/** Make a current best guess at our address, either because
- * it's configured in torrc, or because we've learned it from
- * dirserver headers. Place the answer in *<b>addr</b> and return
- * 0 on success, else return -1 if we have no guess.
- *
- * If <b>cache_only</b> is true, just return any cached answers, and
- * don't try to get any new answers.
- */
-MOCK_IMPL(int,
-router_pick_published_address,(const or_options_t *options, uint32_t *addr,
- int cache_only))
-{
- /* First, check the cached output from resolve_my_address(). */
- *addr = get_last_resolved_addr();
- if (*addr)
- return 0;
-
- /* Second, consider doing a resolve attempt right here. */
- if (!cache_only) {
- if (resolve_my_address(LOG_INFO, options, addr, NULL, NULL) >= 0) {
- log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr));
- return 0;
- }
- }
-
- /* Third, check the cached output from router_new_address_suggestion(). */
- if (router_guess_address_from_dir_headers(addr) >= 0)
- return 0;
-
- /* We have no useful cached answers. Return failure. */
- return -1;
-}
-
/* Like router_check_descriptor_address_consistency, but specifically for the
* ORPort or DirPort.
* listener_type is either CONN_TYPE_OR_LISTENER or CONN_TYPE_DIR_LISTENER. */
@@ -1993,34 +2019,11 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
sizeof(curve25519_public_key_t));
/* For now, at most one IPv6 or-address is being advertised. */
- {
- const port_cfg_t *ipv6_orport = NULL;
- SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
- if (p->type == CONN_TYPE_OR_LISTENER &&
- ! p->server_cfg.no_advertise &&
- ! p->server_cfg.bind_ipv4_only &&
- tor_addr_family(&p->addr) == AF_INET6) {
- /* Like IPv4, if the relay is configured using the default
- * authorities, disallow internal IPs. Otherwise, allow them. */
- const int default_auth = using_default_dir_authorities(options);
- if (! tor_addr_is_internal(&p->addr, 0) || ! default_auth) {
- ipv6_orport = p;
- break;
- } else {
- char addrbuf[TOR_ADDR_BUF_LEN];
- log_warn(LD_CONFIG,
- "Unable to use configured IPv6 address \"%s\" in a "
- "descriptor. Skipping it. "
- "Try specifying a globally reachable address explicitly.",
- tor_addr_to_str(addrbuf, &p->addr, sizeof(addrbuf), 1));
- }
- }
- } SMARTLIST_FOREACH_END(p);
- if (ipv6_orport) {
- tor_addr_copy(&ri->ipv6_addr, &ipv6_orport->addr);
- ri->ipv6_orport = ipv6_orport->port;
- }
- }
+ tor_addr_port_t ipv6_orport;
+ router_get_advertised_ipv6_or_ap(options, &ipv6_orport);
+ /* If there is no valid IPv6 ORPort, the address and port are null. */
+ tor_addr_copy(&ri->ipv6_addr, &ipv6_orport.addr);
+ ri->ipv6_orport = ipv6_orport.port;
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (BUG(crypto_pk_get_digest(ri->identity_pkey,
@@ -2037,10 +2040,10 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
ri->protocol_list = tor_strdup(protover_get_supported_protocols());
/* compute ri->bandwidthrate as the min of various options */
- ri->bandwidthrate = get_effective_bwrate(options);
+ ri->bandwidthrate = relay_get_effective_bwrate(options);
/* and compute ri->bandwidthburst similarly */
- ri->bandwidthburst = get_effective_bwburst(options);
+ ri->bandwidthburst = relay_get_effective_bwburst(options);
/* Report bandwidth, unless we're hibernating or shutting down */
ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess();
@@ -2487,7 +2490,7 @@ check_descriptor_bandwidth_changed(time_t now)
/** Note at log level severity that our best guess of address has changed from
* <b>prev</b> to <b>cur</b>. */
-static void
+void
log_addr_has_changed(int severity,
const tor_addr_t *prev,
const tor_addr_t *cur,
@@ -2559,86 +2562,6 @@ check_descriptor_ipaddress_changed(time_t now)
tor_free(hostname);
}
-/** The most recently guessed value of our IP address, based on directory
- * headers. */
-static tor_addr_t last_guessed_ip = TOR_ADDR_NULL;
-
-/** A directory server <b>d_conn</b> told us our IP address is
- * <b>suggestion</b>.
- * If this address is different from the one we think we are now, and
- * if our computer doesn't actually know its IP address, then switch. */
-void
-router_new_address_suggestion(const char *suggestion,
- const dir_connection_t *d_conn)
-{
- tor_addr_t addr;
- uint32_t cur = 0; /* Current IPv4 address. */
- const or_options_t *options = get_options();
-
- /* first, learn what the IP address actually is */
- if (tor_addr_parse(&addr, suggestion) == -1) {
- log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
- escaped(suggestion));
- return;
- }
-
- log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
-
- if (!server_mode(options)) {
- tor_addr_copy(&last_guessed_ip, &addr);
- return;
- }
-
- /* XXXX ipv6 */
- cur = get_last_resolved_addr();
- if (cur ||
- resolve_my_address(LOG_INFO, options, &cur, NULL, NULL) >= 0) {
- /* We're all set -- we already know our address. Great. */
- tor_addr_from_ipv4h(&last_guessed_ip, cur); /* store it in case we
- need it later */
- return;
- }
- if (tor_addr_is_internal(&addr, 0)) {
- /* Don't believe anybody who says our IP is, say, 127.0.0.1. */
- return;
- }
- if (tor_addr_eq(&d_conn->base_.addr, &addr)) {
- /* Don't believe anybody who says our IP is their IP. */
- log_debug(LD_DIR, "A directory server told us our IP address is %s, "
- "but they are just reporting their own IP address. Ignoring.",
- suggestion);
- return;
- }
-
- /* Okay. We can't resolve our own address, and X-Your-Address-Is is giving
- * us an answer different from what we had the last time we managed to
- * resolve it. */
- if (!tor_addr_eq(&last_guessed_ip, &addr)) {
- control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
- suggestion);
- log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr,
- d_conn->base_.address);
- ip_address_changed(0);
- tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
- will fetch it */
- }
-}
-
-/** We failed to resolve our address locally, but we'd like to build
- * a descriptor and publish / test reachability. If we have a guess
- * about our address based on directory headers, answer it and return
- * 0; else return -1. */
-static int
-router_guess_address_from_dir_headers(uint32_t *guess)
-{
- if (!tor_addr_is_null(&last_guessed_ip)) {
- *guess = tor_addr_to_ipv4h(&last_guessed_ip);
- return 0;
- }
- return -1;
-}
-
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
* string describing the version of Tor and the operating system we're
* currently running on.
@@ -2861,6 +2784,9 @@ router_dump_router_to_string(routerinfo_t *router,
}
address = tor_dup_ip(router->addr);
+ if (!address)
+ goto err;
+
chunks = smartlist_new();
/* Generate the easy portion of the router descriptor. */
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 55b9ef9e68..50790a73dd 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,7 +28,13 @@ struct ed25519_keypair_t;
MOCK_DECL(crypto_pk_t *,get_onion_key,(void));
time_t get_onion_key_set_at(void);
void set_server_identity_key(crypto_pk_t *k);
+/* Some compilers are clever enough to know that when relay mode is disabled,
+ * this function never returns. */
+#ifdef HAVE_MODULE_RELAY
MOCK_DECL(crypto_pk_t *,get_server_identity_key,(void));
+#else
+#define get_server_identity_key() (tor_abort_(),NULL)
+#endif
int server_identity_key_is_set(void);
void set_client_identity_key(crypto_pk_t *k);
crypto_pk_t *get_tlsclient_identity_key(void);
@@ -60,6 +66,10 @@ int init_keys_client(void);
uint16_t router_get_active_listener_port_by_type_af(int listener_type,
sa_family_t family);
uint16_t router_get_advertised_or_port(const or_options_t *options);
+void router_get_advertised_ipv6_or_ap(const or_options_t *options,
+ tor_addr_port_t *ipv6_ap_out);
+bool router_has_advertised_ipv6_orport(const or_options_t *options);
+MOCK_DECL(bool, router_can_extend_over_ipv6,(const or_options_t *options));
uint16_t router_get_advertised_or_port_by_af(const or_options_t *options,
sa_family_t family);
uint16_t router_get_advertised_dir_port(const or_options_t *options,
@@ -77,8 +87,6 @@ void mark_my_descriptor_dirty(const char *reason);
void check_descriptor_bandwidth_changed(time_t now);
void check_descriptor_ipaddress_changed(time_t now);
int router_has_bandwidth_to_be_dirserver(const or_options_t *options);
-void router_new_address_suggestion(const char *suggestion,
- const dir_connection_t *d_conn);
int router_compare_to_my_exit_policy(const tor_addr_t *addr, uint16_t port);
MOCK_DECL(int, router_my_exit_policy_is_reject_star,(void));
MOCK_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
@@ -90,9 +98,6 @@ int router_digest_is_me(const char *digest);
const uint8_t *router_get_my_id_digest(void);
int router_extrainfo_digest_is_me(const char *digest);
int router_is_me(const routerinfo_t *router);
-MOCK_DECL(int,router_pick_published_address,(const or_options_t *options,
- uint32_t *addr,
- int cache_only));
int router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e);
int router_rebuild_descriptor(int force);
char *router_dump_router_to_string(routerinfo_t *router,
@@ -110,8 +115,10 @@ int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo,
const char *routerinfo_err_to_string(int err);
int routerinfo_err_is_transient(int err);
+void log_addr_has_changed(int severity, const tor_addr_t *prev,
+ const tor_addr_t *cur, const char *source);
+
void router_reset_warnings(void);
-void router_reset_reachability(void);
void router_free_all(void);
#ifdef ROUTER_PRIVATE
diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c
index a9190b2e13..d3de83cb86 100644
--- a/src/feature/relay/routerkeys.c
+++ b/src/feature/relay/routerkeys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h
index cde07b52c3..1fb5d724e9 100644
--- a/src/feature/relay/routerkeys.h
+++ b/src/feature/relay/routerkeys.h
@@ -1,11 +1,18 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerkeys.h
+ * @brief Header for routerkeys.c
+ **/
+
#ifndef TOR_ROUTERKEYS_H
#define TOR_ROUTERKEYS_H
#include "lib/crypt_ops/crypto_ed25519.h"
+#ifdef HAVE_MODULE_RELAY
+
const ed25519_public_key_t *get_master_identity_key(void);
MOCK_DECL(const ed25519_keypair_t *, get_master_signing_keypair,(void));
MOCK_DECL(const struct tor_cert_st *, get_master_signing_key_cert,(void));
@@ -19,6 +26,7 @@ void get_master_rsa_crosscert(const uint8_t **cert_out,
int router_ed25519_id_is_me(const ed25519_public_key_t *id);
+/* These are only used by router.c */
struct tor_cert_st *make_ntor_onion_key_crosscert(
const curve25519_keypair_t *onion_key,
const ed25519_public_key_t *master_id_key,
@@ -37,6 +45,85 @@ int generate_ed_link_cert(const or_options_t *options, time_t now, int force);
void routerkeys_free_all(void);
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#define router_ed25519_id_is_me(id) \
+ ((void)(id), 0)
+
+static inline void *
+relay_key_is_unavailable_(void)
+{
+ tor_assert_nonfatal_unreached();
+ return NULL;
+}
+#define relay_key_is_unavailable(type) \
+ ((type)(relay_key_is_unavailable_()))
+
+// Many of these can be removed once relay_handshake.c is relay-only.
+#define get_current_auth_keypair() \
+ relay_key_is_unavailable(const ed25519_keypair_t *)
+#define get_master_signing_keypair() \
+ relay_key_is_unavailable(const ed25519_keypair_t *)
+#define get_current_link_cert_cert() \
+ relay_key_is_unavailable(const struct tor_cert_st *)
+#define get_current_auth_key_cert() \
+ relay_key_is_unavailable(const struct tor_cert_st *)
+#define get_master_signing_key_cert() \
+ relay_key_is_unavailable(const struct tor_cert_st *)
+#define get_master_rsa_crosscert(cert_out, size_out) \
+ STMT_BEGIN \
+ tor_assert_nonfatal_unreached(); \
+ *(cert_out) = NULL; \
+ *(size_out) = 0; \
+ STMT_END
+#define get_master_identity_key() \
+ relay_key_is_unavailable(const ed25519_public_key_t *)
+
+#define generate_ed_link_cert(options, now, force) \
+ ((void)(options), (void)(now), (void)(force), 0)
+#define should_make_new_ed_keys(options, now) \
+ ((void)(options), (void)(now), 0)
+
+// These can get removed once router.c becomes relay-only.
+static inline struct tor_cert_st *
+make_ntor_onion_key_crosscert(const curve25519_keypair_t *onion_key,
+ const ed25519_public_key_t *master_id_key,
+ time_t now, time_t lifetime,
+ int *sign_out)
+{
+ (void)onion_key;
+ (void)master_id_key;
+ (void)now;
+ (void)lifetime;
+ *sign_out = 0;
+ tor_assert_nonfatal_unreached();
+ return NULL;
+}
+static inline uint8_t *
+make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
+ const ed25519_public_key_t *master_id_key,
+ const crypto_pk_t *rsa_id_key,
+ int *len_out)
+{
+ (void)onion_key;
+ (void)master_id_key;
+ (void)rsa_id_key;
+ *len_out = 0;
+ tor_assert_nonfatal_unreached();
+ return NULL;
+}
+
+/* This calls is used outside of relay mode, but only to implement
+ * CMD_KEY_EXPIRATION */
+#define log_cert_expiration() \
+ (puts("Not available: Tor has been compiled without relay support"), 0)
+/* This calls is used outside of relay mode, but only to implement
+ * CMD_KEYGEN. */
+#define load_ed_keys(x,y) \
+ (puts("Not available: Tor has been compiled without relay support"), 0)
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
#ifdef TOR_UNIT_TESTS
const ed25519_keypair_t *get_master_identity_keypair(void);
void init_mock_ed_keys(const crypto_pk_t *rsa_identity_key);
diff --git a/src/feature/relay/routermode.c b/src/feature/relay/routermode.c
index 2a9ddeac4d..c4d8792b5b 100644
--- a/src/feature/relay/routermode.c
+++ b/src/feature/relay/routermode.c
@@ -1,14 +1,17 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routermode.c
+ * @brief Check if we're running as a relay/cache.
+ **/
+
#include "core/or/or.h"
#include "app/config/config.h"
-#include "core/mainloop/connection.h"
-#include "core/or/port_cfg_st.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
@@ -25,21 +28,6 @@ dir_server_mode(const or_options_t *options)
(server_mode(options) && router_has_bandwidth_to_be_dirserver(options));
}
-/** Return true iff we are trying to proxy client connections. */
-int
-proxy_mode(const or_options_t *options)
-{
- (void)options;
- SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
- if (p->type == CONN_TYPE_AP_LISTENER ||
- p->type == CONN_TYPE_AP_TRANS_LISTENER ||
- p->type == CONN_TYPE_AP_DNS_LISTENER ||
- p->type == CONN_TYPE_AP_NATD_LISTENER)
- return 1;
- } SMARTLIST_FOREACH_END(p);
- return 0;
-}
-
/** Return true iff we are trying to be a server.
*/
MOCK_IMPL(int,
diff --git a/src/feature/relay/routermode.h b/src/feature/relay/routermode.h
index be535af478..6d7404968d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,13 +12,31 @@
#ifndef TOR_ROUTERMODE_H
#define TOR_ROUTERMODE_H
+#ifdef HAVE_MODULE_RELAY
+
int dir_server_mode(const or_options_t *options);
MOCK_DECL(int, server_mode, (const or_options_t *options));
MOCK_DECL(int, public_server_mode, (const or_options_t *options));
MOCK_DECL(int, advertised_server_mode, (void));
-int proxy_mode(const or_options_t *options);
void set_server_advertised(int s);
+/** Is the relay module enabled? */
+#define have_module_relay() (1)
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#define dir_server_mode(options) (((void)(options)),0)
+#define server_mode(options) (((void)(options)),0)
+#define public_server_mode(options) (((void)(options)),0)
+#define advertised_server_mode() (0)
+
+/* We shouldn't be publishing descriptors when relay mode is disabled. */
+#define set_server_advertised(s) tor_assert_nonfatal(!(s))
+
+#define have_module_relay() (0)
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
#endif /* !defined(TOR_ROUTERMODE_H) */
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index f8b54ff45d..18fe25b989 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -1,19 +1,17 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file selftest.c
* \brief Relay self-testing
*
- * Relays need to make sure that their own ports are reasonable, and estimate
+ * Relays need to make sure that their own ports are reachable, and estimate
* their own bandwidth, before publishing.
*/
-#define SELFTEST_PRIVATE
-
#include "core/or/or.h"
#include "app/config/config.h"
@@ -215,6 +213,44 @@ router_do_reachability_checks(int test_or, int test_dir)
}
}
+/** We've decided to start our reachability testing. If all
+ * is set, log this to the user. Return 1 if we did, or 0 if
+ * we chose not to log anything. */
+int
+inform_testing_reachability(void)
+{
+ char dirbuf[128];
+ char *address;
+ const routerinfo_t *me = router_get_my_routerinfo();
+ if (!me)
+ return 0;
+
+ address = tor_dup_ip(me->addr);
+ if (!address)
+ return 0;
+
+ control_event_server_status(LOG_NOTICE,
+ "CHECKING_REACHABILITY ORADDRESS=%s:%d",
+ address, me->or_port);
+ if (me->dir_port) {
+ tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d",
+ address, me->dir_port);
+ control_event_server_status(LOG_NOTICE,
+ "CHECKING_REACHABILITY DIRADDRESS=%s:%d",
+ address, me->dir_port);
+ }
+ log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... "
+ "(this may take up to %d minutes -- look for log "
+ "messages indicating success)",
+ address, me->or_port,
+ me->dir_port ? dirbuf : "",
+ me->dir_port ? "are" : "is",
+ TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
+
+ tor_free(address);
+ return 1;
+}
+
/** Annotate that we found our ORPort reachable. */
void
router_orport_found_reachable(void)
@@ -223,6 +259,10 @@ router_orport_found_reachable(void)
const or_options_t *options = get_options();
if (!can_reach_or_port && me) {
char *address = tor_dup_ip(me->addr);
+
+ if (!address)
+ return;
+
log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
"the outside. Excellent.%s",
options->PublishServerDescriptor_ != NO_DIRINFO
@@ -250,6 +290,10 @@ router_dirport_found_reachable(void)
const or_options_t *options = get_options();
if (!can_reach_dir_port && me) {
char *address = tor_dup_ip(me->addr);
+
+ if (!address)
+ return;
+
log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
"from the outside. Excellent.%s",
options->PublishServerDescriptor_ != NO_DIRINFO
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index aea77ec791..f5babc95da 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,13 +12,57 @@
#ifndef TOR_SELFTEST_H
#define TOR_SELFTEST_H
+#ifdef HAVE_MODULE_RELAY
+
struct or_options_t;
int check_whether_orport_reachable(const struct or_options_t *options);
int check_whether_dirport_reachable(const struct or_options_t *options);
void router_do_reachability_checks(int test_or, int test_dir);
+void router_perform_bandwidth_test(int num_circs, time_t now);
+int inform_testing_reachability(void);
+
void router_orport_found_reachable(void);
void router_dirport_found_reachable(void);
-void router_perform_bandwidth_test(int num_circs, time_t now);
+
+void router_reset_reachability(void);
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#define check_whether_orport_reachable(opts) \
+ ((void)(opts), 0)
+#define check_whether_dirport_reachable(opts) \
+ ((void)(opts), 0)
+
+static inline void
+router_do_reachability_checks(int test_or, int test_dir)
+{
+ (void)test_or;
+ (void)test_dir;
+ tor_assert_nonfatal_unreached();
+}
+static inline void
+router_perform_bandwidth_test(int num_circs, time_t now)
+{
+ (void)num_circs;
+ (void)now;
+ tor_assert_nonfatal_unreached();
+}
+static inline int
+inform_testing_reachability(void)
+{
+ 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
+
+#endif /* defined(HAVE_MODULE_RELAY) */
#endif /* !defined(TOR_SELFTEST_H) */
diff --git a/src/feature/relay/transport_config.c b/src/feature/relay/transport_config.c
new file mode 100644
index 0000000000..7dcce70e30
--- /dev/null
+++ b/src/feature/relay/transport_config.c
@@ -0,0 +1,307 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file transport_config.c
+ * @brief Code to interpret the user's configuration of Tor's server
+ * pluggable transports.
+ **/
+
+#include "orconfig.h"
+#define RELAY_TRANSPORT_CONFIG_PRIVATE
+#include "feature/relay/transport_config.h"
+
+#include "lib/encoding/confline.h"
+#include "lib/encoding/keyval.h"
+
+#include "lib/container/smartlist.h"
+
+/* Required for dirinfo_type_t in or_options_t */
+#include "core/or/or.h"
+#include "app/config/config.h"
+
+#include "feature/relay/ext_orport.h"
+#include "feature/relay/routermode.h"
+
+/* Copied from config.c, we will refactor later in 29211. */
+#define REJECT(arg) \
+ STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
+
+/** Given a ServerTransportListenAddr <b>line</b>, return its
+ * <address:port> string. Return NULL if the line was not
+ * well-formed.
+ *
+ * If <b>transport</b> is set, return NULL if the line is not
+ * referring to <b>transport</b>.
+ *
+ * The returned string is allocated on the heap and it's the
+ * responsibility of the caller to free it. */
+static char *
+get_bindaddr_from_transport_listen_line(const char *line,
+ const char *transport)
+{
+ smartlist_t *items = NULL;
+ const char *parsed_transport = NULL;
+ char *addrport = NULL;
+ tor_addr_t addr;
+ uint16_t port = 0;
+
+ items = smartlist_new();
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(items) < 2) {
+ log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line.");
+ goto err;
+ }
+
+ parsed_transport = smartlist_get(items, 0);
+ addrport = tor_strdup(smartlist_get(items, 1));
+
+ /* If 'transport' is given, check if it matches the one on the line */
+ if (transport && strcmp(transport, parsed_transport))
+ goto err;
+
+ /* Validate addrport */
+ if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) {
+ log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
+ "address '%s'", addrport);
+ goto err;
+ }
+
+ goto done;
+
+ err:
+ tor_free(addrport);
+ addrport = NULL;
+
+ done:
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+
+ return addrport;
+}
+
+/** Given the name of a pluggable transport in <b>transport</b>, check
+ * the configuration file to see if the user has explicitly asked for
+ * it to listen on a specific port. Return a <address:port> string if
+ * so, otherwise NULL. */
+char *
+pt_get_bindaddr_from_config(const char *transport)
+{
+ config_line_t *cl;
+ const or_options_t *options = get_options();
+
+ for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+ char *bindaddr =
+ get_bindaddr_from_transport_listen_line(cl->value, transport);
+ if (bindaddr)
+ return bindaddr;
+ }
+
+ return NULL;
+}
+
+/** Given a ServerTransportOptions <b>line</b>, return a smartlist
+ * with the options. Return NULL if the line was not well-formed.
+ *
+ * If <b>transport</b> is set, return NULL if the line is not
+ * referring to <b>transport</b>.
+ *
+ * The returned smartlist and its strings are allocated on the heap
+ * and it's the responsibility of the caller to free it. */
+STATIC smartlist_t *
+get_options_from_transport_options_line(const char *line,
+ const char *transport)
+{
+ smartlist_t *items = smartlist_new();
+ smartlist_t *pt_options = smartlist_new();
+ const char *parsed_transport = NULL;
+
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(items) < 2) {
+ log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line.");
+ goto err;
+ }
+
+ parsed_transport = smartlist_get(items, 0);
+ /* If 'transport' is given, check if it matches the one on the line */
+ if (transport && strcmp(transport, parsed_transport))
+ goto err;
+
+ SMARTLIST_FOREACH_BEGIN(items, const char *, option) {
+ if (option_sl_idx == 0) /* skip the transport field (first field)*/
+ continue;
+
+ /* validate that it's a k=v value */
+ if (!string_is_key_value(LOG_WARN, option)) {
+ log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option));
+ goto err;
+ }
+
+ /* add it to the options smartlist */
+ smartlist_add_strdup(pt_options, option);
+ log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option));
+ } SMARTLIST_FOREACH_END(option);
+
+ goto done;
+
+ err:
+ SMARTLIST_FOREACH(pt_options, char*, s, tor_free(s));
+ smartlist_free(pt_options);
+ pt_options = NULL;
+
+ done:
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+
+ return pt_options;
+}
+
+/** Given the name of a pluggable transport in <b>transport</b>, check
+ * the configuration file to see if the user has asked us to pass any
+ * parameters to the pluggable transport. Return a smartlist
+ * containing the parameters, otherwise NULL. */
+smartlist_t *
+pt_get_options_for_server_transport(const char *transport)
+{
+ config_line_t *cl;
+ const or_options_t *options = get_options();
+
+ for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
+ smartlist_t *options_sl =
+ get_options_from_transport_options_line(cl->value, transport);
+ if (options_sl)
+ return options_sl;
+ }
+
+ return NULL;
+}
+
+/**
+ * Legacy validation/normalization function for the server transport options.
+ * Uses old_options as the previous options.
+ *
+ * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
+ * on error.
+ */
+int
+options_validate_server_transport(const or_options_t *old_options,
+ or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ if (BUG(!options))
+ return -1;
+
+ if (BUG(!msg))
+ return -1;
+
+ config_line_t *cl;
+
+ if (options->ServerTransportPlugin && !server_mode(options)) {
+ log_notice(LD_GENERAL, "Tor is not configured as a relay but you specified"
+ " a ServerTransportPlugin line (%s). The ServerTransportPlugin "
+ "line will be ignored.",
+ escaped(options->ServerTransportPlugin->value));
+ }
+
+ if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) {
+ log_notice(LD_GENERAL, "You need at least a single managed-proxy to "
+ "specify a transport listen address. The "
+ "ServerTransportListenAddr line will be ignored.");
+ }
+
+ for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
+ if (pt_parse_transport_line(options, cl->value, 1, 1) < 0)
+ REJECT("Invalid server transport line. See logs for details.");
+ }
+
+ for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+ /** If get_bindaddr_from_transport_listen_line() fails with
+ 'transport' being NULL, it means that something went wrong
+ while parsing the ServerTransportListenAddr line. */
+ char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL);
+ if (!bindaddr)
+ REJECT("ServerTransportListenAddr did not parse. See logs for details.");
+ tor_free(bindaddr);
+ }
+
+ for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
+ /** If get_options_from_transport_options_line() fails with
+ 'transport' being NULL, it means that something went wrong
+ while parsing the ServerTransportOptions line. */
+ smartlist_t *options_sl =
+ get_options_from_transport_options_line(cl->value, NULL);
+ if (!options_sl)
+ REJECT("ServerTransportOptions did not parse. See logs for details.");
+
+ SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp));
+ smartlist_free(options_sl);
+ }
+
+ return 0;
+}
+
+/** Fetch the active option list, and take server pluggable transport actions
+ * based on it. All of the things we do should survive being done repeatedly.
+ * If present, <b>old_options</b> contains the previous value of the options.
+ *
+ * Return 0 if all goes well, return -1 if it's time to die.
+ *
+ * Note: We haven't moved all the "act on new configuration" logic
+ * into the options_act* functions yet. Some is still in do_hup() and other
+ * places.
+ */
+int
+options_act_server_transport(const or_options_t *old_options)
+{
+ (void)old_options;
+
+ config_line_t *cl;
+ const or_options_t *options = get_options();
+ int running_tor = options->command == CMD_RUN_TOR;
+
+ /* If we are a bridge with a pluggable transport proxy but no
+ Extended ORPort, inform the user that they are missing out. */
+ if (options->ServerTransportPlugin &&
+ !options->ExtORPort_lines) {
+ log_notice(LD_CONFIG, "We use pluggable transports but the Extended "
+ "ORPort is disabled. Tor and your pluggable transports proxy "
+ "communicate with each other via the Extended ORPort so it "
+ "is suggested you enable it: it will also allow your Bridge "
+ "to collect statistics about its clients that use pluggable "
+ "transports. Please enable it using the ExtORPort torrc option "
+ "(e.g. set 'ExtORPort auto').");
+ }
+
+ /* If we have an ExtORPort, initialize its auth cookie. */
+ if (running_tor &&
+ init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
+ log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
+ return -1;
+ }
+
+ if (!options->DisableNetwork) {
+ if (options->ServerTransportPlugin) {
+ for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
+ if (pt_parse_transport_line(options, cl->value, 0, 1) < 0) {
+ // LCOV_EXCL_START
+ log_warn(LD_BUG,
+ "Previously validated ServerTransportPlugin line "
+ "could not be added!");
+ return -1;
+ // LCOV_EXCL_STOP
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/feature/relay/transport_config.h b/src/feature/relay/transport_config.h
new file mode 100644
index 0000000000..6d956d9af1
--- /dev/null
+++ b/src/feature/relay/transport_config.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 2001 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 transport_config.h
+ * @brief Header for feature/relay/transport_config.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_TRANSPORT_CONFIG_H
+#define TOR_FEATURE_RELAY_TRANSPORT_CONFIG_H
+
+#ifdef HAVE_MODULE_RELAY
+
+#include "lib/testsupport/testsupport.h"
+
+struct or_options_t;
+struct smartlist_t;
+
+int options_validate_server_transport(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg);
+
+char *pt_get_bindaddr_from_config(const char *transport);
+struct smartlist_t *pt_get_options_for_server_transport(const char *transport);
+
+int options_act_server_transport(const struct or_options_t *old_options);
+
+#ifdef RELAY_TRANSPORT_CONFIG_PRIVATE
+
+STATIC struct smartlist_t *get_options_from_transport_options_line(
+ const char *line,
+ const char *transport);
+
+#endif /* defined(RELAY_TRANSPORT_CONFIG_PRIVATE) */
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+/** When tor is compiled with the relay module disabled, it can't be
+ * configured with server pluggable transports.
+ *
+ * Returns -1 and sets msg to a newly allocated string, if ExtORPort,
+ * ServerTransportPlugin, ServerTransportListenAddr, or
+ * ServerTransportOptions are set in options. Otherwise returns 0. */
+static inline int
+options_validate_server_transport(const struct or_options_t *old_options,
+ struct or_options_t *options,
+ char **msg)
+{
+ (void)old_options;
+
+ /* These ExtORPort checks are too strict, and will reject valid configs
+ * that disable ports, like "ExtORPort 0". */
+ if (options->ServerTransportPlugin ||
+ options->ServerTransportListenAddr ||
+ options->ServerTransportOptions ||
+ options->ExtORPort_lines) {
+ /* REJECT() this configuration */
+ *msg = tor_strdup("This tor was built with relay mode disabled. "
+ "It can not be configured with an ExtORPort, "
+ "a ServerTransportPlugin, a ServerTransportListenAddr, "
+ "or ServerTransportOptions.");
+ return -1;
+ }
+
+ return 0;
+}
+
+#define pt_get_bindaddr_from_config(transport) \
+ (((void)(transport)),NULL)
+
+/* 31851: called from client/transports.c, but only from server code */
+#define pt_get_options_for_server_transport(transport) \
+ (((void)(transport)),NULL)
+
+#define options_validate_server_transport(old_options, options, msg) \
+ (((void)(old_options)),((void)(options)),((void)(msg)),0)
+#define options_act_server_transport(old_options) \
+ (((void)(old_options)),0)
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
+#endif /* !defined(TOR_FEATURE_RELAY_TRANSPORT_CONFIG_H) */
diff --git a/src/feature/rend/.may_include b/src/feature/rend/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/rend/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/rend/feature_rend.md b/src/feature/rend/feature_rend.md
new file mode 100644
index 0000000000..bfd8ae3dbc
--- /dev/null
+++ b/src/feature/rend/feature_rend.md
@@ -0,0 +1,7 @@
+@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
new file mode 100644
index 0000000000..fb12439a90
--- /dev/null
+++ b/src/feature/rend/include.am
@@ -0,0 +1,22 @@
+
+# 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
+
+# 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
diff --git a/src/feature/rend/rend_authorized_client_st.h b/src/feature/rend/rend_authorized_client_st.h
index 51a1798fcb..c6a6676da9 100644
--- a/src/feature/rend/rend_authorized_client_st.h
+++ b/src/feature/rend/rend_authorized_client_st.h
@@ -1,9 +1,14 @@
/* 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-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
@@ -15,4 +20,3 @@ struct rend_authorized_client_t {
};
#endif /* !defined(REND_AUTHORIZED_CLIENT_ST_H) */
-
diff --git a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h
index bd8a60f0d9..fea91b876a 100644
--- a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h
+++ b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h
@@ -1,9 +1,14 @@
/* 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-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
@@ -14,4 +19,3 @@ struct rend_encoded_v2_service_descriptor_t {
};
#endif /* !defined(REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H) */
-
diff --git a/src/feature/rend/rend_intro_point_st.h b/src/feature/rend/rend_intro_point_st.h
index 4882b62752..4f0aa01523 100644
--- a/src/feature/rend/rend_intro_point_st.h
+++ b/src/feature/rend/rend_intro_point_st.h
@@ -1,9 +1,14 @@
/* 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-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
diff --git a/src/feature/rend/rend_service_descriptor_st.h b/src/feature/rend/rend_service_descriptor_st.h
index ff7627ce96..80c8034f46 100644
--- a/src/feature/rend/rend_service_descriptor_st.h
+++ b/src/feature/rend/rend_service_descriptor_st.h
@@ -1,9 +1,14 @@
/* 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-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
@@ -31,4 +36,3 @@ struct rend_service_descriptor_t {
};
#endif /* !defined(REND_SERVICE_DESCRIPTOR_ST_H) */
-
diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c
index c3f86d8c82..0890a81d8f 100644
--- a/src/feature/rend/rendcache.c
+++ b/src/feature/rend/rendcache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -228,6 +228,17 @@ 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)
@@ -515,9 +526,16 @@ rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
rend_cache_entry_t *entry = NULL;
static const int default_version = 2;
- tor_assert(rend_cache);
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;
diff --git a/src/feature/rend/rendcache.h b/src/feature/rend/rendcache.h
index aec97eabb8..45410610b4 100644
--- a/src/feature/rend/rendcache.h
+++ b/src/feature/rend/rendcache.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -80,6 +80,8 @@ int rend_cache_store_v2_desc_as_client(const char *desc,
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);
diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c
index 2e119d7c99..d33b61851f 100644
--- a/src/feature/rend/rendclient.c
+++ b/src/feature/rend/rendclient.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -261,8 +261,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
> MAX_NICKNAME_LEN)) {
goto perm_err;
}
- strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
- (MAX_NICKNAME_LEN+1)); /* nul pads */
+ 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;
@@ -1048,18 +1048,30 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
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(usable_nodes, rend_intro_point_t *, ip,
- if (ip->timed_out) {
- SMARTLIST_DEL_CURRENT(usable_nodes, ip);
- });
+ 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) {
@@ -1238,3 +1250,66 @@ rend_parse_service_authorization(const or_options_t *options,
}
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
index e5f333238e..b7aa212487 100644
--- a/src/feature/rend/rendclient.h
+++ b/src/feature/rend/rendclient.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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,7 @@
#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);
@@ -47,5 +48,7 @@ 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 0a606a9f02..5d04755819 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/rend/rendcommon.h b/src/feature/rend/rendcommon.h
index f136863c7a..d8281e0578 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c
index 06471b2a7f..a473f0c7e1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -59,7 +59,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request,
pk = crypto_pk_asn1_decode((char*)(request+2), asn1len);
if (!pk) {
reason = END_CIRC_REASON_TORPROTOCOL;
- log_warn(LD_PROTOCOL, "Couldn't decode public key.");
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Couldn't decode public key.");
goto err;
}
@@ -81,7 +81,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request,
(char*)request, 2+asn1len+DIGEST_LEN,
(char*)(request+2+DIGEST_LEN+asn1len),
request_len-(2+DIGEST_LEN+asn1len))<0) {
- log_warn(LD_PROTOCOL,
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Incorrect signature on ESTABLISH_INTRO cell; rejecting.");
reason = END_CIRC_REASON_TORPROTOCOL;
goto err;
@@ -162,9 +162,9 @@ rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request,
if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+
DH1024_KEY_LEN+CIPHER_KEY_LEN+
PKCS1_OAEP_PADDING_OVERHEAD)) {
- log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %u; "
- "responding with nack.",
- (unsigned)circ->p_circ_id);
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Impossibly short INTRODUCE1 cell on circuit %u; "
+ "responding with nack.", (unsigned)circ->p_circ_id);
goto err;
}
@@ -258,7 +258,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
}
if (circ->base_.n_chan) {
- log_warn(LD_PROTOCOL,
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Tried to establish rendezvous on non-edge circuit");
goto err;
}
@@ -270,8 +270,8 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
}
if (hs_circuitmap_get_rend_circ_relay_side(request)) {
- log_warn(LD_PROTOCOL,
- "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS.");
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS.");
goto err;
}
@@ -313,9 +313,9 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
int reason = END_CIRC_REASON_INTERNAL;
if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
- log_info(LD_REND,
- "Tried to complete rendezvous on non-OR or non-edge circuit %u.",
- (unsigned)circ->p_circ_id);
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Tried to complete rendezvous on non-OR or non-edge circuit %u.",
+ (unsigned)circ->p_circ_id);
reason = END_CIRC_REASON_TORPROTOCOL;
goto err;
}
diff --git a/src/feature/rend/rendmid.h b/src/feature/rend/rendmid.h
index 8ae1fa16b8..789596d855 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c
index a98cb3ad88..0979d767a7 100644
--- a/src/feature/rend/rendparse.c
+++ b/src/feature/rend/rendparse.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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/rend/rendparse.h b/src/feature/rend/rendparse.h
index b1ccce9b6c..75109c204d 100644
--- a/src/feature/rend/rendparse.h
+++ b/src/feature/rend/rendparse.h
@@ -1,12 +1,12 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file rend_parse.h
- * \brief Header file for rend_parse.c.
+ * \file rendparse.h
+ * \brief Header file for rendparse.c.
**/
#ifndef TOR_REND_PARSE_H
diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c
index e0cf06b9df..83388a72eb 100644
--- a/src/feature/rend/rendservice.c
+++ b/src/feature/rend/rendservice.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -49,6 +49,7 @@
#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"
@@ -131,6 +132,22 @@ static smartlist_t *rend_service_list = NULL;
* 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)
@@ -714,24 +731,25 @@ service_config_shadow_copy(rend_service_t *service,
config->ports = NULL;
}
-/* Parse the hidden service configuration starting at <b>line_</b> using the
+/* 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 config_line_t *line_,
+rend_config_service(const hs_opts_t *hs_opts,
const or_options_t *options,
hs_service_config_t *config)
{
- const config_line_t *line;
rend_service_t *service = NULL;
- /* line_ can be NULL which would mean that the service configuration only
- * have one line that is the directory directive. */
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) {
@@ -746,126 +764,109 @@ rend_config_service(const config_line_t *line_,
* options, we'll copy over the useful data to the rend_service_t object. */
service_config_shadow_copy(service, config);
- for (line = line_; line; line = line->next) {
- if (!strcasecmp(line->key, "HiddenServiceDir")) {
- /* We just hit the next hidden service, stop right now. */
- break;
+ /* 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;
}
- /* Number of introduction points. */
- if (!strcasecmp(line->key, "HiddenServiceNumIntroductionPoints")) {
- int ok = 0;
- /* Those are specific defaults for version 2. */
- service->n_intro_points_wanted =
- (unsigned int) tor_parse_long(line->value, 10,
- 0, NUM_INTRO_POINTS_MAX, &ok, NULL);
- if (!ok) {
- log_warn(LD_CONFIG,
- "HiddenServiceNumIntroductionPoints "
- "should be between %d and %d, not %s",
- 0, NUM_INTRO_POINTS_MAX, line->value);
- goto err;
- }
- log_info(LD_CONFIG, "HiddenServiceNumIntroductionPoints=%d for %s",
- service->n_intro_points_wanted, escaped(service->directory));
- continue;
+ 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;
}
- if (!strcasecmp(line->key, "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;
- if (service->auth_type != REND_NO_AUTH) {
- log_warn(LD_CONFIG, "Got multiple HiddenServiceAuthorizeClient "
- "lines for a single service.");
- goto err;
- }
- type_names_split = smartlist_new();
- smartlist_split_string(type_names_split, line->value, " ", 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);
- continue;
- }
- clients = smartlist_new();
- smartlist_split_string(clients, smartlist_get(type_names_split, 1),
- ",", SPLIT_SKIP_SPACE, 0);
+ 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);
- /* 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);
+ 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_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");
+ }
+ 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;
}
- continue;
+ 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. */
@@ -3733,20 +3734,23 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
base32_encode(desc_id_base32, sizeof(desc_id_base32),
desc->desc_id, DIGEST_LEN);
hs_dir_ip = tor_dup_ip(hs_dir->addr);
- 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->or_port);
+ 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->or_port);
+ tor_free(hs_dir_ip);
+ }
+
control_event_hs_descriptor_upload(service_id,
hs_dir->identity_digest,
desc_id_base32, NULL);
- tor_free(hs_dir_ip);
/* Remember successful upload to this router for next time. */
if (!smartlist_contains_digest(successful_uploads,
hs_dir->identity_digest))
@@ -4369,17 +4373,16 @@ rend_consider_descriptor_republication(void)
void
rend_service_dump_stats(int severity)
{
- int i,j;
rend_service_t *service;
rend_intro_point_t *intro;
const char *safe_name;
origin_circuit_t *circ;
- for (i=0; i < smartlist_len(rend_service_list); ++i) {
+ 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 (j=0; j < smartlist_len(service->intro_nodes); ++j) {
+ 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);
diff --git a/src/feature/rend/rendservice.h b/src/feature/rend/rendservice.h
index a8eb28bee2..012afc0f9f 100644
--- a/src/feature/rend/rendservice.h
+++ b/src/feature/rend/rendservice.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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -139,7 +139,8 @@ STATIC void rend_service_prune_list_impl_(void);
#endif /* defined(RENDSERVICE_PRIVATE) */
int rend_num_services(void);
-int rend_config_service(const struct config_line_t *line_,
+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);
diff --git a/src/feature/stats/.may_include b/src/feature/stats/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/stats/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/stats/feature_stats.md b/src/feature/stats/feature_stats.md
new file mode 100644
index 0000000000..d205fe5571
--- /dev/null
+++ b/src/feature/stats/feature_stats.md
@@ -0,0 +1,10 @@
+@dir /feature/stats
+@brief feature/stats: Relay statistics. Also, port prediction.
+
+This module collects anonymized relay statistics in order to publish them in
+relays' routerinfo and extrainfo documents.
+
+Additionally, it contains predict_ports.c, which remembers which ports we've
+visited recently as a client, so we can make sure we have open circuits that
+support them.
+
diff --git a/src/feature/stats/geoip_stats.c b/src/feature/stats/geoip_stats.c
index 6fb21f4f79..f9a2f19d2e 100644
--- a/src/feature/stats/geoip_stats.c
+++ b/src/feature/stats/geoip_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -146,9 +146,9 @@ clientmap_entries_eq(const clientmap_entry_t *a, const clientmap_entry_t *b)
}
HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
- clientmap_entries_eq)
+ clientmap_entries_eq);
HT_GENERATE2(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
- clientmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+ clientmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
#define clientmap_entry_free(ent) \
FREE_AND_NULL(clientmap_entry_t, clientmap_entry_free_, ent)
@@ -484,9 +484,9 @@ dirreq_map_ent_hash(const dirreq_map_entry_t *entry)
}
HT_PROTOTYPE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
- dirreq_map_ent_eq)
+ dirreq_map_ent_eq);
HT_GENERATE2(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
- dirreq_map_ent_eq, 0.6, tor_reallocarray_, tor_free_)
+ dirreq_map_ent_eq, 0.6, tor_reallocarray_, tor_free_);
/** Helper: Put <b>entry</b> into map of directory requests using
* <b>type</b> and <b>dirreq_id</b> as key parts. If there is
diff --git a/src/feature/stats/geoip_stats.h b/src/feature/stats/geoip_stats.h
index 2fc62b5466..fcfe7a31f0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,7 @@
#define TOR_GEOIP_STATS_H
#include "core/or/dos.h"
+#include "ext/ht.h"
/** Indicates an action that we might be noting geoip statistics on.
* Note that if we're noticing CONNECT, we're a bridge, and if we're noticing
diff --git a/src/feature/stats/include.am b/src/feature/stats/include.am
new file mode 100644
index 0000000000..8789bc3d96
--- /dev/null
+++ b/src/feature/stats/include.am
@@ -0,0 +1,12 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/stats/geoip_stats.c \
+ src/feature/stats/rephist.c \
+ src/feature/stats/predict_ports.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/stats/geoip_stats.h \
+ src/feature/stats/rephist.h \
+ src/feature/stats/predict_ports.h
diff --git a/src/feature/stats/predict_ports.c b/src/feature/stats/predict_ports.c
index 3cbba2c831..d728f106a2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/stats/predict_ports.h b/src/feature/stats/predict_ports.h
index 45b206c23a..ed067b6ced 100644
--- a/src/feature/stats/predict_ports.h
+++ b/src/feature/stats/predict_ports.h
@@ -1,11 +1,11 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file predict_portst.h
+ * \file predict_ports.h
* \brief Header file for predict_ports.c.
**/
diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c
index 3f560fbce7..71e2e00086 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -1122,7 +1122,7 @@ static bw_array_t *dir_read_array = NULL;
directory protocol. */
static bw_array_t *dir_write_array = NULL;
-/** Set up [dir-]read_array and [dir-]write_array, freeing them if they
+/** Set up [dir_]read_array and [dir_]write_array, freeing them if they
* already exist. */
static void
bw_arrays_init(void)
@@ -2285,9 +2285,9 @@ bidi_map_ent_hash(const bidi_map_entry_t *entry)
}
HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
- bidi_map_ent_eq)
+ bidi_map_ent_eq);
HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
- bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_)
+ bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_);
/* DOCDOC bidi_map_free */
static void
diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h
index 0d72946382..92c3d2a5a5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/include.am b/src/include.am
index 065bdc31cb..657f6e823a 100644
--- a/src/include.am
+++ b/src/include.am
@@ -1,4 +1,5 @@
include src/ext/include.am
+
include src/lib/arch/include.am
include src/lib/buf/include.am
include src/lib/err/include.am
@@ -18,6 +19,7 @@ include src/lib/fs/include.am
include src/lib/geoip/include.am
include src/lib/include.libdonna.am
include src/lib/intmath/include.am
+include src/lib/llharden/include.am
include src/lib/lock/include.am
include src/lib/log/include.am
include src/lib/math/include.am
@@ -42,6 +44,42 @@ include src/lib/version/include.am
include src/lib/wallclock/include.am
include src/trunnel/include.am
+noinst_LIBRARIES += src/core/libtor-app.a
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/core/libtor-app-testing.a
+endif
+
+LIBTOR_APP_A_SOURCES =
+#
+# Sources that we only add for the real libtor_a, and not for testing.
+#
+LIBTOR_APP_A_STUB_SOURCES =
+
+include src/core/crypto/include.am
+include src/core/mainloop/include.am
+include src/core/or/include.am
+include src/core/proto/include.am
+
+include src/feature/api/include.am
+include src/feature/client/include.am
+include src/feature/control/include.am
+include src/feature/dirauth/include.am
+include src/feature/dircache/include.am
+include src/feature/dirclient/include.am
+include src/feature/dircommon/include.am
+include src/feature/dirparse/include.am
+include src/feature/hibernate/include.am
+include src/feature/hs_common/include.am
+include src/feature/hs/include.am
+include src/feature/keymgt/include.am
+include src/feature/nodelist/include.am
+include src/feature/relay/include.am
+include src/feature/rend/include.am
+include src/feature/stats/include.am
+
+include src/app/config/include.am
+include src/app/main/include.am
+
include src/core/include.am
include src/app/include.am
diff --git a/src/lib/arch/bytes.h b/src/lib/arch/bytes.h
index 4756ca2beb..c72ac3eb8e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_BYTES_H
@@ -16,12 +16,17 @@
#include <string.h>
#include "lib/cc/torint.h"
-/* The uint8 variants are defined to make the code more uniform. */
+/**
+ * Read an 8-bit from <b>cp</b>.
+ */
static inline uint8_t
get_uint8(const void *cp)
{
return *(const uint8_t*)(cp);
}
+/**
+ * Store an 8-bit value from <b>v</b> to <b>cp</b>.
+ */
static inline void
set_uint8(void *cp, uint8_t v)
{
@@ -93,7 +98,7 @@ set_uint64(void *cp, uint64_t v)
memcpy(cp,&v,8);
}
-#ifdef WORDS_BIGENDIAN
+#if defined(WORDS_BIGENDIAN)
static inline uint16_t
tor_htons(uint32_t a)
{
@@ -130,6 +135,9 @@ tor_ntohll(uint64_t a)
return a;
}
#else /* !defined(WORDS_BIGENDIAN) */
+/**
+ * Convert a 16-bit value from host order to network order (big-endian).
+ **/
static inline uint16_t
tor_htons(uint16_t a)
{
@@ -139,12 +147,18 @@ tor_htons(uint16_t a)
((a & 0xff00) >> 8);
}
+/**
+ * Convert a 16-bit value from network order (big-endian) to host order.
+ **/
static inline uint16_t
tor_ntohs(uint16_t a)
{
return tor_htons(a);
}
+/**
+ * Convert a 32-bit value from host order to network order (big-endian).
+ **/
static inline uint32_t
tor_htonl(uint32_t a)
{
@@ -156,6 +170,9 @@ tor_htonl(uint32_t a)
((a & 0xff000000) >>24);
}
+/**
+ * Convert a 32-bit value from network order (big-endian) to host order.
+ **/
static inline uint32_t
tor_ntohl(uint32_t a)
{
diff --git a/src/lib/arch/lib_arch.md b/src/lib/arch/lib_arch.md
new file mode 100644
index 0000000000..9b8bccdf16
--- /dev/null
+++ b/src/lib/arch/lib_arch.md
@@ -0,0 +1,2 @@
+@dir /lib/arch
+@brief lib/arch: Compatibility code for handling different CPU architectures.
diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c
index ace5bdc4a4..a5031a47a6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -99,6 +99,7 @@
#define DBG_S(s) (void)0
#endif
+#ifndef COCCI
#ifdef DISABLE_MEMORY_SENTINELS
#define CHUNK_SET_SENTINEL(chunk, alloclen) STMT_NIL
#else
@@ -109,6 +110,7 @@
memset(a,0,SENTINEL_LEN); \
} while (0)
#endif /* defined(DISABLE_MEMORY_SENTINELS) */
+#endif /* !defined(COCCI) */
/** Move all bytes stored in <b>chunk</b> to the front of <b>chunk</b>->mem,
* to free up space at the end. */
@@ -283,7 +285,7 @@ buf_t *
buf_new_with_data(const char *cp, size_t sz)
{
/* Validate arguments */
- if (!cp || sz <= 0 || sz >= INT_MAX) {
+ if (!cp || sz <= 0 || sz > BUF_MAX_LEN) {
return NULL;
}
@@ -528,9 +530,9 @@ buf_add(buf_t *buf, const char *string, size_t string_len)
return (int)buf->datalen;
check();
- if (BUG(buf->datalen >= INT_MAX))
+ if (BUG(buf->datalen > BUF_MAX_LEN))
return -1;
- if (BUG(buf->datalen >= INT_MAX - string_len))
+ if (BUG(buf->datalen > BUF_MAX_LEN - string_len))
return -1;
while (string_len) {
@@ -549,7 +551,7 @@ buf_add(buf_t *buf, const char *string, size_t string_len)
}
check();
- tor_assert(buf->datalen < INT_MAX);
+ tor_assert(buf->datalen <= BUF_MAX_LEN);
return (int)buf->datalen;
}
@@ -578,6 +580,7 @@ buf_add_vprintf(buf_t *buf, const char *format, va_list args)
/* XXXX Faster implementations are easy enough, but let's optimize later */
char *tmp;
tor_vasprintf(&tmp, format, args);
+ tor_assert(tmp != NULL);
buf_add(buf, tmp, strlen(tmp));
tor_free(tmp);
}
@@ -642,7 +645,7 @@ buf_get_bytes(buf_t *buf, char *string, size_t string_len)
buf_peek(buf, string, string_len);
buf_drain(buf, string_len);
check();
- tor_assert(buf->datalen < INT_MAX);
+ tor_assert(buf->datalen <= BUF_MAX_LEN);
return (int)buf->datalen;
}
@@ -657,9 +660,9 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
char b[4096];
size_t cp, len;
- if (BUG(buf_out->datalen >= INT_MAX || *buf_flushlen >= INT_MAX))
+ if (BUG(buf_out->datalen > BUF_MAX_LEN || *buf_flushlen > BUF_MAX_LEN))
return -1;
- if (BUG(buf_out->datalen >= INT_MAX - *buf_flushlen))
+ if (BUG(buf_out->datalen > BUF_MAX_LEN - *buf_flushlen))
return -1;
len = *buf_flushlen;
@@ -667,7 +670,7 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
len = buf_in->datalen;
cp = len; /* Remember the number of bytes we intend to copy. */
- tor_assert(cp < INT_MAX);
+ tor_assert(cp <= BUF_MAX_LEN);
while (len) {
/* This isn't the most efficient implementation one could imagine, since
* it does two copies instead of 1, but I kinda doubt that this will be
@@ -691,9 +694,9 @@ buf_move_all(buf_t *buf_out, buf_t *buf_in)
return;
if (buf_datalen(buf_in) == 0)
return;
- if (BUG(buf_out->datalen >= INT_MAX || buf_in->datalen >= INT_MAX))
+ if (BUG(buf_out->datalen > BUF_MAX_LEN || buf_in->datalen > BUF_MAX_LEN))
return;
- if (BUG(buf_out->datalen >= INT_MAX - buf_in->datalen))
+ if (BUG(buf_out->datalen > BUF_MAX_LEN - buf_in->datalen))
return;
if (buf_out->head == NULL) {
@@ -747,7 +750,7 @@ buf_find_pos_of_char(char ch, buf_pos_t *out)
char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos);
if (cp) {
out->chunk = chunk;
- tor_assert(cp - chunk->data < INT_MAX);
+ tor_assert(cp - chunk->data <= BUF_MAX_LEN);
out->pos = (int)(cp - chunk->data);
return out->chunk_pos + out->pos;
} else {
@@ -763,7 +766,7 @@ buf_find_pos_of_char(char ch, buf_pos_t *out)
static inline int
buf_pos_inc(buf_pos_t *pos)
{
- tor_assert(pos->pos < INT_MAX - 1);
+ tor_assert(pos->pos < BUF_MAX_LEN);
++pos->pos;
if (pos->pos == (ptrdiff_t)pos->chunk->datalen) {
if (!pos->chunk->next)
@@ -810,7 +813,7 @@ buf_find_string_offset(const buf_t *buf, const char *s, size_t n)
buf_pos_init(buf, &pos);
while (buf_find_pos_of_char(*s, &pos) >= 0) {
if (buf_matches_at_pos(&pos, s, n)) {
- tor_assert(pos.chunk_pos + pos.pos < INT_MAX);
+ tor_assert(pos.chunk_pos + pos.pos <= BUF_MAX_LEN);
return (int)(pos.chunk_pos + pos.pos);
} else {
if (buf_pos_inc(&pos)<0)
@@ -844,7 +847,7 @@ buf_find_offset_of_char(buf_t *buf, char ch)
{
chunk_t *chunk;
ptrdiff_t offset = 0;
- tor_assert(buf->datalen < INT_MAX);
+ tor_assert(buf->datalen <= BUF_MAX_LEN);
for (chunk = buf->head; chunk; chunk = chunk->next) {
char *cp = memchr(chunk->data, ch, chunk->datalen);
if (cp)
@@ -914,7 +917,7 @@ buf_assert_ok(buf_t *buf)
for (ch = buf->head; ch; ch = ch->next) {
total += ch->datalen;
tor_assert(ch->datalen <= ch->memlen);
- tor_assert(ch->datalen < INT_MAX);
+ tor_assert(ch->datalen <= BUF_MAX_LEN);
tor_assert(ch->data >= &ch->mem[0]);
tor_assert(ch->data <= &ch->mem[0]+ch->memlen);
if (ch->data == &ch->mem[0]+ch->memlen) {
diff --git a/src/lib/buf/buffers.h b/src/lib/buf/buffers.h
index c103b93a82..d8a77feb72 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,6 +29,9 @@ void buf_free_(buf_t *buf);
void buf_clear(buf_t *buf);
buf_t *buf_copy(const buf_t *buf);
+/** Maximum bytes in a buffer, inclusive. */
+#define BUF_MAX_LEN (INT_MAX - 1)
+
MOCK_DECL(size_t, buf_datalen, (const buf_t *buf));
size_t buf_allocation(const buf_t *buf);
size_t buf_slack(const buf_t *buf);
diff --git a/src/lib/buf/lib_buf.md b/src/lib/buf/lib_buf.md
new file mode 100644
index 0000000000..519ab50a2d
--- /dev/null
+++ b/src/lib/buf/lib_buf.md
@@ -0,0 +1,13 @@
+@dir /lib/buf
+@brief lib/buf: An efficient byte queue.
+
+This module defines the buf_t type, which is used throughout our networking
+code. The implementation is a singly-linked queue of buffer chunks, similar
+to the BSD kernel's
+["mbuf"](https://www.freebsd.org/cgi/man.cgi?query=mbuf&sektion=9) structure.
+
+The buf_t type is also reasonable for use in constructing long strings.
+
+See \refdir{lib/net} for networking code that uses buf_t, and
+\refdir{lib/tls} for cryptographic code that uses buf_t.
+
diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h
index d9ccabb2b3..96aa912652 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,11 +25,11 @@
#endif /* defined(__has_feature) */
#ifndef NULL_REP_IS_ZERO_BYTES
-#error "It seems your platform does not represent NULL as zero. We can't cope."
+#error "Your platform does not represent NULL as zero. We can't cope."
#endif
#ifndef DOUBLE_0_REP_IS_ZERO_BYTES
-#error "It seems your platform does not represent 0.0 as zeros. We can't cope."
+#error "Your platform does not represent 0.0 as zeros. We can't cope."
#endif
#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32
@@ -65,8 +65,6 @@
/* Temporarily enable and disable warnings. */
#ifdef __GNUC__
-# define PRAGMA_STRINGIFY_(s) #s
-# define PRAGMA_JOIN_STRINGIFY_(a,b) PRAGMA_STRINGIFY_(a ## b)
/* Support for macro-generated pragmas (c99) */
# define PRAGMA_(x) _Pragma (#x)
# ifdef __clang__
@@ -78,15 +76,15 @@
/* we have push/pop support */
# define DISABLE_GCC_WARNING(warningopt) \
PRAGMA_DIAGNOSTIC_(push) \
- PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt))
+ PRAGMA_DIAGNOSTIC_(ignored warningopt)
# define ENABLE_GCC_WARNING(warningopt) \
PRAGMA_DIAGNOSTIC_(pop)
#else /* !(defined(__clang__) || GCC_VERSION >= 406) */
/* older version of gcc: no push/pop support. */
# define DISABLE_GCC_WARNING(warningopt) \
- PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt))
+ PRAGMA_DIAGNOSTIC_(ignored warningopt)
# define ENABLE_GCC_WARNING(warningopt) \
- PRAGMA_DIAGNOSTIC_(warning PRAGMA_JOIN_STRINGIFY_(-W,warningopt))
+ PRAGMA_DIAGNOSTIC_(warning warningopt)
#endif /* defined(__clang__) || GCC_VERSION >= 406 */
#else /* !defined(__GNUC__) */
/* not gcc at all */
@@ -200,8 +198,8 @@
/** Macro: yield a pointer to the field at position <b>off</b> within the
* structure <b>st</b>. Example:
* <pre>
- * struct a { int foo; int bar; } x;
- * ptrdiff_t bar_offset = offsetof(struct a, bar);
+ * struct a_t { int foo; int bar; } x;
+ * ptrdiff_t bar_offset = offsetof(struct a_t, bar);
* int *bar_p = STRUCT_VAR_P(&x, bar_offset);
* *bar_p = 3;
* </pre>
@@ -211,10 +209,10 @@
/** Macro: yield a pointer to an enclosing structure given a pointer to
* a substructure at offset <b>off</b>. Example:
* <pre>
- * struct base { ... };
- * struct subtype { int x; struct base b; } x;
- * struct base *bp = &x.base;
- * struct *sp = SUBTYPE_P(bp, struct subtype, b);
+ * struct base_t { ... };
+ * struct subtype_t { int x; struct base_t b; } x;
+ * struct base_t *bp = &x.base;
+ * struct *sp = SUBTYPE_P(bp, struct subtype_t, b);
* </pre>
*/
#define SUBTYPE_P(p, subtype, basemember) \
@@ -235,4 +233,17 @@
#define EAT_SEMICOLON \
struct dummy_semicolon_eater__
+/**
+ * Tell our static analysis tool to believe that (clang's scan-build or
+ * coverity scan) that an expression might be true. We use this to suppress
+ * dead-code warnings.
+ **/
+#if defined(__COVERITY__) || defined(__clang_analyzer__)
+/* By calling getenv, we force the analyzer not to conclude that 'expr' is
+ * false. */
+#define POSSIBLE(expr) ((expr) || getenv("STATIC_ANALYZER_DEADCODE_DUMMY_"))
+#else
+#define POSSIBLE(expr) (expr)
+#endif /* defined(__COVERITY__) || defined(__clang_analyzer__) */
+
#endif /* !defined(TOR_COMPAT_COMPILER_H) */
diff --git a/src/lib/cc/ctassert.h b/src/lib/cc/ctassert.h
index bedf0b83a6..d9d3aa40b0 100644
--- a/src/lib/cc/ctassert.h
+++ b/src/lib/cc/ctassert.h
@@ -46,7 +46,7 @@
#define CTASSERT_EXPN(x, a, b) CTASSERT_DECL(x, a, b)
#define CTASSERT_DECL(x, a, b) \
- typedef char tor_ctassert_##a##_##b[(x) ? 1 : -1] ATTR_UNUSED
+ typedef char tor_ctassert_##a##_##b[(x) ? 1 : -1] ATTR_UNUSED; EAT_SEMICOLON
#endif /* __STDC_VERSION__ >= 201112L */
diff --git a/src/lib/cc/include.am b/src/lib/cc/include.am
index 1aa722dd82..d2a415e956 100644
--- a/src/lib/cc/include.am
+++ b/src/lib/cc/include.am
@@ -3,4 +3,5 @@
noinst_HEADERS += \
src/lib/cc/compat_compiler.h \
src/lib/cc/ctassert.h \
+ src/lib/cc/tokpaste.h \
src/lib/cc/torint.h
diff --git a/src/lib/cc/lib_cc.md b/src/lib/cc/lib_cc.md
new file mode 100644
index 0000000000..bd49005ba2
--- /dev/null
+++ b/src/lib/cc/lib_cc.md
@@ -0,0 +1,2 @@
+@dir /lib/cc
+@brief lib/cc: Macros for managing the C compiler and language.
diff --git a/src/lib/cc/tokpaste.h b/src/lib/cc/tokpaste.h
new file mode 100644
index 0000000000..068621b5bd
--- /dev/null
+++ b/src/lib/cc/tokpaste.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2001 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 tokpaste.h
+ * @brief Token-pasting macros.
+ **/
+
+#ifndef TOR_LIB_CC_TOKPASTE_H
+#define TOR_LIB_CC_TOKPASTE_H
+
+/**
+ * Concatenate `a` and `b` in a way that allows their result itself to be
+ * expanded by the preprocessor.
+ *
+ * Ordinarily you could just say `a ## b` in a macro definition. But doing so
+ * results in a symbol which the preprocessor will not then expand. If you
+ * wanted to use `a ## b` to create the name of a macro and have the
+ * preprocessor expand _that_ macro, you need to have another level of
+ * indirection, as this macro provides.
+ **/
+#define PASTE(a,b) PASTE__(a,b)
+
+/** Helper for PASTE(). */
+#define PASTE__(a,b) a ## b
+
+#endif /* !defined(TOR_LIB_CC_TOKPASTE_H) */
diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h
index 94b79d30a1..af7a90431c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -49,7 +49,7 @@ typedef int32_t ssize_t;
* aren't 2's complement, and you don't define LONG_MAX, then you're so
* bizarre that I want nothing to do with you. */
#ifndef USING_TWOS_COMPLEMENT
-#error "Seems that your platform doesn't use 2's complement arithmetic. Argh."
+#error "Your platform doesn't use 2's complement arithmetic."
#endif
#ifndef TIME_MAX
@@ -126,12 +126,11 @@ typedef int32_t ssize_t;
#define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16))
#if SIZEOF_INT > SIZEOF_VOID_P
-#error "sizeof(int) > sizeof(void *) - Tor cannot be built on this platform!"
+#error "sizeof(int) > sizeof(void *) - Can't build Tor here."
#endif
#if SIZEOF_UNSIGNED_INT > SIZEOF_VOID_P
-#error "sizeof(unsigned int) > sizeof(void *) - Tor cannot be built on this \
-platform!"
+#error "sizeof(unsigned int) > sizeof(void *) - Can't build Tor here."
#endif
#endif /* !defined(TOR_TORINT_H) */
diff --git a/src/lib/compress/compress.c b/src/lib/compress/compress.c
index 51591410a2..7ce3910d84 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -694,7 +694,8 @@ subsys_compress_initialize(void)
const subsys_fns_t sys_compress = {
.name = "compress",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
- .level = -70,
+ .level = -55,
.initialize = subsys_compress_initialize,
};
diff --git a/src/lib/compress/compress.h b/src/lib/compress/compress.h
index 8cea4ead60..f36cdb82aa 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 2e704466f2..d1941c9da6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 915f4949ae..8884b020e8 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 556ab437dc..de03cda91c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 0b5760773a..43c021c788 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 2bb9c3d66c..df696a11aa 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 6181072315..dce0549924 100644
--- a/src/lib/compress/compress_sys.h
+++ b/src/lib/compress/compress_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 df0d1bff5f..3711e46222 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e4f248cd9b..7328ce899b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 9076665295..5913d823e1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,11 +29,11 @@
#ifdef HAVE_ZSTD
#ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE
-DISABLE_GCC_WARNING(unused-const-variable)
+DISABLE_GCC_WARNING("-Wunused-const-variable")
#endif
#include <zstd.h>
#ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE
-ENABLE_GCC_WARNING(unused-const-variable)
+ENABLE_GCC_WARNING("-Wunused-const-variable")
#endif
#endif /* defined(HAVE_ZSTD) */
diff --git a/src/lib/compress/compress_zstd.h b/src/lib/compress/compress_zstd.h
index 47f950b9e0..0fc71db749 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/lib_compress.md b/src/lib/compress/lib_compress.md
new file mode 100644
index 0000000000..c43f223fe7
--- /dev/null
+++ b/src/lib/compress/lib_compress.md
@@ -0,0 +1,6 @@
+@dir /lib/compress
+@brief lib/compress: Wraps several compression libraries
+
+Currently supported are zlib (mandatory), zstd (optional), and lzma
+(optional).
+
diff --git a/src/lib/conf/confdecl.h b/src/lib/conf/confdecl.h
new file mode 100644
index 0000000000..c2d3fb335d
--- /dev/null
+++ b/src/lib/conf/confdecl.h
@@ -0,0 +1,221 @@
+/* Copyright (c) 2001 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 confdecl.h
+ * @brief Macros for generating a configuration struct from a list
+ * of its individual fields.
+ *
+ * This header defines three important macros: BEGIN_CONF_STRUCT(),
+ * END_CONF_STRUCT(), and CONF_VAR(). They're meant to be used together to
+ * define a configuration structure and the means for encoding and decoding
+ * it.
+ *
+ * To use them, make a new header with a name like `MOD_options.inc`. Start
+ * it with a BEGIN_CONF_STRUCT(), then define your variables with CONF_VAR(),
+ * then end the header with END_CONF_STRUCT(), as in:
+ *
+ * BEGIN_CONF_STRUCT(module_options_t)
+ * CONF_VAR(ModuleIsActive, BOOLEAN, 0, "1")
+ * END_CONF_STRUCT(module_options_t)
+ *
+ * Once you've done that, you can use that header to define a configuration
+ * structure by saying:
+ *
+ * typedef struct module_options_t module_options_t;
+ * #define CONF_CONTEXT STRUCT
+ * #include "MOD_options.inc"
+ * #undef CONF_CONTEXT
+ *
+ * And you can define your field definition table by saying:
+ *
+ * #define CONF_CONTEXT TABLE
+ * #include "MOD_options.inc"
+ * #undef CONF_CONTEXT
+ *
+ * The two above snippets will define a structure called `module_options_t`
+ * with appropriate members, and a table of config_var_t objects called
+ * `module_options_t_vars[]`.
+ *
+ * For lower-level modules, you can say <tt>\#define CONF_TABLE LL_TABLE</tt>,
+ * and get a table definition suitable for use in modules that are at a lower
+ * level than lib/confmgt. Note that the types for these tables cannot
+ * include any extended types.
+ **/
+
+#ifndef TOR_LIB_CONF_CONFDECL_H
+#define TOR_LIB_CONF_CONFDECL_H
+
+#undef CONF_CONTEXT
+#include "lib/cc/tokpaste.h"
+#include "lib/cc/torint.h"
+
+/**
+ * Begin the definition of a configuration object called `name`.
+ **/
+#define BEGIN_CONF_STRUCT(name) \
+ PASTE(BEGIN_CONF_STRUCT__, CONF_CONTEXT)(name)
+/**
+ * End the definition of a configuration object called `name`.
+ **/
+#define END_CONF_STRUCT(name) \
+ PASTE(END_CONF_STRUCT__, CONF_CONTEXT)(name)
+/**
+ * Declare a single configuration field with name `varname`, type `vartype`,
+ * flags `varflags`, and initial value `initval`.
+ **/
+#define CONF_VAR(varname, vartype, varflags, initval) \
+ PASTE(CONF_VAR__, CONF_CONTEXT)(varname, vartype, varflags, initval)
+
+#ifndef COCCI
+/**
+ * @defgroup STRUCT_MACROS Internal macros: struct definitions.
+ * Implementation helpers: the regular confdecl macros expand to these
+ * when CONF_CONTEXT is defined to STRUCT. Don't use them directly.
+ * @{*/
+#define BEGIN_CONF_STRUCT__STRUCT(name) \
+ struct name { \
+ uint32_t magic;
+#define END_CONF_STRUCT__STRUCT(name) \
+ };
+#define CONF_VAR__STRUCT(varname, vartype, varflags, initval) \
+ config_decl_ ## vartype varname;
+/** @} */
+
+/**
+ * @defgroup TABLE_MACROS Internal macros: table definitions.
+ * Implementation helpers: the regular confdecl macros expand to these
+ * when CONF_CONTEXT is defined to TABLE. Don't use them directly.
+ * @{*/
+#define BEGIN_CONF_STRUCT__TABLE(structname) \
+ /* We use this typedef so we can refer to the config type */ \
+ /* without having its name as a macro argument to CONF_VAR. */ \
+ typedef struct structname config_var_reference__obj; \
+ static const config_var_t structname##_vars[] = {
+#define END_CONF_STRUCT__TABLE(structname) \
+ { .member = { .name = NULL } } \
+ };
+#define CONF_VAR__TABLE(varname, vartype, varflags, initval) \
+ { \
+ .member = \
+ { .name = #varname, \
+ .type = CONFIG_TYPE_EXTENDED, \
+ .type_def = &vartype ## _type_defn, \
+ .offset=offsetof(config_var_reference__obj, varname), \
+ }, \
+ .flags = varflags, \
+ .initvalue = initval \
+ },
+/**@}*/
+
+/**
+ * @defgroup LL_TABLE_MACROS Internal macros: low-level table definitions.
+ * Implementation helpers: the regular confdecl macros expand to these
+ * when CONF_CONTEXT is defined to LL_TABLE. Don't use them directly.
+ * @{*/
+#define BEGIN_CONF_STRUCT__LL_TABLE(structname) \
+ /* We use this typedef so we can refer to the config type */ \
+ /* without having its name as a macro argument to CONF_VAR. */ \
+ typedef struct structname config_var_reference__obj; \
+ static const config_var_t structname##_vars[] = {
+#define END_CONF_STRUCT__LL_TABLE(structname) \
+ { .member = { .name = NULL } } \
+ };
+#define CONF_VAR__LL_TABLE(varname, vartype, varflags, initval) \
+ { \
+ .member = \
+ { .name = #varname, \
+ .type = CONFIG_TYPE_ ## vartype, \
+ .offset=offsetof(config_var_reference__obj, varname), \
+ }, \
+ .flags = varflags, \
+ .initvalue = initval \
+ },
+/**@}*/
+
+/** @defgroup STUB_TABLE_MACROS Internal macros: stub table declarations,
+ * for use when a module is disabled.
+ * Implementation helpers: the regular confdecl macros expand to these
+ * when CONF_CONTEXT is defined to LL_TABLE. Don't use them directly.
+ * @{ */
+#define BEGIN_CONF_STRUCT__STUB_TABLE(structname) \
+ static const config_var_t structname##_vars[] = {
+#define END_CONF_STRUCT__STUB_TABLE(structname) \
+ { .member = { .name = NULL } } \
+ };
+#define CONF_VAR__STUB_TABLE(varname, vartype, varflags, initval) \
+ { \
+ .member = \
+ { .name = #varname, \
+ .type = CONFIG_TYPE_IGNORE, \
+ .offset = -1, \
+ }, \
+ .flags = CFLG_GROUP_DISABLED, \
+ },
+/**@}*/
+
+#endif /* !defined(COCCI) */
+
+/** Type aliases for the "commonly used" configuration types.
+ *
+ * Defining them in this way allows our CONF_VAR__STRUCT() macro to declare
+ * structure members corresponding to the configuration types. For example,
+ * when the macro sees us declare a configuration option "foo" of type STRING,
+ * it can emit `config_decl_STRING foo;`, which is an alias for `char *foo`.
+ */
+/**@{*/
+typedef char *config_decl_STRING;
+typedef char *config_decl_FILENAME;
+/* Yes, "POSINT" is really an int, and not an unsigned int. For
+ * historical reasons, many configuration values are restricted
+ * to the range [0,INT_MAX], and stored in signed ints.
+ */
+typedef int config_decl_POSINT;
+typedef uint64_t config_decl_UINT64;
+typedef int config_decl_INT;
+typedef int config_decl_INTERVAL;
+typedef int config_decl_MSEC_INTERVAL;
+typedef uint64_t config_decl_MEMUNIT;
+typedef double config_decl_DOUBLE;
+typedef int config_decl_BOOL;
+typedef int config_decl_AUTOBOOL;
+typedef time_t config_decl_ISOTIME;
+typedef struct smartlist_t config_decl_CSV;
+typedef int config_decl_CSV_INTERVAL;
+typedef struct config_line_t *config_decl_LINELIST;
+typedef struct config_line_t *config_decl_LINELIST_V;
+typedef struct nonexistent_struct *config_decl_LINELIST_S;
+/**@}*/
+
+struct var_type_def_t;
+
+/* Forward declarations for configuration type definitions. These are used by
+ * the CONF_VAR__TABLE macro to set the definition of each variable type
+ * correctly.
+ */
+/**@{*/
+extern const struct var_type_def_t STRING_type_defn;
+extern const struct var_type_def_t FILENAME_type_defn;
+extern const struct var_type_def_t POSINT_type_defn;
+extern const struct var_type_def_t UINT64_type_defn;
+extern const struct var_type_def_t INT_type_defn;
+extern const struct var_type_def_t INTERVAL_type_defn;
+extern const struct var_type_def_t MSEC_INTERVAL_type_defn;
+extern const struct var_type_def_t MEMUNIT_type_defn;
+extern const struct var_type_def_t DOUBLE_type_defn;
+extern const struct var_type_def_t BOOL_type_defn;
+extern const struct var_type_def_t AUTOBOOL_type_defn;
+extern const struct var_type_def_t ISOTIME_type_defn;
+extern const struct var_type_def_t CSV_type_defn;
+extern const struct var_type_def_t CSV_INTERVAL_type_defn;
+extern const struct var_type_def_t LINELIST_type_defn;
+extern const struct var_type_def_t LINELIST_V_type_defn;
+extern const struct var_type_def_t LINELIST_S_type_defn;
+extern const struct var_type_def_t IGNORE_type_defn;
+extern const struct var_type_def_t OBSOLETE_type_defn;
+/**@}*/
+
+#endif /* !defined(TOR_LIB_CONF_CONFDECL_H) */
diff --git a/src/lib/conf/config.md b/src/lib/conf/config.md
new file mode 100644
index 0000000000..7741e21f42
--- /dev/null
+++ b/src/lib/conf/config.md
@@ -0,0 +1,126 @@
+
+@page configuration Configuration options and persistent state
+
+@tableofcontents
+
+## Introduction
+
+Tor uses a shared, table-driven mechanism to handle its
+configuration (torrc) files and its state files. Each module can
+declare a set of named fields for these files, and get notified
+whenever the configuration changes, or when the state is about to be
+flushed to disk.
+
+## Declaring options
+
+Most modules will only need to use the macros in confdecl.h to
+declare a configuration or state structure.
+
+You'll write something like this:
+
+ // my_module_config.inc
+ BEGIN_CONF_STRUCT(module_options_t)
+ CONF_VAR(FieldOne, INT, 0, "7")
+ CONF_VAR(FieldTwo, STRING, 0, NULL)
+ END_CONF_STRUCT(module_options_t)
+
+The above example will result in a structure called module_config_t
+with two fields: one an integer called FieldOne and one a string
+called FieldTwo. The integer gets a default value of 7; the
+string's default value is NULL.
+
+After making a definition file like that, you include it twice: once
+in a header, after saying \#define CONF_CONTEXT STRUCT, and once in
+a C file, after saying \#define CONF_CONTEXT TABLE. The first time
+defines a module_options_t structure, and the second time defines a
+table that tells the configuration manager how to use it.
+
+Using the table, you declare a `const` config_format_t, which
+associates the fields with a set of functions for validating and
+normalizing them, a list of abbreviations and deprecations, and
+other features.
+
+See confdecl.h and conftypes.h for more information. For example
+usage, see crypto_options.inc or mainloop_state.inc.
+
+## Getting notifications
+
+After using those macros, you must tell the subsystem management
+code about your module's configuration/state.
+
+If you're writing configuration code, you'll need a function that receives
+the configuration object, and acts upon it. This function needs to be safe
+to call multiple times, since Tor will reconfigure its subsystems whenever it
+re-reads the torrc, gets a configuration change from a controller, or
+restarts in process. This function goes in your subsystem's
+subsys_fns_t.set_options field.
+
+If you're writing state code, you'll need a function that receives
+state (subsys_fns_t.set_state), and a function that flushes the
+application state into a state object (subsys_fns_t.flush_state).
+The `set_state` function will be called once (@ref config_once_per
+"1") when Tor is starting, whereas the `flush_state` function will
+be called whenever Tor is about to save the state to disk.
+
+See subsys_fns_t for more information here, and \ref initialization
+for more information about initialization and subsystems in general.
+
+> @anchor config_once_per 1. Technically, state is set once _per startup_.
+> Remember that Tor can be stopped and started multiple times in
+> the same process. If this happens, then your set_state() function
+> is called once every time Tor starts.
+
+## How it works
+
+The common logic used to handle configuration and state files lives
+in @refdir{lib/confmgt}. At the highest level, a configuration
+manager object (config_mgr_t) maintains a list of each module's
+configuration objects, and a list of all their fields. When the
+user specifies a configuration value, the manager finds out how to
+parse it, where to store it, and which configuration object is
+affected.
+
+The top-level configuration module (config.c) and state module
+(statefile.c) use config_mgr_t to create, initialize, set, compare,
+and free a "top level configuration object". This object contains a
+list of sub-objects: one for each module that participates in the
+configuration/state system. This top-level code then invokes the
+subsystem manager code (subsysmgr.c) to pass the corresponding
+configuration or state objects to each module that has one.
+
+Note that the top level code does not have easy access to the
+configuration objects used by the sub-modules. This is by design. A
+module _may_ expose some or all of its configuration or state object via
+accessor functions, if it likes, but if it does not, that object should
+be considered module-local.
+
+## Adding new types
+
+Configuration and state fields each have a "type". These types
+specify how the fields' values are represented in C; how they are
+stored in files; and how they are encoded back and forth.
+
+There is a set of built-in types listed in conftypes.h, but
+higher-level code can define its own types. To do so, you make an
+instance of var_type_fns_t that describes how to manage your type,
+and an instance of var_type_def_t that wraps your var_type_fns_t
+with a name and optional parameters and flags.
+
+For an example of how a higher-level type is defined, see
+ROUTERSET_type_defn in routerset.c. Also see the typedef
+`config_decl_ROUTERSET`. Together, these let the routerset type be
+used with the macros in confdecl.h.
+
+## Legacy configuration and state
+
+As of this writing (November 2019), most of the configuration and state is
+still handled directly in config.c and statefile.c, and stored in the
+monolithic structures or_options_t and or_state_t respectively.
+
+These top-level structures are accessed with get_options() and
+get_state(), and used throughout much of the code, at the level of
+@refdir{core} and higher.
+
+With time we hope to refactor this configuration into more
+reasonable pieces, so that they are no longer (effectively) global
+variables used throughout the code.
diff --git a/src/lib/conf/confmacros.h b/src/lib/conf/confmacros.h
index 68121891f1..9f85d21740 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,11 +15,13 @@
#include "orconfig.h"
#include "lib/conf/conftesting.h"
+#ifndef COCCI
/**
* Used to indicate the end of an array of configuration variables.
**/
#define END_OF_CONFIG_VARS \
{ .member = { .name = NULL } DUMMY_CONF_TEST_MEMBERS }
+#endif /* !defined(COCCI) */
/**
* Declare a config_var_t as a member named <b>membername</b> of the structure
@@ -43,7 +45,7 @@
}
/**
- * As CONFIG_VAR_XTYPE, but declares a value using an extension type whose
+ * As CONFIG_VAR_ETYPE, but declares a value using an extension type whose
* type definition is <b>vartype</b>_type_defn.
**/
#define CONFIG_VAR_DEFN(structtype, varname, vartype, membername, \
@@ -59,6 +61,9 @@
CONF_TEST_MEMBERS(structtype, vartype, membername) \
}
+/**
+ * Declare an obsolete configuration variable with a given name.
+ **/
#define CONFIG_VAR_OBSOLETE(varname) \
{ .member = { .name = varname, .type = CONFIG_TYPE_OBSOLETE }, \
.flags = CFLG_GROUP_OBSOLETE \
diff --git a/src/lib/conf/conftesting.h b/src/lib/conf/conftesting.h
index f01f52d59e..4707c919d3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,10 +12,14 @@
#ifndef TOR_LIB_CONF_CONFTESTING_H
#define TOR_LIB_CONF_CONFTESTING_H
+#include "lib/cc/torint.h"
+
+#ifndef COCCI
#ifdef TOR_UNIT_TESTS
+#define USE_CONF_TESTING
/**
* Union used when building in test mode typechecking the members of a type
- * used with confparse.c. See CONF_CHECK_VAR_TYPE for a description of how
+ * used with confmgt.c. See CONF_CHECK_VAR_TYPE for a description of how
* it is used. */
typedef union {
char **STRING;
@@ -41,13 +45,11 @@ typedef union {
// XXXX this doesn't belong at this level of abstraction.
struct routerset_t **ROUTERSET;
} confparse_dummy_values_t;
-#endif /* defined(TOR_UNIT_TESTS) */
/* Macros to define extra members inside config_var_t fields, and at the
* end of a list of them.
*/
-#ifdef TOR_UNIT_TESTS
-/* This is a somewhat magic type-checking macro for users of confparse.c.
+/* This is a somewhat magic type-checking macro for users of confmgt.c.
* It initializes a union member "confparse_dummy_values_t.conftype" with
* the address of a static member "tp_dummy.member". This
* will give a compiler warning unless the member field is of the correct
@@ -72,15 +74,16 @@ typedef union {
#define DUMMY_CONF_TEST_MEMBERS , .var_ptr_dummy={ .INT=NULL }
#define DUMMY_TYPECHECK_INSTANCE(tp) \
static tp tp ## _dummy
+#endif /* defined(TOR_UNIT_TESTS) */
+#endif /* !defined(COCCI) */
-#else /* !defined(TOR_UNIT_TESTS) */
-
+#ifndef USE_CONF_TESTING
#define CONF_TEST_MEMBERS(tp, conftype, member)
/* Repeatedly declarable incomplete struct to absorb redundant semicolons */
#define DUMMY_TYPECHECK_INSTANCE(tp) \
struct tor_semicolon_eater
#define DUMMY_CONF_TEST_MEMBERS
-#endif /* defined(TOR_UNIT_TESTS) */
+#endif /* !defined(USE_CONF_TESTING) */
#endif /* !defined(TOR_LIB_CONF_CONFTESTING_H) */
diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h
index 274065cff2..081ebf397f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -64,7 +64,18 @@ typedef enum config_type_t {
CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize
* context-sensitive config lines when fetching.
*/
- CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
+ /** Ignored (obsolete) option. Uses no storage.
+ *
+ * Reported as "obsolete" when its type is queried.
+ */
+ CONFIG_TYPE_OBSOLETE,
+ /** Ignored option. Uses no storage.
+ *
+ * Reported as "ignored" when its type is queried. For use with options used
+ * by disabled modules.
+ **/
+ CONFIG_TYPE_IGNORE,
+
/**
* Extended type: definition appears in the <b>type_def</b> pointer
* of the corresponding struct_member_t.
@@ -120,6 +131,9 @@ typedef struct struct_member_t {
*
* These 'magic numbers' are 32-bit values used to tag objects to make sure
* that they have the correct type.
+ *
+ * If all fields in this structure are zero or 0, the magic-number check is
+ * not performed.
*/
typedef struct struct_magic_decl_t {
/** The name of the structure */
@@ -178,12 +192,35 @@ typedef struct struct_magic_decl_t {
* however, setting them appends to their old value.
*/
#define CFLG_NOREPLACE (1u<<5)
+/**
+ * Flag to indicate that an option or type cannot be changed while Tor is
+ * running.
+ **/
+#define CFLG_IMMUTABLE (1u<<6)
+/**
+ * Flag to indicate that we should warn that an option or type is obsolete
+ * whenever the user tries to use it.
+ **/
+#define CFLG_WARN_OBSOLETE (1u<<7)
+/**
+ * Flag to indicate that we should warn that an option applies only to
+ * a disabled module, whenever the user tries to use it.
+ **/
+#define CFLG_WARN_DISABLED (1u<<8)
/**
* A group of flags that should be set on all obsolete options and types.
**/
#define CFLG_GROUP_OBSOLETE \
- (CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET|CFLG_NOLIST)
+ (CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET|CFLG_NOLIST|\
+ CFLG_WARN_OBSOLETE)
+
+/**
+ * A group of fflags that should be set on all disabled options.
+ **/
+#define CFLG_GROUP_DISABLED \
+ (CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET|CFLG_NOLIST|\
+ CFLG_WARN_DISABLED)
/** A variable allowed in the configuration file or on the command line. */
typedef struct config_var_t {
@@ -199,4 +236,148 @@ typedef struct config_var_t {
#endif
} config_var_t;
+/**
+ * An abbreviation or alias for a configuration option.
+ **/
+typedef struct config_abbrev_t {
+ /** The option name as abbreviated. Not case-sensitive. */
+ const char *abbreviated;
+ /** The full name of the option. Not case-sensitive. */
+ const char *full;
+ /** True if this abbreviation should only be allowed on the command line. */
+ int commandline_only;
+ /** True if we should warn whenever this abbreviation is used. */
+ int warn;
+} config_abbrev_t;
+
+/**
+ * A note that a configuration option is deprecated, with an explanation why.
+ */
+typedef struct config_deprecation_t {
+ /** The option that is deprecated. */
+ const char *name;
+ /** A user-facing string explaining why the option is deprecated. */
+ const char *why_deprecated;
+} config_deprecation_t;
+
+#ifndef COCCI
+/**
+ * Handy macro for declaring "In the config file or on the command line, you
+ * can abbreviate <b>tok</b>s as <b>tok</b>". Used inside an array of
+ * config_abbrev_t.
+ *
+ * For example, to declare "NumCpu" as an abbreviation for "NumCPUs",
+ * you can say PLURAL(NumCpu).
+ **/
+#define PLURAL(tok) { (#tok), (#tok "s"), 0, 0 }
+#endif /* !defined(COCCI) */
+
+/**
+ * Validation function: verify whether a configuation object is well-formed
+ * and consistent.
+ *
+ * On success, return 0. On failure, set <b>msg_out</b> to a newly allocated
+ * string containing an error message, and return -1. */
+typedef int (*validate_fn_t)(const void *value, char **msg_out);
+/**
+ * Validation function: verify whether a configuration object (`value`) is an
+ * allowable value given the previous configuration value (`old_value`).
+ *
+ * On success, return 0. On failure, set <b>msg_out</b> to a newly allocated
+ * string containing an error message, and return -1. */
+typedef int (*check_transition_fn_t)(const void *old_value, const void *value,
+ char **msg_out);
+/**
+ * Validation function: normalize members of `value`, and compute derived
+ * members.
+ *
+ * This function is called before any other validation of `value`, and must
+ * not assume that validate_fn or check_transition_fn has passed.
+ *
+ * On success, return 0. On failure, set <b>msg_out</b> to a newly allocated
+ * string containing an error message, and return -1. */
+typedef int (*pre_normalize_fn_t)(void *value, char **msg_out);
+/**
+ * Validation function: normalize members of `value`, and compute derived
+ * members.
+ *
+ * This function is called after validation of `value`, and may
+ * assume that validate_fn or check_transition_fn has passed.
+ *
+ * On success, return 0. On failure, set <b>msg_out</b> to a newly allocated
+ * string containing an error message, and return -1. */
+typedef int (*post_normalize_fn_t)(void *value, char **msg_out);
+
+/**
+ * Legacy function to validate whether a given configuration is
+ * well-formed and consistent.
+ *
+ * The configuration to validate is passed as <b>newval</b>. The previous
+ * configuration, if any, is provided in <b>oldval</b>.
+ *
+ * This API is deprecated, since it mixes the responsibilities of
+ * pre_normalize_fn_t, post_normalize_fn_t, validate_fn_t, and
+ * check_transition_fn_t. No new instances of this function type should
+ * be written.
+ *
+ * On success, return 0. On failure, set *<b>msg_out</b> to a newly allocated
+ * error message, and return -1.
+ */
+typedef int (*legacy_validate_fn_t)(const void *oldval,
+ void *newval,
+ char **msg_out);
+
+struct config_mgr_t;
+
+/**
+ * Callback to clear all non-managed fields of a configuration object.
+ *
+ * <b>obj</b> is the configuration object whose non-managed fields should be
+ * cleared.
+ *
+ * (Regular fields get cleared by config_reset(), but you might have fields
+ * in the object that do not correspond to configuration variables. If those
+ * fields need to be cleared or freed, this is where to do it.)
+ */
+typedef void (*clear_cfg_fn_t)(const struct config_mgr_t *mgr, void *obj);
+
+/** Information on the keys, value types, key-to-struct-member mappings,
+ * variable descriptions, validation functions, and abbreviations for a
+ * configuration or storage format. */
+typedef struct config_format_t {
+ size_t size; /**< Size of the struct that everything gets parsed into. */
+ struct_magic_decl_t magic; /**< Magic number info for this struct. */
+ const config_abbrev_t *abbrevs; /**< List of abbreviations that we expand
+ * when parsing this format. */
+ const config_deprecation_t *deprecations; /** List of deprecated options */
+ const config_var_t *vars; /**< List of variables we recognize, their default
+ * values, and where we stick them in the
+ * structure. */
+
+ /** Early-stage normalization callback. Invoked by config_validate(). */
+ pre_normalize_fn_t pre_normalize_fn;
+ /** Configuration validation function. Invoked by config_validate(). */
+ validate_fn_t validate_fn;
+ /** Legacy validation function. Invoked by config_validate(). */
+ legacy_validate_fn_t legacy_validate_fn;
+ /** Transition checking function. Invoked by config_validate(). */
+ check_transition_fn_t check_transition_fn;
+ /** Late-stage normalization callback. Invoked by config_validate(). */
+ post_normalize_fn_t post_normalize_fn;
+
+ clear_cfg_fn_t clear_fn; /**< Function to clear the configuration. */
+ /** If present, extra denotes a LINELIST variable for unrecognized
+ * lines. Otherwise, unrecognized lines are an error. */
+ const struct_member_t *extra;
+ /**
+ * If true, this format describes a top-level configuration, with
+ * a suite containing multiple sub-configuration objects.
+ */
+ bool has_config_suite;
+ /** The position of a config_suite_t pointer within the toplevel object.
+ * Ignored unless have_config_suite is true.
+ */
+ ptrdiff_t config_suite_offset;
+} config_format_t;
+
#endif /* !defined(TOR_SRC_LIB_CONF_CONFTYPES_H) */
diff --git a/src/lib/conf/include.am b/src/lib/conf/include.am
index cb7126184d..cb0b83fa64 100644
--- a/src/lib/conf/include.am
+++ b/src/lib/conf/include.am
@@ -1,6 +1,7 @@
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
+ src/lib/conf/confdecl.h \
src/lib/conf/conftesting.h \
src/lib/conf/conftypes.h \
src/lib/conf/confmacros.h
diff --git a/src/lib/conf/lib_conf.md b/src/lib/conf/lib_conf.md
new file mode 100644
index 0000000000..60dd04e99e
--- /dev/null
+++ b/src/lib/conf/lib_conf.md
@@ -0,0 +1,3 @@
+@dir /lib/conf
+@brief lib/conf: Types and macros for declaring configuration options.
+
diff --git a/src/lib/confmgt/.may_include b/src/lib/confmgt/.may_include
index 2564133917..5ff949f103 100644
--- a/src/lib/confmgt/.may_include
+++ b/src/lib/confmgt/.may_include
@@ -4,6 +4,7 @@ lib/conf/*.h
lib/confmgt/*.h
lib/container/*.h
lib/encoding/*.h
+lib/intmath/*.h
lib/log/*.h
lib/malloc/*.h
lib/string/*.h
diff --git a/src/lib/confmgt/confparse.c b/src/lib/confmgt/confmgt.c
index 08e562f654..bf2764160e 100644
--- a/src/lib/confmgt/confparse.c
+++ b/src/lib/confmgt/confmgt.c
@@ -1,11 +1,11 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file confparse.c
+ * \file confmgt.c
*
* \brief Back-end for parsing and generating key-value files, used to
* implement the torrc file format and the state file.
@@ -21,9 +21,9 @@
* specified, and a linked list of key-value pairs.
*/
-#define CONFPARSE_PRIVATE
+#define CONFMGT_PRIVATE
#include "orconfig.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/confmgt/structvar.h"
#include "lib/confmgt/unitparse.h"
@@ -169,9 +169,14 @@ config_mgr_register_fmt(config_mgr_t *mgr,
"it had been frozen.");
if (object_idx != IDX_TOPLEVEL) {
- tor_assertf(fmt->config_suite_offset < 0,
+ tor_assertf(! fmt->has_config_suite,
"Tried to register a toplevel format in a non-toplevel position");
}
+ if (fmt->config_suite_offset) {
+ tor_assertf(fmt->has_config_suite,
+ "config_suite_offset was set, but has_config_suite was not.");
+ }
+
tor_assertf(fmt != mgr->toplevel &&
! smartlist_contains(mgr->subconfigs, fmt),
"Tried to register an already-registered format.");
@@ -223,7 +228,7 @@ config_mgr_add_format(config_mgr_t *mgr,
static inline config_suite_t **
config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
{
- if (mgr->toplevel->config_suite_offset < 0)
+ if (! mgr->toplevel->has_config_suite)
return NULL;
return STRUCT_VAR_P(toplevel, mgr->toplevel->config_suite_offset);
}
@@ -237,7 +242,7 @@ config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
* to configuration objects for other modules. This function gets
* the sub-object for a particular module.
*/
-STATIC void *
+void *
config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
{
tor_assert(mgr);
@@ -256,7 +261,7 @@ config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
}
/** As config_mgr_get_obj_mutable(), but return a const pointer. */
-STATIC const void *
+const void *
config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx)
{
return config_mgr_get_obj_mutable(mgr, (void*)toplevel, idx);
@@ -334,6 +339,17 @@ config_mgr_list_deprecated_vars(const config_mgr_t *mgr)
return result;
}
+/**
+ * Check the magic number on <b>object</b> to make sure it's a valid toplevel
+ * object, created with <b>mgr</b>. Exit with an assertion if it isn't.
+ **/
+void
+config_check_toplevel_magic(const config_mgr_t *mgr,
+ const void *object)
+{
+ struct_check_magic(object, &mgr->toplevel_magic);
+}
+
/** Assert that the magic fields in <b>options</b> and its subsidiary
* objects are all okay. */
static void
@@ -641,6 +657,14 @@ config_assign_value(const config_mgr_t *mgr, void *options,
tor_assert(!strcmp(c->key, var->cvar->member.name));
void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
+ if (config_var_has_flag(var->cvar, CFLG_WARN_OBSOLETE)) {
+ log_warn(LD_GENERAL, "Skipping obsolete configuration option \"%s\".",
+ var->cvar->member.name);
+ } else if (config_var_has_flag(var->cvar, CFLG_WARN_DISABLED)) {
+ log_warn(LD_GENERAL, "This copy of Tor was built without support for "
+ "the option \"%s\". Skipping.", var->cvar->member.name);
+ }
+
return struct_var_kvassign(object, c, msg, &var->cvar->member);
}
@@ -1142,6 +1166,146 @@ config_init(const config_mgr_t *mgr, void *options)
} SMARTLIST_FOREACH_END(mv);
}
+/**
+ * Helper for config_validate_single: see whether any immutable option
+ * has changed between old_options and new_options.
+ *
+ * On success return 0; on failure set *msg_out to a newly allocated
+ * string explaining what is wrong, and return -1.
+ */
+static int
+config_check_immutable_flags(const config_format_t *fmt,
+ const void *old_options,
+ const void *new_options,
+ char **msg_out)
+{
+ tor_assert(fmt);
+ tor_assert(new_options);
+ if (BUG(! old_options))
+ return 0;
+
+ unsigned i;
+ for (i = 0; fmt->vars[i].member.name; ++i) {
+ const config_var_t *v = &fmt->vars[i];
+ if (! config_var_has_flag(v, CFLG_IMMUTABLE))
+ continue;
+
+ if (! struct_var_eq(old_options, new_options, &v->member)) {
+ tor_asprintf(msg_out,
+ "While Tor is running, changing %s is not allowed",
+ v->member.name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Normalize and validate a single object `options` within a configuration
+ * suite, according to its format. `options` may be modified as appropriate
+ * in order to set ancillary data. If `old_options` is provided, make sure
+ * that the transition from `old_options` to `options` is permitted.
+ *
+ * On success return VSTAT_OK; on failure set *msg_out to a newly allocated
+ * string explaining what is wrong, and return a different validation_status_t
+ * to describe which step failed.
+ **/
+static validation_status_t
+config_validate_single(const config_format_t *fmt,
+ const void *old_options, void *options,
+ char **msg_out)
+{
+ tor_assert(fmt);
+ tor_assert(options);
+
+ if (fmt->pre_normalize_fn) {
+ if (fmt->pre_normalize_fn(options, msg_out) < 0) {
+ return VSTAT_PRE_NORMALIZE_ERR;
+ }
+ }
+
+ if (fmt->legacy_validate_fn) {
+ if (fmt->legacy_validate_fn(old_options, options, msg_out) < 0) {
+ return VSTAT_LEGACY_ERR;
+ }
+ }
+
+ if (fmt->validate_fn) {
+ if (fmt->validate_fn(options, msg_out) < 0) {
+ return VSTAT_VALIDATE_ERR;
+ }
+ }
+
+ if (old_options) {
+ if (config_check_immutable_flags(fmt, old_options, options, msg_out) < 0) {
+ return VSTAT_TRANSITION_ERR;
+ }
+
+ if (fmt->check_transition_fn) {
+ if (fmt->check_transition_fn(old_options, options, msg_out) < 0) {
+ return VSTAT_TRANSITION_ERR;
+ }
+ }
+ }
+
+ if (fmt->post_normalize_fn) {
+ if (fmt->post_normalize_fn(options, msg_out) < 0) {
+ return VSTAT_POST_NORMALIZE_ERR;
+ }
+ }
+
+ return VSTAT_OK;
+}
+
+/**
+ * Normalize and validate all the options in configuration object `options`
+ * and its sub-objects. `options` may be modified as appropriate in order to
+ * set ancillary data. If `old_options` is provided, make sure that the
+ * transition from `old_options` to `options` is permitted.
+ *
+ * On success return VSTAT_OK; on failure set *msg_out to a newly allocated
+ * string explaining what is wrong, and return a different validation_status_t
+ * to describe which step failed.
+ **/
+validation_status_t
+config_validate(const config_mgr_t *mgr,
+ const void *old_options, void *options,
+ char **msg_out)
+{
+ validation_status_t rv;
+ CONFIG_CHECK(mgr, options);
+ if (old_options) {
+ CONFIG_CHECK(mgr, old_options);
+ }
+
+ config_suite_t **suitep_new = config_mgr_get_suite_ptr(mgr, options);
+ config_suite_t **suitep_old = NULL;
+ if (old_options)
+ suitep_old = config_mgr_get_suite_ptr(mgr, (void*) old_options);
+
+ /* Validate the sub-objects */
+ if (suitep_new) {
+ SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
+ void *obj = smartlist_get((*suitep_new)->configs, fmt_sl_idx);
+ const void *obj_old=NULL;
+ if (suitep_old)
+ obj_old = smartlist_get((*suitep_old)->configs, fmt_sl_idx);
+
+ rv = config_validate_single(fmt, obj_old, obj, msg_out);
+ if (rv < 0)
+ return rv;
+ } SMARTLIST_FOREACH_END(fmt);
+ }
+
+ /* Validate the top-level object. */
+ rv = config_validate_single(mgr->toplevel, old_options, options, msg_out);
+ if (rv < 0)
+ return rv;
+
+ return VSTAT_OK;
+}
+
/** Allocate and return a new string holding the written-out values of the vars
* in 'options'. If 'minimal', do not write out any default-valued vars.
* Else, if comment_defaults, write default values as comments.
@@ -1166,7 +1330,7 @@ config_dump(const config_mgr_t *mgr, const void *default_options,
/* XXX use a 1 here so we don't add a new log line while dumping */
if (default_options == NULL) {
- if (fmt->validate_fn(NULL, defaults_tmp, defaults_tmp, 1, &msg) < 0) {
+ if (config_validate(mgr, NULL, defaults_tmp, &msg) < 0) {
// LCOV_EXCL_START
log_err(LD_BUG, "Failed to validate default config: %s", msg);
tor_free(msg);
@@ -1197,9 +1361,10 @@ config_dump(const config_mgr_t *mgr, const void *default_options,
*/
continue;
}
- smartlist_add_asprintf(elements, "%s%s %s\n",
+ int value_exists = line->value && *(line->value);
+ smartlist_add_asprintf(elements, "%s%s%s%s\n",
comment_option ? "# " : "",
- line->key, line->value);
+ line->key, value_exists ? " " : "", line->value);
}
config_free_lines(assigned);
} SMARTLIST_FOREACH_END(mv);
@@ -1207,7 +1372,9 @@ config_dump(const config_mgr_t *mgr, const void *default_options,
if (fmt->extra) {
line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset);
for (; line; line = line->next) {
- smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
+ int value_exists = line->value && *(line->value);
+ smartlist_add_asprintf(elements, "%s%s%s\n",
+ line->key, value_exists ? " " : "", line->value);
}
}
diff --git a/src/lib/confmgt/confparse.h b/src/lib/confmgt/confmgt.h
index 2332f69790..5065c13b60 100644
--- a/src/lib/confmgt/confparse.h
+++ b/src/lib/confmgt/confmgt.h
@@ -1,116 +1,23 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file confparse.h
+ * \file confmgt.h
*
- * \brief Header for confparse.c.
+ * \brief Header for confmgt.c.
*/
-#ifndef TOR_CONFPARSE_H
-#define TOR_CONFPARSE_H
+#ifndef TOR_CONFMGT_H
+#define TOR_CONFMGT_H
#include "lib/conf/conftypes.h"
#include "lib/conf/confmacros.h"
#include "lib/testsupport/testsupport.h"
/**
- * An abbreviation or alias for a configuration option.
- **/
-typedef struct config_abbrev_t {
- /** The option name as abbreviated. Not case-sensitive. */
- const char *abbreviated;
- /** The full name of the option. Not case-sensitive. */
- const char *full;
- /** True if this abbreviation should only be allowed on the command line. */
- int commandline_only;
- /** True if we should warn whenever this abbreviation is used. */
- int warn;
-} config_abbrev_t;
-
-/**
- * A note that a configuration option is deprecated, with an explanation why.
- */
-typedef struct config_deprecation_t {
- /** The option that is deprecated. */
- const char *name;
- /** A user-facing string explaining why the option is deprecated. */
- const char *why_deprecated;
-} config_deprecation_t;
-
-/**
- * Handy macro for declaring "In the config file or on the command line, you
- * can abbreviate <b>tok</b>s as <b>tok</b>". Used inside an array of
- * config_abbrev_t.
- *
- * For example, to declare "NumCpu" as an abbreviation for "NumCPUs",
- * you can say PLURAL(NumCpu).
- **/
-#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
-
-/**
- * Type of a callback to validate whether a given configuration is
- * well-formed and consistent.
- *
- * The configuration to validate is passed as <b>newval</b>. The previous
- * configuration, if any, is provided in <b>oldval</b>. The
- * <b>default_val</b> argument receives a configuration object initialized
- * with default values for all its fields. The <b>from_setconf</b> argument
- * is true iff the input comes from a SETCONF controller command.
- *
- * On success, return 0. On failure, set *<b>msg_out</b> to a newly allocated
- * error message, and return -1.
- *
- * REFACTORING NOTE: Currently, this callback type is only used from inside
- * config_dump(); later in our refactoring, it will be cleaned up and used
- * more generally.
- */
-typedef int (*validate_fn_t)(void *oldval,
- void *newval,
- void *default_val,
- int from_setconf,
- char **msg_out);
-
-struct config_mgr_t;
-
-/**
- * Callback to clear all non-managed fields of a configuration object.
- *
- * <b>obj</b> is the configuration object whose non-managed fields should be
- * cleared.
- *
- * (Regular fields get cleared by config_reset(), but you might have fields
- * in the object that do not correspond to configuration variables. If those
- * fields need to be cleared or freed, this is where to do it.)
- */
-typedef void (*clear_cfg_fn_t)(const struct config_mgr_t *mgr, void *obj);
-
-/** Information on the keys, value types, key-to-struct-member mappings,
- * variable descriptions, validation functions, and abbreviations for a
- * configuration or storage format. */
-typedef struct config_format_t {
- size_t size; /**< Size of the struct that everything gets parsed into. */
- struct_magic_decl_t magic; /**< Magic number info for this struct. */
- const config_abbrev_t *abbrevs; /**< List of abbreviations that we expand
- * when parsing this format. */
- const config_deprecation_t *deprecations; /** List of deprecated options */
- const config_var_t *vars; /**< List of variables we recognize, their default
- * values, and where we stick them in the
- * structure. */
- validate_fn_t validate_fn; /**< Function to validate config. */
- clear_cfg_fn_t clear_fn; /**< Function to clear the configuration. */
- /** If present, extra denotes a LINELIST variable for unrecognized
- * lines. Otherwise, unrecognized lines are an error. */
- const struct_member_t *extra;
- /** The position of a config_suite_t pointer within the toplevel object,
- * or -1 if there is no such pointer. */
- ptrdiff_t config_suite_offset;
-} config_format_t;
-
-/**
* A collection of config_format_t objects to describe several objects
* that are all configured with the same configuration file.
*
@@ -171,10 +78,26 @@ int config_is_same(const config_mgr_t *fmt,
struct config_line_t *config_get_changes(const config_mgr_t *mgr,
const void *options1, const void *options2);
void config_init(const config_mgr_t *mgr, void *options);
+
+/** An enumeration to report which validation step failed. */
+typedef enum {
+ VSTAT_PRE_NORMALIZE_ERR = -5,
+ VSTAT_VALIDATE_ERR = -4,
+ VSTAT_LEGACY_ERR = -3,
+ VSTAT_TRANSITION_ERR = -2,
+ VSTAT_POST_NORMALIZE_ERR = -1,
+ VSTAT_OK = 0,
+} validation_status_t;
+
+validation_status_t config_validate(const config_mgr_t *mgr,
+ const void *old_options, void *options,
+ char **msg_out);
void *config_dup(const config_mgr_t *mgr, const void *old);
char *config_dump(const config_mgr_t *mgr, const void *default_options,
const void *options, int minimal,
int comment_defaults);
+void config_check_toplevel_magic(const config_mgr_t *mgr,
+ const void *object);
bool config_check_ok(const config_mgr_t *mgr, const void *options,
int severity);
int config_assign(const config_mgr_t *mgr, void *options,
@@ -200,13 +123,14 @@ bool config_var_is_listable(const config_var_t *var);
#define CFG_EQ_LINELIST(a,b,opt) config_lines_eq((a)->opt, (b)->opt)
#define CFG_EQ_ROUTERSET(a,b,opt) routerset_equal((a)->opt, (b)->opt)
-#ifdef CONFPARSE_PRIVATE
+void *config_mgr_get_obj_mutable(const config_mgr_t *mgr,
+ void *toplevel, int idx);
+const void *config_mgr_get_obj(const config_mgr_t *mgr,
+ const void *toplevel, int idx);
+
+#ifdef CONFMGT_PRIVATE
STATIC void config_reset_line(const config_mgr_t *mgr, void *options,
const char *key, int use_defaults);
-STATIC void *config_mgr_get_obj_mutable(const config_mgr_t *mgr,
- void *toplevel, int idx);
-STATIC const void *config_mgr_get_obj(const config_mgr_t *mgr,
- const void *toplevel, int idx);
-#endif /* defined(CONFPARSE_PRIVATE) */
+#endif /* defined(CONFMGT_PRIVATE) */
-#endif /* !defined(TOR_CONFPARSE_H) */
+#endif /* !defined(TOR_CONFMGT_H) */
diff --git a/src/lib/confmgt/include.am b/src/lib/confmgt/include.am
index 81cd868e5e..d3a7a7cd69 100644
--- a/src/lib/confmgt/include.am
+++ b/src/lib/confmgt/include.am
@@ -6,7 +6,7 @@ endif
# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_confmgt_a_SOURCES = \
- src/lib/confmgt/confparse.c \
+ src/lib/confmgt/confmgt.c \
src/lib/confmgt/structvar.c \
src/lib/confmgt/type_defs.c \
src/lib/confmgt/typedvar.c \
@@ -19,7 +19,7 @@ src_lib_libtor_confmgt_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
- src/lib/confmgt/confparse.h \
+ src/lib/confmgt/confmgt.h \
src/lib/confmgt/structvar.h \
src/lib/confmgt/type_defs.h \
src/lib/confmgt/typedvar.h \
diff --git a/src/lib/confmgt/lib_confmgt.md b/src/lib/confmgt/lib_confmgt.md
new file mode 100644
index 0000000000..861e720f64
--- /dev/null
+++ b/src/lib/confmgt/lib_confmgt.md
@@ -0,0 +1,7 @@
+@dir /lib/confmgt
+@brief lib/confmgt: Parse, encode, manipulate configuration files.
+
+This logic is used in common by our state files (statefile.c) and
+configuration files (config.c) to manage a set of named, typed fields,
+reading and writing them to disk and to the controller.
+
diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c
index 7a3b8c7df2..55deb4759c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -30,13 +30,28 @@
#include <stddef.h>
/**
+ * Return true iff all fields on <b>decl</b> are NULL or 0, indicating that
+ * there is no object or no magic number to check.
+ **/
+static inline bool
+magic_is_null(const struct_magic_decl_t *decl)
+{
+ return decl->typename == NULL &&
+ decl->magic_offset == 0 &&
+ decl->magic_val == 0;
+}
+
+/**
* Set the 'magic number' on <b>object</b> to correspond to decl.
**/
void
struct_set_magic(void *object, const struct_magic_decl_t *decl)
{
- tor_assert(object);
tor_assert(decl);
+ if (magic_is_null(decl))
+ return;
+
+ tor_assert(object);
uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset);
*ptr = decl->magic_val;
}
@@ -47,8 +62,11 @@ struct_set_magic(void *object, const struct_magic_decl_t *decl)
void
struct_check_magic(const void *object, const struct_magic_decl_t *decl)
{
- tor_assert(object);
tor_assert(decl);
+ if (magic_is_null(decl))
+ return;
+
+ tor_assert(object);
const uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset);
tor_assertf(*ptr == decl->magic_val,
diff --git a/src/lib/confmgt/structvar.h b/src/lib/confmgt/structvar.h
index bcb4b58c3f..91334fa8c5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 5066e12265..d9e5e1e4c2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,12 +17,12 @@
#include "orconfig.h"
#include "lib/conf/conftypes.h"
+#include "lib/conf/confdecl.h"
#include "lib/confmgt/typedvar.h"
#include "lib/confmgt/type_defs.h"
#include "lib/confmgt/unitparse.h"
#include "lib/cc/compat_compiler.h"
-#include "lib/conf/conftypes.h"
#include "lib/container/smartlist.h"
#include "lib/encoding/confline.h"
#include "lib/encoding/time_fmt.h"
@@ -52,11 +52,10 @@
static int
string_parse(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
(void)params;
(void)errmsg;
- (void)key;
char **p = (char**)target;
*p = tor_strdup(value);
return 0;
@@ -91,9 +90,12 @@ static const var_type_fns_t string_fns = {
// These types are implemented as int, possibly with a restricted range.
/////
+/**
+ * Parameters for parsing an integer type.
+ **/
typedef struct int_type_params_t {
- int minval;
- int maxval;
+ int minval; /**< Lowest allowed value */
+ int maxval; /**< Highest allowed value */
} int_parse_params_t;
static const int_parse_params_t INT_PARSE_UNRESTRICTED = {
@@ -107,10 +109,8 @@ static const int_parse_params_t INT_PARSE_POSINT = {
};
static int
-int_parse(void *target, const char *value, char **errmsg, const void *params,
- const char *key)
+int_parse(void *target, const char *value, char **errmsg, const void *params)
{
- (void)key;
const int_parse_params_t *pp;
if (params) {
pp = params;
@@ -121,8 +121,9 @@ int_parse(void *target, const char *value, char **errmsg, const void *params,
int ok=0;
*p = (int)tor_parse_long(value, 10, pp->minval, pp->maxval, &ok, NULL);
if (!ok) {
- tor_asprintf(errmsg, "Integer %s is malformed or out of bounds.",
- value);
+ tor_asprintf(errmsg, "Integer %s is malformed or out of bounds. "
+ "Allowed values are between %d and %d.",
+ value, pp->minval, pp->maxval);
return -1;
}
return 0;
@@ -172,11 +173,10 @@ static const var_type_fns_t int_fns = {
static int
uint64_parse(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
(void)params;
(void)errmsg;
- (void)key;
uint64_t *p = target;
int ok=0;
*p = tor_parse_uint64(value, 10, 0, UINT64_MAX, &ok, NULL);
@@ -223,35 +223,45 @@ static const var_type_fns_t uint64_fns = {
static int
units_parse_u64(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
- (void)key;
const unit_table_t *table = params;
tor_assert(table);
uint64_t *v = (uint64_t*)target;
int ok=1;
- *v = config_parse_units(value, table, &ok);
+ char *msg = NULL;
+ *v = config_parse_units(value, table, &ok, &msg);
if (!ok) {
- *errmsg = tor_strdup("Provided value is malformed or out of bounds.");
+ tor_asprintf(errmsg, "Provided value is malformed or out of bounds: %s",
+ msg);
+ tor_free(msg);
return -1;
}
+ if (BUG(msg)) {
+ tor_free(msg);
+ }
return 0;
}
static int
units_parse_int(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
- (void)key;
const unit_table_t *table = params;
tor_assert(table);
int *v = (int*)target;
int ok=1;
- uint64_t u64 = config_parse_units(value, table, &ok);
+ char *msg = NULL;
+ uint64_t u64 = config_parse_units(value, table, &ok, &msg);
if (!ok) {
- *errmsg = tor_strdup("Provided value is malformed or out of bounds.");
+ tor_asprintf(errmsg, "Provided value is malformed or out of bounds: %s",
+ msg);
+ tor_free(msg);
return -1;
}
+ if (BUG(msg)) {
+ tor_free(msg);
+ }
if (u64 > INT_MAX) {
tor_asprintf(errmsg, "Provided value %s is too large", value);
return -1;
@@ -289,11 +299,10 @@ static const var_type_fns_t interval_fns = {
static int
double_parse(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
(void)params;
(void)errmsg;
- (void)key;
double *v = (double*)target;
char *endptr=NULL;
errno = 0;
@@ -352,12 +361,17 @@ typedef struct enumeration_table_t {
int value;
} enumeration_table_t;
+typedef struct enumeration_params_t {
+ const char *allowed_val_string;
+ const enumeration_table_t *table;
+} enumeration_params_t;
+
static int
enum_parse(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params_)
{
- (void)key;
- const enumeration_table_t *table = params;
+ const enumeration_params_t *params = params_;
+ const enumeration_table_t *table = params->table;
int *p = (int *)target;
for (; table->name; ++table) {
if (!strcasecmp(value, table->name)) {
@@ -365,15 +379,17 @@ enum_parse(void *target, const char *value, char **errmsg,
return 0;
}
}
- tor_asprintf(errmsg, "Unrecognized value %s.", value);
+ tor_asprintf(errmsg, "Unrecognized value %s. %s",
+ value, params->allowed_val_string);
return -1;
}
static char *
-enum_encode(const void *value, const void *params)
+enum_encode(const void *value, const void *params_)
{
int v = *(const int*)value;
- const enumeration_table_t *table = params;
+ const enumeration_params_t *params = params_;
+ const enumeration_table_t *table = params->table;
for (; table->name; ++table) {
if (v == table->value)
return tor_strdup(table->name);
@@ -382,19 +398,21 @@ enum_encode(const void *value, const void *params)
}
static void
-enum_clear(void *value, const void *params)
+enum_clear(void *value, const void *params_)
{
int *p = (int*)value;
- const enumeration_table_t *table = params;
+ const enumeration_params_t *params = params_;
+ const enumeration_table_t *table = params->table;
tor_assert(table->name);
*p = table->value;
}
static bool
-enum_ok(const void *value, const void *params)
+enum_ok(const void *value, const void *params_)
{
int v = *(const int*)value;
- const enumeration_table_t *table = params;
+ const enumeration_params_t *params = params_;
+ const enumeration_table_t *table = params->table;
for (; table->name; ++table) {
if (v == table->value)
return true;
@@ -408,6 +426,11 @@ static const enumeration_table_t enum_table_bool[] = {
{ NULL, 0 },
};
+static const enumeration_params_t enum_params_bool = {
+ "Allowed values are 0 and 1.",
+ enum_table_bool
+};
+
static const enumeration_table_t enum_table_autobool[] = {
{ "0", 0 },
{ "1", 1 },
@@ -415,6 +438,11 @@ static const enumeration_table_t enum_table_autobool[] = {
{ NULL, 0 },
};
+static const enumeration_params_t enum_params_autobool = {
+ "Allowed values are 0, 1, and auto.",
+ enum_table_autobool
+};
+
static const var_type_fns_t enum_fns = {
.parse = enum_parse,
.encode = enum_encode,
@@ -430,10 +458,9 @@ static const var_type_fns_t enum_fns = {
static int
time_parse(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
(void) params;
- (void) key;
time_t *p = target;
if (parse_iso_time(value, p) < 0) {
tor_asprintf(errmsg, "Invalid time %s", escaped(value));
@@ -475,11 +502,10 @@ static const var_type_fns_t time_fns = {
static int
csv_parse(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
(void)params;
(void)errmsg;
- (void)key;
smartlist_t **sl = (smartlist_t**)target;
*sl = smartlist_new();
smartlist_split_string(*sl, value, ",",
@@ -525,7 +551,7 @@ static const var_type_fns_t csv_fns = {
static int
legacy_csv_interval_parse(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
(void)params;
/* We used to have entire smartlists here. But now that all of our
@@ -539,7 +565,7 @@ legacy_csv_interval_parse(void *target, const char *value, char **errmsg,
val = tmp;
}
- int rv = units_parse_int(target, val, errmsg, &time_units, key);
+ int rv = units_parse_int(target, val, errmsg, &time_units);
tor_free(tmp);
return rv;
}
@@ -688,32 +714,23 @@ static const var_type_fns_t linelist_s_fns = {
/////
// CONFIG_TYPE_ROUTERSET
//
-// XXXX This type is not implemented here, since routerset_t is not available
// XXXX to this module.
/////
/////
-// CONFIG_TYPE_OBSOLETE
-//
-// Used to indicate an obsolete option.
+// CONFIG_TYPE_IGNORE
//
-// XXXX This is not a type, and should be handled at a higher level of
-// XXXX abstraction.
+// Used to indicate an option that cannot be stored or encoded.
/////
static int
ignore_parse(void *target, const char *value, char **errmsg,
- const void *params, const char *key)
+ const void *params)
{
(void)target;
(void)value;
(void)errmsg;
(void)params;
- // XXXX move this to a higher level, once such a level exists.
- log_warn(LD_GENERAL, "Skipping obsolete configuration option%s%s%s",
- key && *key ? " \"" : "",
- key && *key ? key : "",
- key && *key ? "\"." : ".");
return 0;
}
@@ -730,50 +747,91 @@ static const var_type_fns_t ignore_fns = {
.encode = ignore_encode,
};
+const var_type_def_t STRING_type_defn = {
+ .name="String", .fns=&string_fns };
+const var_type_def_t FILENAME_type_defn = {
+ .name="Filename", .fns=&string_fns };
+const var_type_def_t INT_type_defn = {
+ .name="SignedInteger", .fns=&int_fns,
+ .params=&INT_PARSE_UNRESTRICTED };
+const var_type_def_t POSINT_type_defn = {
+ .name="Integer", .fns=&int_fns,
+ .params=&INT_PARSE_POSINT };
+const var_type_def_t UINT64_type_defn = {
+ .name="Integer", .fns=&uint64_fns, };
+const var_type_def_t MEMUNIT_type_defn = {
+ .name="DataSize", .fns=&memunit_fns,
+ .params=&memory_units };
+const var_type_def_t INTERVAL_type_defn = {
+ .name="TimeInterval", .fns=&interval_fns,
+ .params=&time_units };
+const var_type_def_t MSEC_INTERVAL_type_defn = {
+ .name="TimeMsecInterval",
+ .fns=&interval_fns,
+ .params=&time_msec_units };
+const var_type_def_t DOUBLE_type_defn = {
+ .name="Float", .fns=&double_fns, };
+const var_type_def_t BOOL_type_defn = {
+ .name="Boolean", .fns=&enum_fns,
+ .params=&enum_params_bool };
+const var_type_def_t AUTOBOOL_type_defn = {
+ .name="Boolean+Auto", .fns=&enum_fns,
+ .params=&enum_params_autobool };
+const var_type_def_t ISOTIME_type_defn = {
+ .name="Time", .fns=&time_fns, };
+const var_type_def_t CSV_type_defn = {
+ .name="CommaList", .fns=&csv_fns, };
+const var_type_def_t CSV_INTERVAL_type_defn = {
+ .name="TimeInterval",
+ .fns=&legacy_csv_interval_fns, };
+const var_type_def_t LINELIST_type_defn = {
+ .name="LineList", .fns=&linelist_fns,
+ .flags=CFLG_NOREPLACE };
+/*
+ * A "linelist_s" is a derived view of a linelist_v: inspecting
+ * it gets part of a linelist_v, and setting it adds to the linelist_v.
+ */
+const var_type_def_t LINELIST_S_type_defn = {
+ .name="Dependent", .fns=&linelist_s_fns,
+ .flags=CFLG_NOREPLACE|
+ /* The operations we disable here are
+ * handled by the linelist_v. */
+ CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP };
+const var_type_def_t LINELIST_V_type_defn = {
+ .name="Virtual", .fns=&linelist_v_fns,
+ .flags=CFLG_NOREPLACE|CFLG_NOSET };
+const var_type_def_t IGNORE_type_defn = {
+ .name="Ignored", .fns=&ignore_fns,
+ .flags=CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET,
+};
+const var_type_def_t OBSOLETE_type_defn = {
+ .name="Obsolete", .fns=&ignore_fns,
+ .flags=CFLG_GROUP_OBSOLETE,
+};
+
/**
* Table mapping conf_type_t values to var_type_def_t objects.
**/
-static const var_type_def_t type_definitions_table[] = {
- [CONFIG_TYPE_STRING] = { .name="String", .fns=&string_fns },
- [CONFIG_TYPE_FILENAME] = { .name="Filename", .fns=&string_fns },
- [CONFIG_TYPE_INT] = { .name="SignedInteger", .fns=&int_fns,
- .params=&INT_PARSE_UNRESTRICTED },
- [CONFIG_TYPE_POSINT] = { .name="Integer", .fns=&int_fns,
- .params=&INT_PARSE_POSINT },
- [CONFIG_TYPE_UINT64] = { .name="Integer", .fns=&uint64_fns, },
- [CONFIG_TYPE_MEMUNIT] = { .name="DataSize", .fns=&memunit_fns,
- .params=&memory_units },
- [CONFIG_TYPE_INTERVAL] = { .name="TimeInterval", .fns=&interval_fns,
- .params=&time_units },
- [CONFIG_TYPE_MSEC_INTERVAL] = { .name="TimeMsecInterval",
- .fns=&interval_fns,
- .params=&time_msec_units },
- [CONFIG_TYPE_DOUBLE] = { .name="Float", .fns=&double_fns, },
- [CONFIG_TYPE_BOOL] = { .name="Boolean", .fns=&enum_fns,
- .params=&enum_table_bool },
- [CONFIG_TYPE_AUTOBOOL] = { .name="Boolean+Auto", .fns=&enum_fns,
- .params=&enum_table_autobool },
- [CONFIG_TYPE_ISOTIME] = { .name="Time", .fns=&time_fns, },
- [CONFIG_TYPE_CSV] = { .name="CommaList", .fns=&csv_fns, },
- [CONFIG_TYPE_CSV_INTERVAL] = { .name="TimeInterval",
- .fns=&legacy_csv_interval_fns, },
- [CONFIG_TYPE_LINELIST] = { .name="LineList", .fns=&linelist_fns,
- .flags=CFLG_NOREPLACE },
- /*
- * A "linelist_s" is a derived view of a linelist_v: inspecting
- * it gets part of a linelist_v, and setting it adds to the linelist_v.
- */
- [CONFIG_TYPE_LINELIST_S] = { .name="Dependent", .fns=&linelist_s_fns,
- .flags=CFLG_NOREPLACE|
- /* The operations we disable here are
- * handled by the linelist_v. */
- CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP },
- [CONFIG_TYPE_LINELIST_V] = { .name="Virtual", .fns=&linelist_v_fns,
- .flags=CFLG_NOREPLACE|CFLG_NOSET },
- [CONFIG_TYPE_OBSOLETE] = {
- .name="Obsolete", .fns=&ignore_fns,
- .flags=CFLG_GROUP_OBSOLETE,
- }
+static const var_type_def_t *type_definitions_table[] = {
+ [CONFIG_TYPE_STRING] = &STRING_type_defn,
+ [CONFIG_TYPE_FILENAME] = &FILENAME_type_defn,
+ [CONFIG_TYPE_INT] = &INT_type_defn,
+ [CONFIG_TYPE_POSINT] = &POSINT_type_defn,
+ [CONFIG_TYPE_UINT64] = &UINT64_type_defn,
+ [CONFIG_TYPE_MEMUNIT] = &MEMUNIT_type_defn,
+ [CONFIG_TYPE_INTERVAL] = &INTERVAL_type_defn,
+ [CONFIG_TYPE_MSEC_INTERVAL] = &MSEC_INTERVAL_type_defn,
+ [CONFIG_TYPE_DOUBLE] = &DOUBLE_type_defn,
+ [CONFIG_TYPE_BOOL] = &BOOL_type_defn,
+ [CONFIG_TYPE_AUTOBOOL] = &AUTOBOOL_type_defn,
+ [CONFIG_TYPE_ISOTIME] = &ISOTIME_type_defn,
+ [CONFIG_TYPE_CSV] = &CSV_type_defn,
+ [CONFIG_TYPE_CSV_INTERVAL] = &CSV_INTERVAL_type_defn,
+ [CONFIG_TYPE_LINELIST] = &LINELIST_type_defn,
+ [CONFIG_TYPE_LINELIST_S] = &LINELIST_S_type_defn,
+ [CONFIG_TYPE_LINELIST_V] = &LINELIST_V_type_defn,
+ [CONFIG_TYPE_IGNORE] = &IGNORE_type_defn,
+ [CONFIG_TYPE_OBSOLETE] = &OBSOLETE_type_defn,
};
/**
@@ -787,5 +845,5 @@ lookup_type_def(config_type_t type)
tor_assert(t >= 0);
if (t >= (int)ARRAY_LENGTH(type_definitions_table))
return NULL;
- return &type_definitions_table[t];
+ return type_definitions_table[t];
}
diff --git a/src/lib/confmgt/type_defs.h b/src/lib/confmgt/type_defs.h
index ecf040529e..fec002b1d3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c
index ce11a69379..1955302cdc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -24,6 +24,7 @@
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/malloc/malloc.h"
+#include "lib/string/printf.h"
#include "lib/string/util_string.h"
#include "lib/confmgt/var_type_def_st.h"
@@ -33,8 +34,7 @@
/**
* Try to parse a string in <b>value</b> that encodes an object of the type
- * defined by <b>def</b>. If not NULL, <b>key</b> is the name of the option,
- * which may be used for logging.
+ * defined by <b>def</b>.
*
* On success, adjust the lvalue pointed to by <b>target</b> to hold that
* value, and return 0. On failure, set *<b>errmsg</b> to a newly allocated
@@ -42,7 +42,7 @@
**/
int
typed_var_assign(void *target, const char *value, char **errmsg,
- const var_type_def_t *def, const char *key)
+ const var_type_def_t *def)
{
if (BUG(!def))
return -1; // LCOV_EXCL_LINE
@@ -50,7 +50,7 @@ typed_var_assign(void *target, const char *value, char **errmsg,
typed_var_free(target, def);
tor_assert(def->fns->parse);
- return def->fns->parse(target, value, errmsg, def->params, key);
+ return def->fns->parse(target, value, errmsg, def->params);
}
/**
@@ -76,7 +76,15 @@ typed_var_kvassign(void *target, const config_line_t *line,
return def->fns->kv_parse(target, line, errmsg, def->params);
}
- return typed_var_assign(target, line->value, errmsg, def, line->key);
+ int rv = typed_var_assign(target, line->value, errmsg, def);
+ if (rv < 0 && *errmsg != NULL) {
+ /* typed_var_assign() didn't know the line's keyword, but we do.
+ * Let's add it to the error message. */
+ char *oldmsg = *errmsg;
+ tor_asprintf(errmsg, "Could not parse %s: %s", line->key, oldmsg);
+ tor_free(oldmsg);
+ }
+ return rv;
}
/**
@@ -159,7 +167,7 @@ typed_var_copy(void *dest, const void *src, const var_type_def_t *def)
return 0;
}
char *err = NULL;
- int rv = typed_var_assign(dest, enc, &err, def, NULL);
+ int rv = typed_var_assign(dest, enc, &err, def);
if (BUG(rv < 0)) {
// LCOV_EXCL_START
log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s",
diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h
index 4382613833..cc90ed10a3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,7 +21,7 @@ typedef struct var_type_fns_t var_type_fns_t;
typedef struct var_type_def_t var_type_def_t;
int typed_var_assign(void *target, const char *value, char **errmsg,
- const var_type_def_t *def, const char *key);
+ const var_type_def_t *def);
void typed_var_free(void *target, const var_type_def_t *def);
char *typed_var_encode(const void *value, const var_type_def_t *def);
int typed_var_copy(void *dest, const void *src, const var_type_def_t *def);
diff --git a/src/lib/confmgt/unitparse.c b/src/lib/confmgt/unitparse.c
index c3ed8285a4..99716e8d9d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,13 +13,17 @@
#include "lib/confmgt/unitparse.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
#include "lib/string/parse_int.h"
+#include "lib/string/printf.h"
#include "lib/string/util_string.h"
+#include "lib/intmath/muldiv.h"
#include <string.h>
/** Table to map the names of memory units to the number of bytes they
* contain. */
+// clang-format off
const struct unit_table_t memory_units[] = {
{ "", 1 },
{ "b", 1<< 0 },
@@ -64,9 +68,11 @@ const struct unit_table_t memory_units[] = {
{ "tbit", UINT64_C(1)<<37 },
{ NULL, 0 },
};
+// clang-format on
/** Table to map the names of time units to the number of seconds they
* contain. */
+// clang-format off
const struct unit_table_t time_units[] = {
{ "", 1 },
{ "second", 1 },
@@ -83,9 +89,11 @@ const struct unit_table_t time_units[] = {
{ "months", 2629728, },
{ NULL, 0 },
};
+// clang-format on
/** Table to map the names of time units to the number of milliseconds
* they contain. */
+// clang-format off
const struct unit_table_t time_msec_units[] = {
{ "", 1 },
{ "msec", 1 },
@@ -103,28 +111,37 @@ const struct unit_table_t time_msec_units[] = {
{ "weeks", 7*24*60*60*1000 },
{ NULL, 0 },
};
+// clang-format on
/** Parse a string <b>val</b> containing a number, zero or more
* spaces, and an optional unit string. If the unit appears in the
* table <b>u</b>, then multiply the number by the unit multiplier.
* On success, set *<b>ok</b> to 1 and return this product.
* Otherwise, set *<b>ok</b> to 0.
+ *
+ * If an error (like overflow or a negative value is detected), put an error
+ * message in *<b>errmsg_out</b> if that pointer is non-NULL, and otherwise
+ * log a warning.
*/
uint64_t
-config_parse_units(const char *val, const unit_table_t *u, int *ok)
+config_parse_units(const char *val, const unit_table_t *u, int *ok,
+ char **errmsg_out)
{
uint64_t v = 0;
double d = 0;
int use_float = 0;
char *cp;
+ char *errmsg = NULL;
tor_assert(ok);
v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp);
if (!*ok || (cp && *cp == '.')) {
d = tor_parse_double(val, 0, (double)UINT64_MAX, ok, &cp);
- if (!*ok)
+ if (!*ok) {
+ tor_asprintf(&errmsg, "Unable to parse %s as a number", val);
goto done;
+ }
use_float = 1;
}
@@ -142,18 +159,55 @@ config_parse_units(const char *val, const unit_table_t *u, int *ok)
for ( ;u->unit;++u) {
if (!strcasecmp(u->unit, cp)) {
- if (use_float)
- v = (uint64_t)(u->multiplier * d);
- else
- v *= u->multiplier;
+ if (use_float) {
+ d = u->multiplier * d;
+
+ if (d < 0) {
+ tor_asprintf(&errmsg, "Got a negative value while parsing %s %s",
+ val, u->unit);
+ *ok = 0;
+ goto done;
+ }
+
+ // Some compilers may warn about casting a double to an unsigned type
+ // because they don't know if d is >= 0
+ if (d >= 0 && (d > (double)INT64_MAX || (uint64_t)d > INT64_MAX)) {
+ tor_asprintf(&errmsg, "Overflow while parsing %s %s",
+ val, u->unit);
+ *ok = 0;
+ goto done;
+ }
+
+ v = (uint64_t) d;
+ } else {
+ v = tor_mul_u64_nowrap(v, u->multiplier);
+
+ if (v > INT64_MAX) {
+ tor_asprintf(&errmsg, "Overflow while parsing %s %s",
+ val, u->unit);
+ *ok = 0;
+ goto done;
+ }
+ }
+
*ok = 1;
goto done;
}
}
- log_warn(LD_CONFIG, "Unknown unit '%s'.", cp);
+ tor_asprintf(&errmsg, "Unknown unit in %s", val);
*ok = 0;
done:
+ if (errmsg) {
+ tor_assert_nonfatal(!*ok);
+ if (errmsg_out) {
+ *errmsg_out = errmsg;
+ } else {
+ log_warn(LD_CONFIG, "%s", errmsg);
+ tor_free(errmsg);
+ }
+ }
+
if (*ok)
return v;
else
@@ -167,7 +221,7 @@ config_parse_units(const char *val, const unit_table_t *u, int *ok)
uint64_t
config_parse_memunit(const char *s, int *ok)
{
- uint64_t u = config_parse_units(s, memory_units, ok);
+ uint64_t u = config_parse_units(s, memory_units, ok, NULL);
return u;
}
@@ -179,7 +233,7 @@ int
config_parse_msec_interval(const char *s, int *ok)
{
uint64_t r;
- r = config_parse_units(s, time_msec_units, ok);
+ r = config_parse_units(s, time_msec_units, ok, NULL);
if (r > INT_MAX) {
log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
*ok = 0;
@@ -196,7 +250,7 @@ int
config_parse_interval(const char *s, int *ok)
{
uint64_t r;
- r = config_parse_units(s, time_units, ok);
+ r = config_parse_units(s, time_units, ok, NULL);
if (r > INT_MAX) {
log_warn(LD_CONFIG, "Interval '%s' is too long", s);
*ok = 0;
diff --git a/src/lib/confmgt/unitparse.h b/src/lib/confmgt/unitparse.h
index 216361a7d4..047e11b424 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,7 +25,8 @@ extern const unit_table_t memory_units[];
extern const unit_table_t time_units[];
extern const struct unit_table_t time_msec_units[];
-uint64_t config_parse_units(const char *val, const unit_table_t *u, int *ok);
+uint64_t config_parse_units(const char *val, const unit_table_t *u, int *ok,
+ char **errmsg_out);
uint64_t config_parse_memunit(const char *s, int *ok);
int config_parse_msec_interval(const char *s, int *ok);
diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h
index aa9ded39e9..2519b86aa0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -52,12 +52,9 @@ struct var_type_fns_t {
* type. On success, adjust the lvalue pointed to by <b>target</b> to hold
* that value, and return 0. On failure, set *<b>errmsg</b> to a newly
* allocated string holding an error message, and return -1.
- *
- * If not NULL, <b>key</b> is the name of the option, which may be used for
- * logging.
**/
int (*parse)(void *target, const char *value, char **errmsg,
- const void *params, const char *key);
+ const void *params);
/**
* Try to parse a single line from the head of<b>line</b> that encodes
* an object of this type. On success and failure, behave as in the parse()
diff --git a/src/lib/container/bitarray.h b/src/lib/container/bitarray.h
index 45992796af..41409e350a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 8c61db81d6..34b1265d81 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/bloomfilt.h b/src/lib/container/bloomfilt.h
index 0ce18bd3ec..6d36056b5a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 ca7c94559e..6b1bbd5167 100644
--- a/src/lib/container/handles.h
+++ b/src/lib/container/handles.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,33 +16,33 @@
* To enable a type to have handles, add a HANDLE_ENTRY() field in its
* definition, as in:
*
- * struct walrus {
- * HANDLE_ENTRY(wlr, walrus);
+ * struct walrus_t {
+ * HANDLE_ENTRY(wlr, walrus_t);
* // ...
* };
*
- * And invoke HANDLE_DECL(wlr, walrus, [static]) to declare the handle
+ * And invoke HANDLE_DECL(wlr, walrus_t, [static]) to declare the handle
* manipulation functions (typically in a header):
*
* // opaque handle to walrus.
* typedef struct wlr_handle_t wlr_handle_t;
*
* // make a new handle
- * struct wlr_handle_t *wlr_handle_new(struct walrus *);
+ * struct wlr_handle_t *wlr_handle_new(struct walrus_t *);
*
* // release a handle
* void wlr_handle_free(wlr_handle_t *);
*
* // return the pointed-to walrus, or NULL.
- * struct walrus *wlr_handle_get(wlr_handle_t *).
+ * struct walrus_t *wlr_handle_get(wlr_handle_t *).
*
* // call this function when you're about to free the walrus;
* // it invalidates all handles. (IF YOU DON'T, YOU WILL HAVE
* // DANGLING REFERENCES)
- * void wlr_handles_clear(struct walrus *);
+ * void wlr_handles_clear(struct walrus_t *);
*
* Finally, use HANDLE_IMPL() to define the above functions in some
- * appropriate C file: HANDLE_IMPL(wlr, walrus, [static])
+ * appropriate C file: HANDLE_IMPL(wlr, walrus_t, [static])
*
**/
@@ -57,12 +57,13 @@
#define HANDLE_ENTRY(name, structname) \
struct name ## _handle_head_t *handle_head
-#define HANDLE_DECL(name, structname, linkage) \
+#define HANDLE_DECL(name, structname_t, linkage) \
typedef struct name ## _handle_t name ## _handle_t; \
- linkage name ## _handle_t *name ## _handle_new(struct structname *object); \
+ linkage name ## _handle_t *name ## _handle_new( \
+ struct structname_t *object); \
linkage void name ## _handle_free_(name ## _handle_t *); \
- linkage struct structname *name ## _handle_get(name ## _handle_t *); \
- linkage void name ## _handles_clear(struct structname *object);
+ linkage struct structname_t *name ## _handle_get(name ## _handle_t *); \
+ linkage void name ## _handles_clear(struct structname_t *object);
/*
* Implementation notes: there are lots of possible implementations here. We
diff --git a/src/lib/container/lib_container.md b/src/lib/container/lib_container.md
new file mode 100644
index 0000000000..f4902ca44a
--- /dev/null
+++ b/src/lib/container/lib_container.md
@@ -0,0 +1,49 @@
+@dir /lib/container
+@brief lib/container: Hash tables, dynamic arrays, bit arrays, etc.
+
+### Smartlists: Neither lists, nor especially smart.
+
+For historical reasons, we call our dynamic-allocated array type
+`smartlist_t`. It can grow or shrink as elements are added and removed.
+
+All smartlists hold an array of `void *`. Whenever you expose a smartlist
+in an API you *must* document which types its pointers actually hold.
+
+<!-- It would be neat to fix that, wouldn't it? -NM -->
+
+Smartlists are created empty with `smartlist_new()` and freed with
+`smartlist_free()`. See the `containers.h` header documentation for more
+information; there are many convenience functions for commonly needed
+operations.
+
+For low-level operations on smartlists, see also
+\refdir{lib/smartlist_core}.
+
+<!-- TODO: WRITE more about what you can do with smartlists. -->
+
+### Digest maps, string maps, and more.
+
+Tor makes frequent use of maps from 160-bit digests, 256-bit digests,
+or nul-terminated strings to `void *`. These types are `digestmap_t`,
+`digest256map_t`, and `strmap_t` respectively. See the containers.h
+module documentation for more information.
+
+### Intrusive lists and hashtables
+
+For performance-sensitive cases, we sometimes want to use "intrusive"
+collections: ones where the bookkeeping pointers are stuck inside the
+structures that belong to the collection. If you've used the
+BSD-style sys/queue.h macros, you'll be familiar with these.
+
+Unfortunately, the `sys/queue.h` macros vary significantly between the
+platforms that have them, so we provide our own variants in
+`ext/tor_queue.h`.
+
+We also provide an intrusive hashtable implementation in `ext/ht.h`.
+When you're using it, you'll need to define your own hash
+functions. If attacker-induced collisions are a worry here, use the
+cryptographic siphash24g function to extract hashes.
+
+<!-- TODO: WRITE about bloom filters, namemaps, bit-arrays, order functions.
+-->
+
diff --git a/src/lib/container/map.c b/src/lib/container/map.c
index fde33d6ace..7db84313ea 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -85,21 +85,21 @@ digest256map_entry_hash(const digest256map_entry_t *a)
}
HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
- strmap_entries_eq)
+ strmap_entries_eq);
HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
- strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+ strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
- digestmap_entries_eq)
+ digestmap_entries_eq);
HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
- digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+ digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node,
digest256map_entry_hash,
- digest256map_entries_eq)
+ digest256map_entries_eq);
HT_GENERATE2(digest256map_impl, digest256map_entry_t, node,
digest256map_entry_hash,
- digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+ digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_);
#define strmap_entry_free(ent) \
FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent))
diff --git a/src/lib/container/map.h b/src/lib/container/map.h
index 9da1d3072c..dbc1967247 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_MAP_H
@@ -17,34 +17,35 @@
#include "ext/siphash.h"
-#define DECLARE_MAP_FNS(maptype, keytype, prefix) \
- typedef struct maptype maptype; \
- typedef struct prefix##entry_t *prefix##iter_t; \
- MOCK_DECL(maptype*, prefix##new, (void)); \
- void* prefix##set(maptype *map, keytype key, void *val); \
- void* prefix##get(const maptype *map, keytype key); \
- void* prefix##remove(maptype *map, keytype key); \
- MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \
- int prefix##isempty(const maptype *map); \
- int prefix##size(const maptype *map); \
- prefix##iter_t *prefix##iter_init(maptype *map); \
- prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \
- prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \
- void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \
- int prefix##iter_done(prefix##iter_t *iter); \
- void prefix##assert_ok(const maptype *map)
+#define DECLARE_MAP_FNS(mapname_t, keytype, prefix) \
+ typedef struct mapname_t mapname_t; \
+ typedef struct prefix##_entry_t *prefix##_iter_t; \
+ MOCK_DECL(mapname_t*, prefix##_new, (void)); \
+ void* prefix##_set(mapname_t *map, keytype key, void *val); \
+ void* prefix##_get(const mapname_t *map, keytype key); \
+ void* prefix##_remove(mapname_t *map, keytype key); \
+ MOCK_DECL(void, prefix##_free_, (mapname_t *map, void (*free_val)(void*))); \
+ int prefix##_isempty(const mapname_t *map); \
+ int prefix##_size(const mapname_t *map); \
+ prefix##_iter_t *prefix##_iter_init(mapname_t *map); \
+ prefix##_iter_t *prefix##_iter_next(mapname_t *map, prefix##_iter_t *iter); \
+ prefix##_iter_t *prefix##_iter_next_rmv(mapname_t *map, \
+ prefix##_iter_t *iter); \
+ void prefix##_iter_get(prefix##_iter_t *iter, keytype *keyp, void **valp); \
+ int prefix##_iter_done(prefix##_iter_t *iter); \
+ void prefix##_assert_ok(const mapname_t *map)
/* Map from const char * to void *. Implemented with a hash table. */
-DECLARE_MAP_FNS(strmap_t, const char *, strmap_);
+DECLARE_MAP_FNS(strmap_t, const char *, strmap);
/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */
-DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_);
+DECLARE_MAP_FNS(digestmap_t, const char *, digestmap);
/* Map from const uint8_t[DIGEST256_LEN] to void *. Implemented with a hash
* table. */
-DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
+DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map);
-#define MAP_FREE_AND_NULL(maptype, map, fn) \
+#define MAP_FREE_AND_NULL(mapname_t, map, fn) \
do { \
- maptype ## _free_((map), (fn)); \
+ mapname_t ## _free_((map), (fn)); \
(map) = NULL; \
} while (0)
@@ -55,12 +56,12 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
#undef DECLARE_MAP_FNS
/** Iterates over the key-value pairs in a map <b>map</b> in order.
- * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_).
+ * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap or digestmap).
* The map's keys and values are of type keytype and valtype respectively;
* each iteration assigns them to keyvar and valvar.
*
* Example use:
- * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) {
+ * MAP_FOREACH(digestmap, m, const char *, k, routerinfo_t *, r) {
* // use k and r
* } MAP_FOREACH_END.
*/
@@ -80,21 +81,21 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
*/
#define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \
STMT_BEGIN \
- prefix##iter_t *keyvar##_iter; \
- for (keyvar##_iter = prefix##iter_init(map); \
- !prefix##iter_done(keyvar##_iter); \
- keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \
+ prefix##_iter_t *keyvar##_iter; \
+ for (keyvar##_iter = prefix##_iter_init(map); \
+ !prefix##_iter_done(keyvar##_iter); \
+ keyvar##_iter = prefix##_iter_next(map, keyvar##_iter)) { \
keytype keyvar; \
void *valvar##_voidp; \
valtype valvar; \
- prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \
+ prefix##_iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \
valvar = valvar##_voidp;
/** As MAP_FOREACH, except allows members to be removed from the map
* during the iteration via MAP_DEL_CURRENT. Example use:
*
* Example use:
- * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) {
+ * MAP_FOREACH(digestmap, m, const char *, k, routerinfo_t *, r) {
* if (is_very_old(r))
* MAP_DEL_CURRENT(k);
* } MAP_FOREACH_END.
@@ -120,18 +121,18 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
*/
#define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \
STMT_BEGIN \
- prefix##iter_t *keyvar##_iter; \
+ prefix##_iter_t *keyvar##_iter; \
int keyvar##_del=0; \
- for (keyvar##_iter = prefix##iter_init(map); \
- !prefix##iter_done(keyvar##_iter); \
+ for (keyvar##_iter = prefix##_iter_init(map); \
+ !prefix##_iter_done(keyvar##_iter); \
keyvar##_iter = keyvar##_del ? \
- prefix##iter_next_rmv(map, keyvar##_iter) : \
- prefix##iter_next(map, keyvar##_iter)) { \
+ prefix##_iter_next_rmv(map, keyvar##_iter) : \
+ prefix##_iter_next(map, keyvar##_iter)) { \
keytype keyvar; \
void *valvar##_voidp; \
valtype valvar; \
keyvar##_del=0; \
- prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \
+ prefix##_iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \
valvar = valvar##_voidp;
/** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon
@@ -151,7 +152,7 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
* } DIGESTMAP_FOREACH_END.
*/
#define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \
- MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar)
+ MAP_FOREACH(digestmap, map, const char *, keyvar, valtype, valvar)
/** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or
* keytype.
@@ -162,89 +163,89 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
* } DIGESTMAP_FOREACH_END.
*/
#define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \
- MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar)
+ MAP_FOREACH_MODIFY(digestmap, map, const char *, keyvar, valtype, valvar)
/** Used to end a DIGESTMAP_FOREACH() block. */
#define DIGESTMAP_FOREACH_END MAP_FOREACH_END
#define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \
- MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar)
+ MAP_FOREACH(digest256map, map, const uint8_t *, keyvar, valtype, valvar)
#define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \
- MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \
+ MAP_FOREACH_MODIFY(digest256map, map, const uint8_t *, \
keyvar, valtype, valvar)
#define DIGEST256MAP_FOREACH_END MAP_FOREACH_END
#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \
- MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar)
+ MAP_FOREACH(strmap, map, const char *, keyvar, valtype, valvar)
#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \
- MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar)
+ MAP_FOREACH_MODIFY(strmap, map, const char *, keyvar, valtype, valvar)
#define STRMAP_FOREACH_END MAP_FOREACH_END
void* strmap_set_lc(strmap_t *map, const char *key, void *val);
void* strmap_get_lc(const strmap_t *map, const char *key);
void* strmap_remove_lc(strmap_t *map, const char *key);
-#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \
- typedef struct maptype maptype; \
- typedef struct prefix##iter_t *prefix##iter_t; \
- ATTR_UNUSED static inline maptype* \
- prefix##new(void) \
+#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, mapname_t, valtype) \
+ typedef struct mapname_t mapname_t; \
+ typedef struct prefix##_iter_t *prefix##_iter_t; \
+ ATTR_UNUSED static inline mapname_t* \
+ prefix##_new(void) \
{ \
- return (maptype*)digestmap_new(); \
+ return (mapname_t*)digestmap_new(); \
} \
ATTR_UNUSED static inline digestmap_t* \
- prefix##to_digestmap(maptype *map) \
+ prefix##_to_digestmap(mapname_t *map) \
{ \
return (digestmap_t*)map; \
} \
ATTR_UNUSED static inline valtype* \
- prefix##get(maptype *map, const char *key) \
+ prefix##_get(mapname_t *map, const char *key) \
{ \
return (valtype*)digestmap_get((digestmap_t*)map, key); \
} \
ATTR_UNUSED static inline valtype* \
- prefix##set(maptype *map, const char *key, valtype *val) \
+ prefix##_set(mapname_t *map, const char *key, valtype *val) \
{ \
return (valtype*)digestmap_set((digestmap_t*)map, key, val); \
} \
ATTR_UNUSED static inline valtype* \
- prefix##remove(maptype *map, const char *key) \
+ prefix##_remove(mapname_t *map, const char *key) \
{ \
return (valtype*)digestmap_remove((digestmap_t*)map, key); \
} \
ATTR_UNUSED static inline void \
- prefix##f##ree_(maptype *map, void (*free_val)(void*)) \
+ prefix##_f##ree_(mapname_t *map, void (*free_val)(void*)) \
{ \
digestmap_free_((digestmap_t*)map, free_val); \
} \
ATTR_UNUSED static inline int \
- prefix##isempty(maptype *map) \
+ prefix##_isempty(mapname_t *map) \
{ \
return digestmap_isempty((digestmap_t*)map); \
} \
ATTR_UNUSED static inline int \
- prefix##size(maptype *map) \
+ prefix##_size(mapname_t *map) \
{ \
return digestmap_size((digestmap_t*)map); \
} \
ATTR_UNUSED static inline \
- prefix##iter_t *prefix##iter_init(maptype *map) \
+ prefix##_iter_t *prefix##_iter_init(mapname_t *map) \
{ \
- return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \
+ return (prefix##_iter_t*) digestmap_iter_init((digestmap_t*)map); \
} \
ATTR_UNUSED static inline \
- prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \
+ prefix##_iter_t *prefix##_iter_next(mapname_t *map, prefix##_iter_t *iter) \
{ \
- return (prefix##iter_t*) digestmap_iter_next( \
+ return (prefix##_iter_t*) digestmap_iter_next( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
- ATTR_UNUSED static inline prefix##iter_t* \
- prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \
+ ATTR_UNUSED static inline prefix##_iter_t* \
+ prefix##_iter_next_rmv(mapname_t *map, prefix##_iter_t *iter) \
{ \
- return (prefix##iter_t*) digestmap_iter_next_rmv( \
+ return (prefix##_iter_t*) digestmap_iter_next_rmv( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
ATTR_UNUSED static inline void \
- prefix##iter_get(prefix##iter_t *iter, \
+ prefix##_iter_get(prefix##_iter_t *iter, \
const char **keyp, \
valtype **valp) \
{ \
@@ -253,7 +254,7 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
*valp = v; \
} \
ATTR_UNUSED static inline int \
- prefix##iter_done(prefix##iter_t *iter) \
+ prefix##_iter_done(prefix##_iter_t *iter) \
{ \
return digestmap_iter_done((digestmap_iter_t*)iter); \
}
diff --git a/src/lib/container/namemap.c b/src/lib/container/namemap.c
index a90057b32c..e286cad947 100644
--- a/src/lib/container/namemap.c
+++ b/src/lib/container/namemap.c
@@ -1,8 +1,13 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file namemap.c
+ * @brief Mappings between identifiers and 16-bit ints.
+ **/
+
#include "orconfig.h"
#include "lib/container/smartlist.h"
#include "lib/container/namemap.h"
@@ -30,9 +35,9 @@ mapped_name_hash(const mapped_name_t *a)
}
HT_PROTOTYPE(namemap_ht, mapped_name_t, node, mapped_name_hash,
- mapped_name_eq)
+ mapped_name_eq);
HT_GENERATE2(namemap_ht, mapped_name_t, node, mapped_name_hash,
- mapped_name_eq, 0.6, tor_reallocarray_, tor_free_)
+ mapped_name_eq, 0.6, tor_reallocarray_, tor_free_);
/** Set up an uninitialized <b>map</b>. */
void
diff --git a/src/lib/container/namemap.h b/src/lib/container/namemap.h
index b96bc13f3a..b451c18c68 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 5008fd5855..39aa85cc09 100644
--- a/src/lib/container/namemap_st.h
+++ b/src/lib/container/namemap_st.h
@@ -1,11 +1,16 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef NAMEMAP_ST_H
#define NAMEMAP_ST_H
+/**
+ * @file namemap_st.h
+ * @brief Internal declarations for namemap structure.
+ **/
+
#include "lib/cc/compat_compiler.h"
#include "ext/ht.h"
@@ -28,7 +33,9 @@ struct namemap_t {
struct smartlist_t *names;
};
+#ifndef COCCI
/** Macro to initialize a namemap. */
#define NAMEMAP_INIT() { HT_INITIALIZER(), NULL }
+#endif
#endif /* !defined(NAMEMAP_ST_H) */
diff --git a/src/lib/container/order.c b/src/lib/container/order.c
index f6503a124e..cac241f027 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/order.h b/src/lib/container/order.h
index 3f2fd054a0..5bca095f35 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 2b71c11287..7784f83957 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -652,7 +652,7 @@ smartlist_sort_pointers(smartlist_t *sl)
#define LEFT_CHILD(i) ( 2*(i) + 1 )
#define RIGHT_CHILD(i) ( 2*(i) + 2 )
#define PARENT(i) ( ((i)-1) / 2 )
-/** }@ */
+/** @} */
/** @{ */
/** Helper macros for heaps: Given a local variable <b>idx_field_offset</b>
diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h
index 25638e4b22..458d564cd5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_SMARTLIST_H
@@ -92,6 +92,7 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
size_t join_len, int terminate, size_t *len_out)
ATTR_MALLOC;
+#ifndef COCCI
/* Helper: Given two lists of items, possibly of different types, such that
* both lists are sorted on some common field (as determined by a comparison
* expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no
@@ -165,5 +166,6 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \
} \
STMT_END
+#endif /* !defined(COCCI) */
#endif /* !defined(TOR_SMARTLIST_H) */
diff --git a/src/lib/crypt_ops/.may_include b/src/lib/crypt_ops/.may_include
index 0739699686..810e777271 100644
--- a/src/lib/crypt_ops/.may_include
+++ b/src/lib/crypt_ops/.may_include
@@ -1,6 +1,7 @@
orconfig.h
lib/arch/*.h
lib/cc/*.h
+lib/conf/*.h
lib/container/*.h
lib/crypt_ops/*.h
lib/ctime/*.h
@@ -17,6 +18,8 @@ lib/testsupport/*.h
lib/thread/*.h
lib/log/*.h
+lib/crypt_ops/*.inc
+
trunnel/pwbox.h
keccak-tiny/*.h
diff --git a/src/lib/crypt_ops/aes.h b/src/lib/crypt_ops/aes.h
index 7c774062d9..c25417b4e6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Implements a minimal interface to counter-mode AES. */
@@ -16,7 +16,7 @@
#include "lib/cc/torint.h"
#include "lib/malloc/malloc.h"
-typedef struct aes_cnt_cipher aes_cnt_cipher_t;
+typedef struct aes_cnt_cipher_t aes_cnt_cipher_t;
aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv,
int key_bits);
diff --git a/src/lib/crypt_ops/aes_nss.c b/src/lib/crypt_ops/aes_nss.c
index 4eda5e5902..71d2f01449 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,10 +15,10 @@
#include "lib/crypt_ops/crypto_util.h"
#include "lib/log/util_bug.h"
-DISABLE_GCC_WARNING(strict-prototypes)
+DISABLE_GCC_WARNING("-Wstrict-prototypes")
#include <pk11pub.h>
#include <secerr.h>
-ENABLE_GCC_WARNING(strict-prototypes)
+ENABLE_GCC_WARNING("-Wstrict-prototypes")
aes_cnt_cipher_t *
aes_new_cipher(const uint8_t *key, const uint8_t *iv,
diff --git a/src/lib/crypt_ops/aes_openssl.c b/src/lib/crypt_ops/aes_openssl.c
index 64564892ad..502f7703bd 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,7 +28,7 @@
#error "We require OpenSSL >= 1.0.0"
#endif
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <stdlib.h>
#include <string.h>
@@ -37,9 +37,8 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/engine.h>
#include <openssl/modes.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
-#include "lib/crypt_ops/aes.h"
#include "lib/log/log.h"
#include "lib/ctime/di_ops.h"
@@ -154,7 +153,7 @@ evaluate_ctr_for_aes(void)
/* Interface to AES code, and counter implementation */
/** Implements an AES counter-mode cipher. */
-struct aes_cnt_cipher {
+struct aes_cnt_cipher_t {
/** This next element (however it's defined) is the AES key. */
union {
EVP_CIPHER_CTX evp;
diff --git a/src/lib/crypt_ops/certs.md b/src/lib/crypt_ops/certs.md
new file mode 100644
index 0000000000..f3bd8c2c96
--- /dev/null
+++ b/src/lib/crypt_ops/certs.md
@@ -0,0 +1,29 @@
+
+@page certificates Certificates in Tor
+
+We have, alas, several certificate types in Tor.
+
+The tor_x509_cert_t type represents an X.509 certificate. This document
+won't explain X.509 to you -- possibly, no document can. (OTOH, Peter
+Gutmann's "x.509 style guide", though severely dated, does a good job of
+explaining how awful x.509 can be.) Do not introduce any new usages of
+X.509. Right now we only use it in places where TLS forces us to do so.
+See x509.c for more information about using this type.
+
+
+The authority_cert_t type is used only for directory authority keys. It
+has a medium-term signing key (which the authorities actually keep
+online) signed by a long-term identity key (which the authority operator
+had really better be keeping offline). Don't use it for any new kind of
+certificate.
+
+For new places where you need a certificate, consider tor_cert_t: it
+represents a typed and dated _something_ signed by an Ed25519 key. The
+format is described in tor-spec. Unlike x.509, you can write it on a
+napkin. The torcert.c file is used for manipulating these certificates and
+their associated keys.
+
+(Additionally, the Tor directory design uses a fairly wide variety of
+documents that include keys and which are signed by keys. You can
+consider these documents to be an additional kind of certificate if you
+want.)
diff --git a/src/lib/crypt_ops/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h
index 61ca51315f..5fd073bea1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 7bc2edad54..0a24a580ae 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 88d63c1df2..1e22a7c138 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,7 +25,7 @@
/** Length of our symmetric cipher's keys of 256-bit. */
#define CIPHER256_KEY_LEN 32
-typedef struct aes_cnt_cipher crypto_cipher_t;
+typedef struct aes_cnt_cipher_t crypto_cipher_t;
/* environment setup */
crypto_cipher_t *crypto_cipher_new(const char *key);
diff --git a/src/lib/crypt_ops/crypto_curve25519.c b/src/lib/crypt_ops/crypto_curve25519.c
index de4e17a296..2a2589f07d 100644
--- a/src/lib/crypt_ops/crypto_curve25519.c
+++ b/src/lib/crypt_ops/crypto_curve25519.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, 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 cd23169cd5..154a0b94bc 100644
--- a/src/lib/crypt_ops/crypto_curve25519.h
+++ b/src/lib/crypt_ops/crypto_curve25519.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, 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 4be7948761..086aceed6f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 850d50c7ae..2a0e1f6912 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 379eb84a4f..018db8bf43 100644
--- a/src/lib/crypt_ops/crypto_dh_nss.c
+++ b/src/lib/crypt_ops/crypto_dh_nss.c
@@ -1,11 +1,11 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file crypto_dh_nss.h
+ * \file crypto_dh_nss.c
*
* \brief NSS implementation of Diffie-Hellman over Z_p.
**/
diff --git a/src/lib/crypt_ops/crypto_dh_openssl.c b/src/lib/crypt_ops/crypto_dh_openssl.c
index 8ae97373e8..c5f7271596 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,11 +17,11 @@
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/dh.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/bn.h>
#include <string.h>
@@ -103,7 +103,7 @@ crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g)
#endif /* 0 */
/**
- * Helper: convert <b>hex<b> to a bignum, and return it. Assert that the
+ * Helper: convert <b>hex</b> to a bignum, and return it. Assert that the
* operation was successful.
*/
static BIGNUM *
diff --git a/src/lib/crypt_ops/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c
index ba226f8756..7775e69410 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -150,6 +150,9 @@ struct crypto_xof_t {
*/
EVP_MD_CTX *ctx;
#else /* !defined(OPENSSL_HAS_SHAKE3_EVP) */
+ /**
+ * State of the Keccak sponge for the SHAKE-256 computation.
+ **/
keccak_state s;
#endif /* defined(OPENSSL_HAS_SHAKE3_EVP) */
};
diff --git a/src/lib/crypt_ops/crypto_digest.h b/src/lib/crypt_ops/crypto_digest.h
index 5869db7800..eefd2e3f0a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -38,6 +38,9 @@
/** Length of hex encoding of SHA512 digest, not including final NUL. */
#define HEX_DIGEST512_LEN 128
+/**
+ * An identifier for a cryptographic digest algorithm.
+ **/
typedef enum {
DIGEST_SHA1 = 0,
DIGEST_SHA256 = 1,
@@ -45,16 +48,31 @@ typedef enum {
DIGEST_SHA3_256 = 3,
DIGEST_SHA3_512 = 4,
} digest_algorithm_t;
+/** Number of digest algorithms that we know */
#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1)
+/** Number of digest algorithms to compute when computing "all the
+ * commonly used digests."
+ *
+ * (This is used in common_digests_t and related functions.)
+ */
#define N_COMMON_DIGEST_ALGORITHMS (DIGEST_SHA256+1)
+/**
+ * Bytes of storage needed to record the state of an in-progress SHA-1 digest.
+ *
+ * This is a deliberate overestimate.
+ **/
#define DIGEST_CHECKPOINT_BYTES (SIZEOF_VOID_P + 512)
+
/** Structure used to temporarily save the a digest object. Only implemented
* for SHA1 digest for now. */
typedef struct crypto_digest_checkpoint_t {
#ifdef ENABLE_NSS
+ /** The number of bytes used in <b>mem</b>. */
unsigned int bytes_used;
#endif
+ /** A buffer to store the SHA1 state. Its contents are unspecified, and
+ * are managed by the underlying crypto library.*/
uint8_t mem[DIGEST_CHECKPOINT_BYTES];
} crypto_digest_checkpoint_t;
@@ -67,10 +85,19 @@ typedef struct crypto_digest_checkpoint_t {
* once.
**/
typedef struct {
+ /** An array of digest outputs, one for each "common" digest algorithm. */
char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN];
} common_digests_t;
+/**
+ * State for computing a digest over a stream of data.
+ **/
typedef struct crypto_digest_t crypto_digest_t;
+
+/**
+ * State for computing an "extendable-output function" (like SHAKE) over a
+ * stream of data, and/or streaming the output.
+ **/
typedef struct crypto_xof_t crypto_xof_t;
struct smartlist_t;
@@ -97,6 +124,9 @@ crypto_digest_t *crypto_digest_new(void);
crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm);
void crypto_digest_free_(crypto_digest_t *digest);
+/**
+ * Release all storage held in <b>d</b>, and set it to NULL.
+ **/
#define crypto_digest_free(d) \
FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d))
void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
@@ -122,6 +152,9 @@ crypto_xof_t *crypto_xof_new(void);
void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len);
void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len);
void crypto_xof_free_(crypto_xof_t *xof);
+/**
+ * Release all storage held in <b>xof</b>, and set it to NULL.
+ **/
#define crypto_xof_free(xof) \
FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof))
void crypto_xof(uint8_t *output, size_t output_len,
diff --git a/src/lib/crypt_ops/crypto_digest_nss.c b/src/lib/crypt_ops/crypto_digest_nss.c
index afa8f6d5ef..92c20fe9e8 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,9 +23,9 @@
#include "lib/arch/bytes.h"
-DISABLE_GCC_WARNING(strict-prototypes)
+DISABLE_GCC_WARNING("-Wstrict-prototypes")
#include <pk11pub.h>
-ENABLE_GCC_WARNING(strict-prototypes)
+ENABLE_GCC_WARNING("-Wstrict-prototypes")
/**
* Convert a digest_algorithm_t (used by tor) to a HashType (used by NSS).
@@ -44,7 +44,11 @@ digest_alg_to_nss_oid(digest_algorithm_t alg)
}
}
-/* Helper: get an unkeyed digest via pk11wrap */
+/** Helper: Compute an unkeyed digest of the <b>msg_len</b> bytes at
+ * <b>msg</b>, using the digest algorithm specified by <b>alg</b>.
+ * Store the result in the <b>len_out</b>-byte buffer at <b>digest</b>.
+ * Return the number of bytes written on success, and -1 on failure.
+ **/
static int
digest_nss_internal(SECOidTag alg,
char *digest, unsigned len_out,
diff --git a/src/lib/crypt_ops/crypto_digest_openssl.c b/src/lib/crypt_ops/crypto_digest_openssl.c
index 50a8ff4d27..11189c7fb2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,12 +25,12 @@
#include "lib/crypt_ops/crypto_openssl_mgt.h"
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/hmac.h>
#include <openssl/sha.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
/* Crypto digest functions */
@@ -147,9 +147,9 @@ crypto_digest_get_algorithm(crypto_digest_t *digest)
static size_t
crypto_digest_alloc_bytes(digest_algorithm_t alg)
{
- /* Helper: returns the number of bytes in the 'f' field of 'st' */
+ /** Helper: returns the number of bytes in the 'f' field of 'st' */
#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
- /* Gives the length of crypto_digest_t through the end of the field 'd' */
+ /** Gives the length of crypto_digest_t through the end of the field 'd' */
#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
STRUCT_FIELD_SIZE(crypto_digest_t, f))
switch (alg) {
@@ -519,4 +519,3 @@ crypto_hmac_sha256(char *hmac_out,
(unsigned char*)hmac_out, NULL);
tor_assert(rv);
}
-
diff --git a/src/lib/crypt_ops/crypto_ed25519.c b/src/lib/crypt_ops/crypto_ed25519.c
index c28111a5a5..f242c7011e 100644
--- a/src/lib/crypt_ops/crypto_ed25519.c
+++ b/src/lib/crypt_ops/crypto_ed25519.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, 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 325b28244d..346de464e3 100644
--- a/src/lib/crypt_ops/crypto_ed25519.h
+++ b/src/lib/crypt_ops/crypto_ed25519.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, 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 118cd79045..92b8b9372e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 b4b3aa189c..91da137e1c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e0d241d4ea..7b02820087 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 2994d18e3d..404f548774 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 a16bf4e11a..a836bd8645 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,6 +23,9 @@
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_sys.h"
+#include "lib/crypt_ops/crypto_options_st.h"
+#include "lib/conf/conftypes.h"
+#include "lib/log/util_bug.h"
#include "lib/subsys/subsys.h"
@@ -252,8 +255,69 @@ subsys_crypto_thread_cleanup(void)
crypto_thread_cleanup();
}
+/** Magic number for crypto_options_t. */
+#define CRYPTO_OPTIONS_MAGIC 0x68757368
+
+/**
+ * Return 0 if <b>arg</b> is a valid crypto_options_t. Otherwise return -1
+ * and set *<b>msg_out</b> to a freshly allocated error string.
+ **/
+static int
+crypto_options_validate(const void *arg, char **msg_out)
+{
+ const crypto_options_t *opt = arg;
+ tor_assert(opt->magic == CRYPTO_OPTIONS_MAGIC);
+ tor_assert(msg_out);
+
+ if (opt->AccelDir && !opt->AccelName) {
+ *msg_out = tor_strdup("Can't use hardware crypto accelerator dir "
+ "without engine name.");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Declare the options field table for crypto_options */
+#define CONF_CONTEXT LL_TABLE
+#include "lib/crypt_ops/crypto_options.inc"
+#undef CONF_CONTEXT
+
+/**
+ * Declares the configuration options for this module.
+ **/
+static const config_format_t crypto_options_fmt = {
+ .size = sizeof(crypto_options_t),
+ .magic = { "crypto_options_t",
+ CRYPTO_OPTIONS_MAGIC,
+ offsetof(crypto_options_t, magic) },
+ .vars = crypto_options_t_vars,
+ .validate_fn = crypto_options_validate,
+};
+
+/**
+ * Invoked from subsysmgr.c when a new set of options arrives.
+ **/
+static int
+crypto_set_options(void *arg)
+{
+ const crypto_options_t *options = arg;
+ const bool hardware_accel = options->HardwareAccel || options->AccelName;
+
+ // This call already checks for crypto_global_initialized_, so it
+ // will only initialize the subsystem the first time it's called.
+ if (crypto_global_init(hardware_accel,
+ options->AccelName,
+ options->AccelDir)) {
+ log_err(LD_BUG, "Unable to initialize the crypto subsystem. Exiting.");
+ return -1;
+ }
+ return 0;
+}
+
const struct subsys_fns_t sys_crypto = {
.name = "crypto",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = -60,
.initialize = subsys_crypto_initialize,
@@ -261,4 +325,7 @@ const struct subsys_fns_t sys_crypto = {
.prefork = subsys_crypto_prefork,
.postfork = subsys_crypto_postfork,
.thread_cleanup = subsys_crypto_thread_cleanup,
+
+ .options_format = &crypto_options_fmt,
+ .set_options = crypto_set_options,
};
diff --git a/src/lib/crypt_ops/crypto_init.h b/src/lib/crypt_ops/crypto_init.h
index 8de3eb03ed..b11e2e34bf 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 0179126e38..d82e51249c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,7 +16,7 @@
#include "lib/log/util_bug.h"
#include "lib/string/printf.h"
-DISABLE_GCC_WARNING(strict-prototypes)
+DISABLE_GCC_WARNING("-Wstrict-prototypes")
#include <nss.h>
#include <pk11func.h>
#include <ssl.h>
@@ -24,7 +24,7 @@ DISABLE_GCC_WARNING(strict-prototypes)
#include <prerror.h>
#include <prtypes.h>
#include <prinit.h>
-ENABLE_GCC_WARNING(strict-prototypes)
+ENABLE_GCC_WARNING("-Wstrict-prototypes")
const char *
crypto_nss_get_version_str(void)
diff --git a/src/lib/crypt_ops/crypto_nss_mgt.h b/src/lib/crypt_ops/crypto_nss_mgt.h
index 4cfa9b42a4..8686b1b8aa 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 ed832d852e..4cacb3dd98 100644
--- a/src/lib/crypt_ops/crypto_ope.c
+++ b/src/lib/crypt_ops/crypto_ope.c
@@ -1,8 +1,9 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * A rudimentary order-preserving encryption scheme.
+ * @file crypto_ope.c
+ * @brief A rudimentary order-preserving encryption scheme.
*
* To compute the encryption of N, this scheme uses an AES-CTR stream to
* generate M-byte values, and adds the first N of them together. (+1 each to
@@ -143,7 +144,7 @@ crypto_ope_new(const uint8_t *key)
return ope;
}
-/** Free all storage held in <>ope</b>. */
+/** Free all storage held in <b>ope</b>. */
void
crypto_ope_free_(crypto_ope_t *ope)
{
diff --git a/src/lib/crypt_ops/crypto_ope.h b/src/lib/crypt_ops/crypto_ope.h
index 9778dfe0f0..7498ea6a2e 100644
--- a/src/lib/crypt_ops/crypto_ope.h
+++ b/src/lib/crypt_ops/crypto_ope.h
@@ -1,6 +1,11 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file crypto_ope.h
+ * @brief header for crypto_ope.c
+ **/
+
#ifndef CRYPTO_OPE_H
#define CRYPTO_OPE_H
@@ -37,10 +42,10 @@ void crypto_ope_free_(crypto_ope_t *ope);
uint64_t crypto_ope_encrypt(const crypto_ope_t *ope, int plaintext);
#ifdef CRYPTO_OPE_PRIVATE
-struct aes_cnt_cipher;
-STATIC struct aes_cnt_cipher *ope_get_cipher(const crypto_ope_t *ope,
+struct aes_cnt_cipher_t;
+STATIC struct aes_cnt_cipher_t *ope_get_cipher(const crypto_ope_t *ope,
uint32_t initial_idx);
-STATIC uint64_t sum_values_from_cipher(struct aes_cnt_cipher *c, size_t n);
+STATIC uint64_t sum_values_from_cipher(struct aes_cnt_cipher_t *c, size_t n);
#endif /* defined(CRYPTO_OPE_PRIVATE) */
#endif /* !defined(CRYPTO_OPE_H) */
diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c
index f51309219a..f2f5a55d05 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,7 +21,7 @@
#include "lib/testsupport/testsupport.h"
#include "lib/thread/threads.h"
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/err.h>
#include <openssl/rsa.h>
@@ -36,7 +36,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/crypto.h>
#include <openssl/ssl.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#include <string.h>
@@ -121,10 +121,12 @@ crypto_openssl_get_header_version_str(void)
return crypto_openssl_header_version_str;
}
+#ifndef COCCI
#ifndef OPENSSL_THREADS
-#error OpenSSL has been built without thread support. Tor requires an \
- OpenSSL library with thread support enabled.
+#error "OpenSSL has been built without thread support. Tor requires an \
+ OpenSSL library with thread support enabled."
#endif
+#endif /* !defined(COCCI) */
#ifndef NEW_THREAD_API
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
@@ -273,8 +275,14 @@ log_engine(const char *fn, ENGINE *e)
}
#endif /* !defined(DISABLE_ENGINES) */
-/** Initialize engines for openssl (if enabled). */
-static void
+/** Initialize engines for openssl (if enabled). Load all the built-in
+ * engines, along with the one called <b>accelName</b> (which may be NULL).
+ * If <b>accelName</b> is prefixed with "!", then it is required: return -1
+ * if it can't be loaded. Otherwise return 0.
+ *
+ * If <b>accelDir</b> is not NULL, it is the path from which the engine should
+ * be loaded. */
+static int
crypto_openssl_init_engines(const char *accelName,
const char *accelDir)
{
@@ -282,7 +290,13 @@ crypto_openssl_init_engines(const char *accelName,
(void)accelName;
(void)accelDir;
log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled.");
-#else
+ if (accelName && accelName[0] == '!') {
+ log_warn(LD_CRYPTO, "Unable to load required dynamic OpenSSL engine "
+ "\"%s\".", accelName+1);
+ return -1;
+ }
+ return 0;
+#else /* !defined(DISABLE_ENGINES) */
ENGINE *e = NULL;
log_info(LD_CRYPTO, "Initializing OpenSSL engine support.");
@@ -290,6 +304,9 @@ crypto_openssl_init_engines(const char *accelName,
ENGINE_register_all_complete();
if (accelName) {
+ const bool required = accelName[0] == '!';
+ if (required)
+ ++accelName;
if (accelDir) {
log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\""
" via path \"%s\".", accelName, accelDir);
@@ -300,8 +317,11 @@ crypto_openssl_init_engines(const char *accelName,
e = ENGINE_by_id(accelName);
}
if (!e) {
- log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".",
+ log_warn(LD_CRYPTO, "Unable to load %sdynamic OpenSSL engine \"%s\".",
+ required?"required ":"",
accelName);
+ if (required)
+ return -1;
} else {
log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".",
accelName);
@@ -338,6 +358,7 @@ crypto_openssl_init_engines(const char *accelName,
#ifdef NID_aes_256_gcm
log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm));
#endif
+ return 0;
#endif /* defined(DISABLE_ENGINES) */
}
@@ -348,7 +369,8 @@ crypto_openssl_late_init(int useAccel, const char *accelName,
const char *accelDir)
{
if (useAccel > 0) {
- crypto_openssl_init_engines(accelName, accelDir);
+ if (crypto_openssl_init_engines(accelName, accelDir) < 0)
+ return -1;
} else {
log_info(LD_CRYPTO, "NOT using OpenSSL engine support.");
}
@@ -377,7 +399,7 @@ crypto_openssl_thread_cleanup(void)
void
crypto_openssl_global_cleanup(void)
{
- #ifndef OPENSSL_1_1_API
+#ifndef OPENSSL_1_1_API
EVP_cleanup();
#endif
#ifndef NEW_THREAD_API
diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h
index 111a2d12ed..083df00033 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_options.inc b/src/lib/crypt_ops/crypto_options.inc
new file mode 100644
index 0000000000..5bee0daacd
--- /dev/null
+++ b/src/lib/crypt_ops/crypto_options.inc
@@ -0,0 +1,19 @@
+
+/**
+ * @file crypto_options.inc
+ * @brief Declare configuration options for the crypto_ops module.
+ **/
+
+/** Holds configuration about our cryptography options. */
+BEGIN_CONF_STRUCT(crypto_options_t)
+
+/** Should we enable extra OpenSSL hardware acceleration (where available)? */
+CONF_VAR(HardwareAccel, BOOL, CFLG_IMMUTABLE, "0")
+
+/** Optional OpenSSL hardware-acceleration engine name */
+CONF_VAR(AccelName, STRING, CFLG_IMMUTABLE, NULL)
+
+/** Optional OpenSSL hardware-acceleration engine search directory. */
+CONF_VAR(AccelDir, FILENAME, CFLG_IMMUTABLE, NULL)
+
+END_CONF_STRUCT(crypto_options_t)
diff --git a/src/lib/crypt_ops/crypto_options_st.h b/src/lib/crypt_ops/crypto_options_st.h
new file mode 100644
index 0000000000..a453c451fe
--- /dev/null
+++ b/src/lib/crypt_ops/crypto_options_st.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file crypto_options_st.h
+ * @brief Header for lib/crypt_ops/crypto_options_st.c
+ **/
+
+#ifndef TOR_LIB_CRYPT_OPS_CRYPTO_OPTIONS_ST_H
+#define TOR_LIB_CRYPT_OPS_CRYPTO_OPTIONS_ST_H
+
+#include "lib/conf/confdecl.h"
+
+#define CONF_CONTEXT STRUCT
+#include "lib/crypt_ops/crypto_options.inc"
+#undef CONF_CONTEXT
+
+typedef struct crypto_options_t crypto_options_t;
+
+#endif /* !defined(TOR_LIB_CRYPT_OPS_CRYPTO_OPTIONS_ST_H) */
diff --git a/src/lib/crypt_ops/crypto_pwbox.c b/src/lib/crypt_ops/crypto_pwbox.c
index a8db08f7b7..bfad27d9fc 100644
--- a/src/lib/crypt_ops/crypto_pwbox.c
+++ b/src/lib/crypt_ops/crypto_pwbox.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, 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 5a26889fb2..0a85b1230a 100644
--- a/src/lib/crypt_ops/crypto_pwbox.h
+++ b/src/lib/crypt_ops/crypto_pwbox.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, 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 afbafbfa35..ac5f10da64 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -43,10 +43,10 @@
#endif
#ifdef ENABLE_OPENSSL
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/rand.h>
#include <openssl/sha.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#endif /* defined(ENABLE_OPENSSL) */
#ifdef ENABLE_NSS
diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h
index a019287aa9..99aff5d4a9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e6ceb42ccb..172ea48bdb 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -32,7 +32,6 @@
* request.
*/
-#define CRYPTO_RAND_FAST_PRIVATE
#define CRYPTO_PRIVATE
#include "lib/crypt_ops/crypto_rand.h"
@@ -102,16 +101,16 @@ struct crypto_fast_rng_t {
* crypto_strongest_rand().
*/
int16_t n_till_reseed;
- /** How many bytes are remaining in cbuf.bytes? */
+ /** How many bytes are remaining in cbuf_t.bytes? */
uint16_t bytes_left;
#ifdef CHECK_PID
/** Which process owns this fast_rng? If this value is zero, we do not
* need to test the owner. */
pid_t owner;
#endif
- struct cbuf {
+ struct cbuf_t {
/** The seed (key and IV) that we will use the next time that we refill
- * cbuf. */
+ * cbuf_t. */
uint8_t seed[SEED_LEN];
/**
* Bytes that we are yielding to the user. The next byte to be
@@ -122,9 +121,9 @@ struct crypto_fast_rng_t {
} buf;
};
-/* alignof(uint8_t) should be 1, so there shouldn't be any padding in cbuf.
+/* alignof(uint8_t) should be 1, so there shouldn't be any padding in cbuf_t.
*/
-CTASSERT(sizeof(struct cbuf) == BUFLEN+SEED_LEN);
+CTASSERT(sizeof(struct cbuf_t) == BUFLEN+SEED_LEN);
/* We're trying to fit all of the RNG state into a nice mmapable chunk.
*/
CTASSERT(sizeof(crypto_fast_rng_t) <= MAPLEN);
diff --git a/src/lib/crypt_ops/crypto_rand_numeric.c b/src/lib/crypt_ops/crypto_rand_numeric.c
index ffbfa2d56c..b2516c4bdc 100644
--- a/src/lib/crypt_ops/crypto_rand_numeric.c
+++ b/src/lib/crypt_ops/crypto_rand_numeric.c
@@ -33,8 +33,8 @@
/**
* Return a pseudorandom integer chosen uniformly from the values between 0
- * and <b>limit</b>-1 inclusive. limit must be strictly between 0 and
- * UINT_MAX. */
+ * and <b>limit</b>-1 inclusive. limit must be strictly greater than 0, and
+ * less than UINT_MAX. */
unsigned
crypto_rand_uint(unsigned limit)
{
diff --git a/src/lib/crypt_ops/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c
index 1289a82e62..195e4bbaf9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 01e6d10906..ab2e9db80d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 fd8fda486e..66f325e868 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -645,7 +645,7 @@ crypto_pk_asn1_decode(const char *str, size_t len)
return result;
}
-DISABLE_GCC_WARNING(unused-parameter)
+DISABLE_GCC_WARNING("-Wunused-parameter")
/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the Base64
* encoding of the DER representation of the private key into the
diff --git a/src/lib/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c
index 41d936d25b..c96ee81fd3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,7 +16,7 @@
#include "lib/log/util_bug.h"
#include "lib/fs/files.h"
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/err.h>
#include <openssl/rsa.h>
@@ -27,7 +27,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/bn.h>
#include <openssl/conf.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#include "lib/log/log.h"
#include "lib/encoding/binascii.h"
@@ -583,15 +583,15 @@ rsa_private_key_too_long(RSA *rsa, int max_bits)
dmp1 = RSA_get0_dmp1(rsa);
dmq1 = RSA_get0_dmq1(rsa);
iqmp = RSA_get0_iqmp(rsa);
-#else
+#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1)) */
/* The accessors above did not exist in openssl 1.1.0. */
p = q = dmp1 = dmq1 = iqmp = NULL;
RSA_get0_key(rsa, &n, &e, &d);
-#endif
+#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1) */
if (RSA_bits(rsa) > max_bits)
return true;
-#else
+#else /* !defined(OPENSSL_1_1_API) */
n = rsa->n;
e = rsa->e;
p = rsa->p;
@@ -600,7 +600,7 @@ rsa_private_key_too_long(RSA *rsa, int max_bits)
dmp1 = rsa->dmp1;
dmq1 = rsa->dmq1;
iqmp = rsa->iqmp;
-#endif
+#endif /* defined(OPENSSL_1_1_API) */
if (n && BN_num_bits(n) > max_bits)
return true;
diff --git a/src/lib/crypt_ops/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c
index 361db18927..3a9ed5ef58 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -380,7 +380,7 @@ secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len,
#ifndef HAVE_SCRYPT
if (type == S2K_TYPE_SCRYPT)
return S2K_NO_SCRYPT_SUPPORT;
- #endif
+#endif
if (! legacy_format) {
++spec;
diff --git a/src/lib/crypt_ops/crypto_s2k.h b/src/lib/crypt_ops/crypto_s2k.h
index a16a3d781e..181a17acb1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 894243b175..2115d4fc99 100644
--- a/src/lib/crypt_ops/crypto_sys.h
+++ b/src/lib/crypt_ops/crypto_sys.h
@@ -1,8 +1,8 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file log_crypto.h
+ * \file crypto_sys.h
* \brief Declare subsystem object for the crypto module.
**/
diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c
index 5e3f4a87a1..7ebb860d09 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,8 +10,6 @@
* \brief Common cryptographic utilities.
**/
-#define CRYPTO_UTIL_PRIVATE
-
#include "lib/crypt_ops/crypto_util.h"
#include "lib/cc/compat_compiler.h"
@@ -26,10 +24,10 @@
#include <stdlib.h>
#ifdef ENABLE_OPENSSL
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/err.h>
#include <openssl/crypto.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#endif /* defined(ENABLE_OPENSSL) */
#include "lib/log/log.h"
@@ -109,3 +107,17 @@ memwipe(void *mem, uint8_t byte, size_t sz)
**/
memset(mem, byte, sz);
}
+
+/**
+ * Securely all memory in <b>str</b>, then free it.
+ *
+ * As tor_free(), tolerates null pointers.
+ **/
+void
+tor_str_wipe_and_free_(char *str)
+{
+ if (!str)
+ return;
+ memwipe(str, 0, strlen(str));
+ tor_free_(str);
+}
diff --git a/src/lib/crypt_ops/crypto_util.h b/src/lib/crypt_ops/crypto_util.h
index 613a1bd0dd..36ee230176 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,8 +14,18 @@
#define TOR_CRYPTO_UTIL_H
#include "lib/cc/torint.h"
+#include "lib/malloc/malloc.h"
/** OpenSSL-based utility functions. */
void memwipe(void *mem, uint8_t byte, size_t sz);
+void tor_str_wipe_and_free_(char *str);
+/**
+ * Securely all memory in <b>str</b>, then free it.
+ *
+ * As tor_free(), tolerates null pointers, and sets <b>str</b> to NULL.
+ **/
+#define tor_str_wipe_and_free(str) \
+ FREE_AND_NULL(char, tor_str_wipe_and_free_, (str))
+
#endif /* !defined(TOR_CRYPTO_UTIL_H) */
diff --git a/src/lib/crypt_ops/digestset.c b/src/lib/crypt_ops/digestset.c
index c931b58369..5162d6d8bd 100644
--- a/src/lib/crypt_ops/digestset.c
+++ b/src/lib/crypt_ops/digestset.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 7d6d687342..505ac10395 100644
--- a/src/lib/crypt_ops/digestset.h
+++ b/src/lib/crypt_ops/digestset.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am
index 1f58a33d38..7644cab412 100644
--- a/src/lib/crypt_ops/include.am
+++ b/src/lib/crypt_ops/include.am
@@ -68,6 +68,8 @@ noinst_HEADERS += \
src/lib/crypt_ops/crypto_nss_mgt.h \
src/lib/crypt_ops/crypto_openssl_mgt.h \
src/lib/crypt_ops/crypto_ope.h \
+ src/lib/crypt_ops/crypto_options.inc \
+ src/lib/crypt_ops/crypto_options_st.h \
src/lib/crypt_ops/crypto_pwbox.h \
src/lib/crypt_ops/crypto_rand.h \
src/lib/crypt_ops/crypto_rsa.h \
diff --git a/src/lib/crypt_ops/lib_crypt_ops.md b/src/lib/crypt_ops/lib_crypt_ops.md
new file mode 100644
index 0000000000..4e675e4871
--- /dev/null
+++ b/src/lib/crypt_ops/lib_crypt_ops.md
@@ -0,0 +1,137 @@
+@dir /lib/crypt_ops
+@brief lib/crypt_ops: Cryptographic operations.
+
+This module contains wrappers around the cryptographic libraries that we
+support, and implementations for some higher-level cryptographic
+constructions that we use.
+
+It wraps our two major cryptographic backends (OpenSSL or NSS, as configured
+by the user), and also wraps other cryptographic code in src/ext.
+
+Generally speaking, Tor code shouldn't be calling OpenSSL or NSS
+(or any other crypto library) directly. Instead, we should indirect through
+one of the functions in this directory, or through \refdir{lib/tls}.
+
+Cryptography functionality that's available is described below.
+
+### RNG facilities ###
+
+The most basic RNG capability in Tor is the crypto_rand() family of
+functions. These currently use OpenSSL's RAND_() backend, but may use
+something faster in the future.
+
+In addition to crypto_rand(), which fills in a buffer with random
+bytes, we also have functions to produce random integers in certain
+ranges; to produce random hostnames; to produce random doubles, etc.
+
+When you're creating a long-term cryptographic secret, you might want
+to use crypto_strongest_rand() instead of crypto_rand(). It takes the
+operating system's entropy source and combines it with output from
+crypto_rand(). This is a pure paranoia measure, but it might help us
+someday.
+
+You can use smartlist_choose() to pick a random element from a smartlist
+and smartlist_shuffle() to randomize the order of a smartlist. Both are
+potentially a bit slow.
+
+### Cryptographic digests and related functions ###
+
+We treat digests as separate types based on the length of their
+outputs. We support one 160-bit digest (SHA1), two 256-bit digests
+(SHA256 and SHA3-256), and two 512-bit digests (SHA512 and SHA3-512).
+
+You should not use SHA1 for anything new.
+
+The crypto_digest\*() family of functions manipulates digests. You
+can either compute a digest of a chunk of memory all at once using
+crypto_digest(), crypto_digest256(), or crypto_digest512(). Or you
+can create a crypto_digest_t object with
+crypto_digest{,256,512}_new(), feed information to it in chunks using
+crypto_digest_add_bytes(), and then extract the final digest using
+crypto_digest_get_digest(). You can copy the state of one of these
+objects using crypto_digest_dup() or crypto_digest_assign().
+
+We support the HMAC hash-based message authentication code
+instantiated using SHA256. See crypto_hmac_sha256. (You should not
+add any HMAC users with SHA1, and HMAC is not necessary with SHA3.)
+
+We also support the SHA3 cousins, SHAKE128 and SHAKE256. Unlike
+digests, these are extendable output functions (or XOFs) where you can
+get any amount of output. Use the crypto_xof_\*() functions to access
+these.
+
+We have several ways to derive keys from cryptographically strong secret
+inputs (like diffie-hellman outputs). The old
+crypto_expand_key_material_TAP() performs an ad-hoc KDF based on SHA1 -- you
+shouldn't use it for implementing anything but old versions of the Tor
+protocol. You can use HKDF-SHA256 (as defined in RFC5869) for more modern
+protocols. Also consider SHAKE256.
+
+If your input is potentially weak, like a password or passphrase, use a salt
+along with the secret_to_key() functions as defined in crypto_s2k.c. Prefer
+scrypt over other hashing methods when possible. If you're using a password
+to encrypt something, see the "boxed file storage" section below.
+
+Finally, in order to store objects in hash tables, Tor includes the
+randomized SipHash 2-4 function. Call it via the siphash24g() function in
+src/ext/siphash.h whenever you're creating a hashtable whose keys may be
+manipulated by an attacker in order to DoS you with collisions.
+
+
+### Stream ciphers ###
+
+You can create instances of a stream cipher using crypto_cipher_new().
+These are stateful objects of type crypto_cipher_t. Note that these
+objects only support AES-128 right now; a future version should add
+support for AES-128 and/or ChaCha20.
+
+You can encrypt/decrypt with crypto_cipher_encrypt or
+crypto_cipher_decrypt. The crypto_cipher_crypt_inplace function performs
+an encryption without a copy.
+
+Note that sensible people should not use raw stream ciphers; they should
+probably be using some kind of AEAD. Sorry.
+
+### Public key functionality ###
+
+We support four public key algorithms: DH1024, RSA, Curve25519, and
+Ed25519.
+
+We support DH1024 over two prime groups. You access these via the
+crypto_dh_\*() family of functions.
+
+We support RSA in many bit sizes for signing and encryption. You access
+it via the crypto_pk_*() family of functions. Note that a crypto_pk_t
+may or may not include a private key. See the crypto_pk_* functions in
+crypto.c for a full list of functions here.
+
+For Curve25519 functionality, see the functions and types in
+crypto_curve25519.c. Curve25519 is generally suitable for when you need
+a secure fast elliptic-curve diffie hellman implementation. When
+designing new protocols, prefer it over DH in Z_p.
+
+For Ed25519 functionality, see the functions and types in
+crypto_ed25519.c. Ed25519 is a generally suitable as a secure fast
+elliptic curve signature method. For new protocols, prefer it over RSA
+signatures.
+
+### Metaformats for storage ###
+
+When OpenSSL manages the storage of some object, we use whatever format
+OpenSSL provides -- typically, some kind of PEM-wrapped base 64 encoding
+that starts with "----- BEGIN CRYPTOGRAPHIC OBJECT ----".
+
+When we manage the storage of some cryptographic object, we prefix the
+object with 32-byte NUL-padded prefix in order to avoid accidental
+object confusion; see the crypto_read_tagged_contents_from_file() and
+crypto_write_tagged_contents_to_file() functions for manipulating
+these. The prefix is "== type: tag ==", where type describes the object
+and its encoding, and tag indicates which one it is.
+
+### Boxed-file storage ###
+
+When managing keys, you frequently want to have some way to write a
+secret object to disk, encrypted with a passphrase. The crypto_pwbox
+and crypto_unpwbox functions do so in a way that's likely to be
+readable by future versions of Tor.
+
diff --git a/src/lib/ctime/di_ops.c b/src/lib/ctime/di_ops.c
index 89e0837ae9..d57d286990 100644
--- a/src/lib/ctime/di_ops.c
+++ b/src/lib/ctime/di_ops.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2019, The Tor Project, Inc. */
+/* Copyright (c) 2011-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -72,10 +72,10 @@ tor_memcmp(const void *a, const void *b, size_t len)
* actually implementation-defined in standard C. So how do we
* get away with assuming it? Easy. We check.) */
#if ((-60 >> 8) != -1)
-#error "According to cpp, right-shift doesn't perform sign-extension."
+#error "cpp says right-shift doesn't perform sign-extension."
#endif
#ifndef RSHIFT_DOES_SIGN_EXTEND
-#error "According to configure, right-shift doesn't perform sign-extension."
+#error "configure says right-shift doesn't perform sign-extension."
#endif
/* If v1 == v2, equal_p is ~0, so this will leave retval
@@ -145,8 +145,11 @@ tor_memeq(const void *a, const void *b, size_t sz)
/* Implement di_digest256_map_t as a linked list of entries. */
struct di_digest256_map_t {
+ /** Pointer to the next entry in the list. */
struct di_digest256_map_t *next;
+ /** Key for this entry. */
uint8_t key[32];
+ /** Value for this entry. */
void *val;
};
@@ -276,3 +279,30 @@ select_array_member_cumulative_timei(const uint64_t *entries, int n_entries,
return i_chosen;
}
+
+/**
+ * If <b>s</b> is true, then copy <b>n</b> bytes from <b>src</b> to
+ * <b>dest</b>. Otherwise leave <b>dest</b> alone.
+ *
+ * This function behaves the same as
+ *
+ * if (s)
+ * memcpy(dest, src, n);
+ *
+ * except that it tries to run in the same amount of time whether <b>s</b> is
+ * true or not.
+ **/
+void
+memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n)
+{
+ // If s is true, mask will be ~0. If s is false, mask will be 0.
+ const char mask = (char) -(signed char)s;
+
+ char *destp = dest;
+ const char *srcp = src;
+ for (size_t i = 0; i < n; ++i) {
+ *destp = (*destp & ~mask) | (*srcp & mask);
+ ++destp;
+ ++srcp;
+ }
+}
diff --git a/src/lib/ctime/di_ops.h b/src/lib/ctime/di_ops.h
index 264b56a8c1..9fe2884ecc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,6 +16,8 @@
int tor_memcmp(const void *a, const void *b, size_t sz);
int tor_memeq(const void *a, const void *b, size_t sz);
+/** Perform a constant-time comparison of the <b>sz</b> bytes at <b>a</b> and
+ * <b>b</b>, yielding true if they are different, and false otherwise. */
#define tor_memneq(a,b,sz) (!tor_memeq((a),(b),(sz)))
/** Alias for the platform's memcmp() function. This function is
@@ -24,7 +26,19 @@ int tor_memeq(const void *a, const void *b, size_t sz);
* implementation.
*/
#define fast_memcmp(a,b,c) (memcmp((a),(b),(c)))
+/** Alias for the platform's memcmp() function, for use in testing equality.
+ *
+ * This function is <em>not</em> data-independent: we define this alias so
+ * that we can mark cases where we are deliberately using a data-dependent
+ * memcmp() implementation.
+ */
#define fast_memeq(a,b,c) (0==memcmp((a),(b),(c)))
+/** Alias for the platform's memcmp() function, for use in testing inequality.
+ *
+ * This function is <em>not</em> data-independent: we define this alias so
+ * that we can mark cases where we are deliberately using a data-dependent
+ * memcmp() implementation.
+ */
#define fast_memneq(a,b,c) (0!=memcmp((a),(b),(c)))
int safe_mem_is_zero(const void *mem, size_t sz);
@@ -35,9 +49,17 @@ int safe_mem_is_zero(const void *mem, size_t sz);
*
* Not efficient for large maps! */
typedef struct di_digest256_map_t di_digest256_map_t;
+/**
+ * Type for a function used to free members of a di_digest256_map_t.
+ **/
typedef void (*dimap_free_fn)(void *);
void dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn);
+/**
+ * @copydoc dimap_free_
+ *
+ * Additionally, set the pointer <b>map</b> to NULL.
+ **/
#define dimap_free(map, free_fn) \
do { \
dimap_free_((map), (free_fn)); \
@@ -51,5 +73,6 @@ int select_array_member_cumulative_timei(const uint64_t *entries,
int n_entries,
uint64_t total, uint64_t rand_val);
-#endif /* !defined(TOR_DI_OPS_H) */
+void memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n);
+#endif /* !defined(TOR_DI_OPS_H) */
diff --git a/src/lib/ctime/lib_ctime.md b/src/lib/ctime/lib_ctime.md
new file mode 100644
index 0000000000..913199f6a5
--- /dev/null
+++ b/src/lib/ctime/lib_ctime.md
@@ -0,0 +1,14 @@
+@dir /lib/ctime
+@brief lib/ctime: Constant-time code to avoid side-channels.
+
+This module contains constant-time implementations of various
+data comparison and table lookup functions. We use these in preference to
+memcmp() and so forth, since memcmp() can leak information about its inputs
+based on how fast it returns. In general, your code should call tor_memeq()
+and tor_memneq(), not memcmp().
+
+We also define some _non_-constant-time wrappers for memcmp() here: Since we
+consider calls to memcmp() to be in error, we require that code that actually
+doesn't need to be constant-time to use the fast_memeq() / fast_memneq() /
+fast_memcmp() aliases instead.
+
diff --git a/src/lib/defs/dh_sizes.h b/src/lib/defs/dh_sizes.h
index b0d1eba0c5..bc2707b36f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 a0dd97a74d..7eef1747db 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_DIGEST_SIZES_H
diff --git a/src/lib/defs/lib_defs.md b/src/lib/defs/lib_defs.md
new file mode 100644
index 0000000000..5762e4550b
--- /dev/null
+++ b/src/lib/defs/lib_defs.md
@@ -0,0 +1,2 @@
+@dir /lib/defs
+@brief lib/defs: Lowest-level constants, used in many places.
diff --git a/src/lib/defs/logging_types.h b/src/lib/defs/logging_types.h
index d3eacde464..33aa46186b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/defs/time.h b/src/lib/defs/time.h
index 459afbf42d..5707330795 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TIME_DEFS_H
@@ -17,7 +17,7 @@
#define TOR_USEC_PER_SEC (1000000)
/** How many nanoseconds per microsecond */
#define TOR_NSEC_PER_USEC (1000)
-/* How many nanoseconds per millisecond */
+/** How many nanoseconds per millisecond */
#define TOR_NSEC_PER_MSEC (1000*1000)
#endif /* !defined(TOR_TIME_DEFS_H) */
diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h
index 6431f0a2dd..acb08c5e6a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,14 +23,22 @@
/** Length of the result of a curve25519 handshake. */
#define CURVE25519_OUTPUT_LEN 32
+/** Length of an Ed25519 public key */
#define ED25519_PUBKEY_LEN 32
+/** Length of an Ed25519 secret key */
#define ED25519_SECKEY_LEN 64
+/** Length of the seed that is ordinarily expanded to an Ed25519 secret
+ * key. */
#define ED25519_SECKEY_SEED_LEN 32
+/** Length of an Ed25519 signature. */
#define ED25519_SIG_LEN 64
+/** Length of a Curve25519 key when encoded in base 64, with padding. */
#define CURVE25519_BASE64_PADDED_LEN 44
+/** Length of a Ed25519 key when encoded in base 64, without padding. */
#define ED25519_BASE64_LEN 43
+/** Length of a Ed25519 signature when encoded in base 64, without padding. */
#define ED25519_SIG_BASE64_LEN 86
#endif /* !defined(TOR_X25519_SIZES_H) */
diff --git a/src/lib/dispatch/dispatch.h b/src/lib/dispatch/dispatch.h
index a9e655409a..9c7c4833c2 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 b3a72ec22f..a54188dcaa 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 348dce8d40..a4f1948eac 100644
--- a/src/lib/dispatch/dispatch_cfg.h
+++ b/src/lib/dispatch/dispatch_cfg.h
@@ -1,12 +1,17 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_DISPATCH_CFG_H
#define TOR_DISPATCH_CFG_H
+/**
+ * @file dispatch_cfg.h
+ * @brief Header for distpach_cfg.c
+ **/
+
#include "lib/dispatch/msgtypes.h"
#include "lib/testsupport/testsupport.h"
diff --git a/src/lib/dispatch/dispatch_cfg_st.h b/src/lib/dispatch/dispatch_cfg_st.h
index 57b6f0347f..3c99adf2f7 100644
--- a/src/lib/dispatch/dispatch_cfg_st.h
+++ b/src/lib/dispatch/dispatch_cfg_st.h
@@ -1,16 +1,24 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dispatch_cfg_st.h
+ * @brief Declarations for dispatch-configuration types.
+ **/
+
#ifndef TOR_DISPATCH_CFG_ST_H
#define TOR_DISPATCH_CFG_ST_H
struct smartlist_t;
-/* Information needed to create a dispatcher, but in a less efficient, more
- * mutable format. */
+/** Information needed to create a dispatcher, but in a less efficient, more
+ * mutable format.
+ *
+ * Nearly everybody should use the \refdir{lib/pubsub} module to configure
+ * dispatchers, instead of using this. */
struct dispatch_cfg_t {
/** A list of msg_type_id_t (cast to void*), indexed by msg_t. */
struct smartlist_t *type_by_msg;
diff --git a/src/lib/dispatch/dispatch_core.c b/src/lib/dispatch/dispatch_core.c
index da54f9b437..3d51c876a7 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 83d9a2d604..bb49343712 100644
--- a/src/lib/dispatch/dispatch_naming.c
+++ b/src/lib/dispatch/dispatch_naming.c
@@ -1,9 +1,14 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dispatch_naming.c
+ * @brief Name-to-ID maps for our message dispatch system.
+ **/
+
#include "orconfig.h"
#include "lib/cc/compat_compiler.h"
@@ -33,6 +38,7 @@ dispatch_naming_init(void)
{
}
+#ifndef COCCI
/* Helper macro: declare functions to map IDs to and from names for a given
* type in a namemap_t.
*/
@@ -56,6 +62,7 @@ dispatch_naming_init(void)
return namemap_get_size(&type##_id_map); \
} \
EAT_SEMICOLON
+#endif /* !defined(COCCI) */
DECLARE_ID_MAP_FNS(message);
DECLARE_ID_MAP_FNS(channel);
diff --git a/src/lib/dispatch/dispatch_naming.h b/src/lib/dispatch/dispatch_naming.h
index fd6c83cc12..72206d3ed5 100644
--- a/src/lib/dispatch/dispatch_naming.h
+++ b/src/lib/dispatch/dispatch_naming.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dispatch_naming.h
+ * @brief Header for dispatch_naming.c
+ **/
+
#ifndef TOR_DISPATCH_NAMING_H
#define TOR_DISPATCH_NAMING_H
diff --git a/src/lib/dispatch/dispatch_new.c b/src/lib/dispatch/dispatch_new.c
index d8e59d610a..e1dbb1c4b8 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 ee42518b5a..ad5b4efc40 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/lib_dispatch.md b/src/lib/dispatch/lib_dispatch.md
new file mode 100644
index 0000000000..153ca50080
--- /dev/null
+++ b/src/lib/dispatch/lib_dispatch.md
@@ -0,0 +1,14 @@
+@dir /lib/dispatch
+@brief lib/dispatch: In-process message delivery.
+
+This module provides a general in-process "message dispatch" system in which
+typed messages are sent on channels. The dispatch.h header has far more
+information.
+
+It is used by by \refdir{lib/pubsub} to implement our general
+inter-module publish/subscribe system.
+
+This is not a fancy multi-threaded many-to-many dispatcher as you may be used
+to from more sophisticated architectures: this dispatcher is intended only
+for use in improving Tor's architecture.
+
diff --git a/src/lib/dispatch/msgtypes.h b/src/lib/dispatch/msgtypes.h
index b4c4a10248..01d969dcb5 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/binascii.c b/src/lib/encoding/binascii.c
index fc64e014e7..3e549eb8e3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/binascii.h b/src/lib/encoding/binascii.h
index 40c5593b11..9cb03bab62 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c
index 0d8384db13..613e4a00c6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -151,6 +151,8 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
if (allow_include && !strcmp(k, "%include") && handle_include) {
tor_free(k);
include_used = 1;
+ log_notice(LD_CONFIG, "Processing configuration path \"%s\" at "
+ "recursion level %d.", v, recursion_level);
config_line_t *include_list;
if (handle_include(v, recursion_level, extended, &include_list,
@@ -161,9 +163,6 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
tor_free(v);
return -1;
}
- log_notice(LD_CONFIG, "Included configuration file or "
- "directory at recursion level %d: \"%s\".",
- recursion_level, v);
*next = include_list;
if (list_last)
next = &list_last->next;
@@ -253,6 +252,35 @@ config_lines_dup_and_filter(const config_line_t *inp,
return result;
}
+/**
+ * Given a linelist <b>inp</b> beginning with the key <b>header</b>, find the
+ * next line with that key, and remove that instance and all following lines
+ * from the list. Return the lines that were removed. Operate
+ * case-insensitively.
+ *
+ * For example, if the header is "H", and <b>inp</b> contains "H, A, B, H, C,
+ * H, D", this function will alter <b>inp</b> to contain only "H, A, B", and
+ * return the elements "H, C, H, D" as a separate list.
+ **/
+config_line_t *
+config_lines_partition(config_line_t *inp, const char *header)
+{
+ if (BUG(inp == NULL))
+ return NULL;
+ if (BUG(strcasecmp(inp->key, header)))
+ return NULL;
+
+ /* Advance ptr until it points to the link to the next segment of this
+ list. */
+ config_line_t **ptr = &inp->next;
+ while (*ptr && strcasecmp((*ptr)->key, header)) {
+ ptr = &(*ptr)->next;
+ }
+ config_line_t *remainder = *ptr;
+ *ptr = NULL;
+ return remainder;
+}
+
/** Return true iff a and b contain identical keys and values in identical
* order. */
int
diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h
index 12c554c6e7..ce0d6c6e17 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -50,6 +50,7 @@ const config_line_t *config_line_find(const config_line_t *lines,
const char *key);
const config_line_t *config_line_find_case(const config_line_t *lines,
const char *key);
+config_line_t *config_lines_partition(config_line_t *inp, const char *header);
int config_lines_eq(const config_line_t *a, const config_line_t *b);
int config_count_key(const config_line_t *a, const char *key);
void config_free_lines_(config_line_t *front);
diff --git a/src/lib/encoding/cstring.c b/src/lib/encoding/cstring.c
index 29d3714126..54c330fca3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/cstring.h b/src/lib/encoding/cstring.h
index 904a2c9c1c..2a3f6d0fc4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/keyval.c b/src/lib/encoding/keyval.c
index c5da5a0bfc..0eb1219d43 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/keyval.h b/src/lib/encoding/keyval.h
index dcddfa3396..b4966b01de 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/kvline.c b/src/lib/encoding/kvline.c
index d4a8f510ba..5b220605d6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,12 +29,20 @@
#include <string.h>
/** Return true iff we need to quote and escape the string <b>s</b> to encode
- * it. */
+ * it.
+ *
+ * kvline_can_encode_lines() also uses this (with
+ * <b>as_keyless_val</b> true) to check whether a key would require
+ * quoting.
+ */
static bool
needs_escape(const char *s, bool as_keyless_val)
{
if (as_keyless_val && *s == 0)
return true;
+ /* Keyless values containing '=' need to be escaped. */
+ if (as_keyless_val && strchr(s, '='))
+ return true;
for (; *s; ++s) {
if (*s >= 127 || TOR_ISSPACE(*s) || ! TOR_ISPRINT(*s) ||
@@ -72,23 +80,17 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
{
for ( ; line; line = line->next) {
const bool keyless = line_has_no_key(line);
- if (keyless) {
- if (! (flags & KV_OMIT_KEYS)) {
- /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
- return false;
- }
- if (strchr(line->value, '=') && !( flags & KV_QUOTED)) {
- /* We can't have a keyless value with = without quoting it. */
- return false;
- }
+ if (keyless && ! (flags & KV_OMIT_KEYS)) {
+ /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
+ return false;
}
- if (needs_escape(line->value, keyless) && ! (flags & KV_QUOTED)) {
- /* If KV_QUOTED is false, we can't encode a value that needs quotes. */
+ if (needs_escape(line->value, keyless) && ! (flags & (KV_QUOTED|KV_RAW))) {
+ /* If both KV_QUOTED and KV_RAW are false, we can't encode a
+ value that needs quotes. */
return false;
}
- if (line->key && strlen(line->key) &&
- (needs_escape(line->key, false) || strchr(line->key, '='))) {
+ if (!keyless && needs_escape(line->key, true)) {
/* We can't handle keys that need quoting. */
return false;
}
@@ -103,7 +105,7 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
*
* If KV_QUOTED is set in <b>flags</b>, then all values that contain
* spaces or unusual characters are escaped and quoted. Otherwise, such
- * values are not allowed.
+ * values are not allowed. Mutually exclusive with KV_RAW.
*
* If KV_OMIT_KEYS is set in <b>flags</b>, then pairs with empty keys are
* allowed, and are encoded as 'Value'. Otherwise, such pairs are not
@@ -113,6 +115,11 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
* encoded as 'Key', not as 'Key=' or 'Key=""'. Mutually exclusive with
* KV_OMIT_KEYS.
*
+ * If KV_RAW is set in <b>flags</b>, then don't apply any quoting to
+ * the value, and assume that the caller has adequately quoted it.
+ * (The control protocol has some quirks that make this necessary.)
+ * Mutually exclusive with KV_QUOTED.
+ *
* KV_QUOTED_QSTRING is not supported.
*/
char *
@@ -121,11 +128,12 @@ kvline_encode(const config_line_t *line,
{
tor_assert(! (flags & KV_QUOTED_QSTRING));
- if (!kvline_can_encode_lines(line, flags))
- return NULL;
-
tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
(KV_OMIT_KEYS|KV_OMIT_VALS));
+ tor_assert((flags & (KV_QUOTED|KV_RAW)) != (KV_QUOTED|KV_RAW));
+
+ if (!kvline_can_encode_lines(line, flags))
+ return NULL;
smartlist_t *elements = smartlist_new();
@@ -142,15 +150,12 @@ kvline_encode(const config_line_t *line,
k = line->key;
} else {
eq = "";
- if (strchr(line->value, '=')) {
- esc = true;
- }
}
if ((flags & KV_OMIT_VALS) && line_has_no_val(line)) {
eq = "";
v = "";
- } else if (esc) {
+ } else if (!(flags & KV_RAW) && esc) {
tmp = esc_for_log(line->value);
v = tmp;
} else {
@@ -187,12 +192,15 @@ kvline_encode(const config_line_t *line,
* If KV_QUOTED_QSTRING is set in <b>flags</b>, then double-quoted values
* are allowed and handled as QuotedStrings per qstring.c. Do not add
* new users of this flag.
+ *
+ * KV_RAW is not supported.
*/
config_line_t *
kvline_parse(const char *line, unsigned flags)
{
tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
(KV_OMIT_KEYS|KV_OMIT_VALS));
+ tor_assert(!(flags & KV_RAW));
const char *cp = line, *cplast = NULL;
const bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
diff --git a/src/lib/encoding/kvline.h b/src/lib/encoding/kvline.h
index dea2ce1809..34c52908e3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,6 +19,7 @@ struct config_line_t;
#define KV_OMIT_KEYS (1u<<1)
#define KV_OMIT_VALS (1u<<2)
#define KV_QUOTED_QSTRING (1u<<3)
+#define KV_RAW (1u<<4)
struct config_line_t *kvline_parse(const char *line, unsigned flags);
char *kvline_encode(const struct config_line_t *line, unsigned flags);
diff --git a/src/lib/encoding/lib_encoding.md b/src/lib/encoding/lib_encoding.md
new file mode 100644
index 0000000000..66dd9d8caf
--- /dev/null
+++ b/src/lib/encoding/lib_encoding.md
@@ -0,0 +1,6 @@
+@dir /lib/encoding
+@brief lib/encoding: Encoding data in various forms, types, and transformations
+
+Here we have time formats (timefmt.c), quoted strings (qstring.c), C strings
+(string.c) base-16/32/64 (binascii.c), and more.
+
diff --git a/src/lib/encoding/pem.c b/src/lib/encoding/pem.c
index 51f37d0840..6c9f10e085 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -42,7 +42,7 @@ pem_encoded_size(size_t src_len, const char *objtype)
/**
* PEM-encode the <b>srclen</b>-byte object at <b>src</b> into the
- * <b>destlen<\b>-byte buffer at <b>dest</b>, tagging it with <b>objtype</b>.
+ * <b>destlen</b>-byte buffer at <b>dest</b>, tagging it with <b>objtype</b>.
* Return 0 on success and -1 on failure.
*/
int
diff --git a/src/lib/encoding/pem.h b/src/lib/encoding/pem.h
index 6b20350aa8..027c31c315 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/qstring.c b/src/lib/encoding/qstring.c
index a92d28c706..5a34924eab 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/qstring.h b/src/lib/encoding/qstring.h
index 840e1044ce..f19a7dad87 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 40543d41e0..573dfaad82 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 d14bc1f902..80e47c5332 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c
index ce8ddcd7c0..afb6b9503f 100644
--- a/src/lib/err/backtrace.c
+++ b/src/lib/err/backtrace.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -54,7 +54,7 @@
#include "lib/cc/ctassert.h"
-#define EXPOSE_CLEAN_BACKTRACE
+#define BACKTRACE_PRIVATE
#include "lib/err/backtrace.h"
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
diff --git a/src/lib/err/backtrace.h b/src/lib/err/backtrace.h
index 7e09a0a5a7..d02e6960b5 100644
--- a/src/lib/err/backtrace.h
+++ b/src/lib/err/backtrace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_BACKTRACE_H
@@ -29,11 +29,11 @@ const char *get_tor_backtrace_version(void);
#define log_backtrace(sev, dom, msg) \
log_backtrace_impl((sev), (dom), (msg), tor_log)
-#ifdef EXPOSE_CLEAN_BACKTRACE
+#ifdef BACKTRACE_PRIVATE
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
void clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx);
#endif
-#endif /* defined(EXPOSE_CLEAN_BACKTRACE) */
+#endif /* defined(BACKTRACE_PRIVATE) */
#endif /* !defined(TOR_BACKTRACE_H) */
diff --git a/src/lib/err/lib_err.md b/src/lib/err/lib_err.md
new file mode 100644
index 0000000000..cb4eba2e0d
--- /dev/null
+++ b/src/lib/err/lib_err.md
@@ -0,0 +1,13 @@
+@dir /lib/err
+@brief lib/err: Lowest-level error handling code.
+
+This module is responsible for generating stack traces, handling raw
+assertion failures, and otherwise reporting problems that might not be
+safe to report via the regular logging module.
+
+There are three kinds of users for the functions in this module:
+ * Code that needs a way to assert(), but which cannot use the regular
+ `tor_assert()` macros in logging module.
+ * Code that needs signal-safe error reporting.
+ * Higher-level error handling code.
+
diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c
index a5c00ca389..2de75c0be4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -151,6 +151,30 @@ tor_log_reset_sigsafe_err_fds(void)
}
/**
+ * Flush the list of fds that get errors from inside a signal handler or
+ * other emergency condition. These fds are shared with the logging code:
+ * flushing them also flushes the log buffers.
+ *
+ * This function is safe to call during signal handlers.
+ */
+void
+tor_log_flush_sigsafe_err_fds(void)
+{
+ /* If we don't have fsync() in unistd.h, we can't flush the logs. */
+#ifdef HAVE_FSYNC
+ int n_fds, i;
+ const int *fds = NULL;
+
+ n_fds = tor_log_get_sigsafe_err_fds(&fds);
+ for (i = 0; i < n_fds; ++i) {
+ /* This function is called on error and on shutdown, so we don't log, or
+ * take any other action, if fsync() fails. */
+ (void)fsync(fds[i]);
+ }
+#endif /* defined(HAVE_FSYNC) */
+}
+
+/**
* Set the granularity (in ms) to use when reporting fatal errors outside
* the logging system.
*/
@@ -191,12 +215,13 @@ tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr,
/**
* Call the abort() function to kill the current process with a fatal
- * error. This is a separate function, so that log users don't have to include
- * the header for abort().
+ * error. But first, flush the raw error file descriptors, so error messages
+ * are written before process termination.
**/
void
tor_raw_abort_(void)
{
+ tor_log_flush_sigsafe_err_fds();
abort();
}
diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h
index a1822d9c9a..ce1b049c47 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -40,6 +40,7 @@ void tor_log_err_sigsafe(const char *m, ...);
int tor_log_get_sigsafe_err_fds(const int **out);
void tor_log_set_sigsafe_err_fds(const int *fds, int n);
void tor_log_reset_sigsafe_err_fds(void);
+void tor_log_flush_sigsafe_err_fds(void);
void tor_log_sigsafe_err_set_granularity(int ms);
void tor_raw_abort_(void) ATTR_NORETURN;
diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c
index c42e958093..8ee1521f3b 100644
--- a/src/lib/err/torerr_sys.c
+++ b/src/lib/err/torerr_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,12 +27,14 @@ subsys_torerr_initialize(void)
static void
subsys_torerr_shutdown(void)
{
- /* Stop handling signals with backtraces. */
+ /* Stop handling signals with backtraces, then flush the logs. */
clean_up_backtrace_handler();
+ tor_log_flush_sigsafe_err_fds();
}
const subsys_fns_t sys_torerr = {
.name = "err",
+ SUBSYS_DECLARE_LOCATION(),
/* Low-level error handling is a diagnostic feature, we want it to init
* right after windows process security, and shutdown last.
* (Security never shuts down.) */
diff --git a/src/lib/err/torerr_sys.h b/src/lib/err/torerr_sys.h
index c947695689..b86ccd2790 100644
--- a/src/lib/err/torerr_sys.h
+++ b/src/lib/err/torerr_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 939d77f857..0fd247d331 100644
--- a/src/lib/evloop/compat_libevent.c
+++ b/src/lib/evloop/compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2019, The Tor Project, Inc. */
+/* Copyright (c) 2009-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -130,7 +130,7 @@ rescan_mainloop_cb(evutil_socket_t fd, short events, void *arg)
/** Initialize the Libevent library and set up the event base. */
void
-tor_libevent_initialize(tor_libevent_cfg *torcfg)
+tor_libevent_initialize(tor_libevent_cfg_t *torcfg)
{
tor_assert(the_event_base == NULL);
/* some paths below don't use torcfg, so avoid unused variable warnings */
@@ -432,7 +432,7 @@ mainloop_event_activate(mainloop_event_t *event)
*
* If the event is scheduled for a different time, cancel it and run
* after this delay instead. If the event is currently pending to run
- * <em>now</b>, has no effect.
+ * <b>now</b>, has no effect.
*
* Do not call this function with <b>tv</b> == NULL -- use
* mainloop_event_activate() instead.
diff --git a/src/lib/evloop/compat_libevent.h b/src/lib/evloop/compat_libevent.h
index 92724c369c..277ba3add6 100644
--- a/src/lib/evloop/compat_libevent.h
+++ b/src/lib/evloop/compat_libevent.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2019, The Tor Project, Inc. */
+/* Copyright (c) 2009-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -61,15 +61,15 @@ void mainloop_event_free_(mainloop_event_t *event);
/** Defines a configuration for using libevent with Tor: passed as an argument
* to tor_libevent_initialize() to describe how we want to set up. */
-typedef struct tor_libevent_cfg {
+typedef struct tor_libevent_cfg_t {
/** How many CPUs should we use (not currently useful). */
int num_cpus;
/** How many milliseconds should we allow between updating bandwidth limits?
* (Not currently useful). */
int msec_per_tick;
-} tor_libevent_cfg;
+} tor_libevent_cfg_t;
-void tor_libevent_initialize(tor_libevent_cfg *cfg);
+void tor_libevent_initialize(tor_libevent_cfg_t *cfg);
bool tor_libevent_is_initialized(void);
MOCK_DECL(struct event_base *, tor_libevent_get_base, (void));
const char *tor_libevent_get_method(void);
diff --git a/src/lib/evloop/evloop_sys.c b/src/lib/evloop/evloop_sys.c
index 56641a3175..b639810c23 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -41,6 +41,7 @@ subsys_evloop_shutdown(void)
const struct subsys_fns_t sys_evloop = {
.name = "evloop",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = -20,
.initialize = subsys_evloop_initialize,
diff --git a/src/lib/evloop/evloop_sys.h b/src/lib/evloop/evloop_sys.h
index e6155c25b0..a37440e7a6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/lib_evloop.md b/src/lib/evloop/lib_evloop.md
new file mode 100644
index 0000000000..830be88148
--- /dev/null
+++ b/src/lib/evloop/lib_evloop.md
@@ -0,0 +1,7 @@
+@dir /lib/evloop
+@brief lib/evloop: Low-level event loop.
+
+This modules has tools to manage the [libevent](https://libevent.org/) event
+loop and related functionality, in order to implement asynchronous
+networking, timers, periodic events, and other scheduling tasks.
+
diff --git a/src/lib/evloop/procmon.c b/src/lib/evloop/procmon.c
index b2d81fc14b..718c7d4777 100644
--- a/src/lib/evloop/procmon.c
+++ b/src/lib/evloop/procmon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2019, The Tor Project, Inc. */
+/* Copyright (c) 2011-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -165,8 +165,8 @@ tor_validate_process_specifier(const char *process_spec,
return parse_process_specifier(process_spec, &ppspec, msg);
}
-/* DOCDOC poll_interval_tv */
-static const struct timeval poll_interval_tv = {15, 0};
+/* We check this often for presence of owning controller process. */
+static const struct timeval poll_interval_tv = {15, 0}; // 15 seconds.
/** Create a process-termination monitor for the process specifier
* given in <b>process_spec</b>. Return a newly allocated
diff --git a/src/lib/evloop/procmon.h b/src/lib/evloop/procmon.h
index 6caae5be86..28f443da18 100644
--- a/src/lib/evloop/procmon.h
+++ b/src/lib/evloop/procmon.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2019, The Tor Project, Inc. */
+/* Copyright (c) 2011-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/time_periodic.md b/src/lib/evloop/time_periodic.md
new file mode 100644
index 0000000000..8b3589d9db
--- /dev/null
+++ b/src/lib/evloop/time_periodic.md
@@ -0,0 +1,76 @@
+
+@page time_periodic Time and periodic events in Tor
+
+### What time is it? ###
+
+We have several notions of the current time in Tor.
+
+The *wallclock time* is available from time(NULL) with
+second-granularity and tor_gettimeofday() with microsecond
+granularity. It corresponds most closely to "the current time and date".
+
+The *monotonic time* is available with the set of monotime_\*
+functions declared in compat_time.h. Unlike the wallclock time, it
+can only move forward. It does not necessarily correspond to a real
+world time, and it is not portable between systems.
+
+The *coarse monotonic time* is available from the set of
+monotime_coarse_\* functions in compat_time.h. It is the same as
+monotime_\* on some platforms. On others, it gives a monotonic timer
+with less precision, but which it's more efficient to access.
+
+### Cached views of time. ###
+
+On some systems (like Linux), many time functions use a VDSO to avoid
+the overhead of a system call. But on other systems, gettimeofday()
+and time() can be costly enough that you wouldn't want to call them
+tens of thousands of times. To get a recent, but not especially
+accurate, view of the current time, see approx_time() and
+tor_gettimeofday_cached().
+
+
+### Parsing and encoding time values ###
+
+Tor has functions to parse and format time in these formats:
+
+ - RFC1123 format. ("Fri, 29 Sep 2006 15:54:20 GMT"). For this,
+ use format_rfc1123_time() and parse_rfc1123_time.
+
+ - ISO8601 format. ("2006-10-29 10:57:20") For this, use
+ format_local_iso_time() and format_iso_time(). We also support the
+ variant format "2006-10-29T10:57:20" with format_iso_time_nospace(), and
+ "2006-10-29T10:57:20.123456" with format_iso_time_nospace_usec().
+
+ - HTTP format collections (preferably "Mon, 25 Jul 2016 04:01:11
+ GMT" or possibly "Wed Jun 30 21:49:08 1993" or even "25-Jul-16
+ 04:01:11 GMT"). For this, use parse_http_time(). Don't generate anything
+ but the first format.
+
+Some of these functions use struct tm. You can use the standard
+tor_localtime_r() and tor_gmtime_r() to wrap these in a safe way. We
+also have a tor_timegm() function.
+
+### Scheduling events ###
+
+The main way to schedule a not-too-frequent periodic event with
+respect to the Tor mainloop is via the mechanism in periodic.c.
+There's a big table of periodic_events in mainloop.c, each of which gets
+invoked on its own schedule. You should not expect more than about
+one second of accuracy with these timers.
+
+You can create an independent timer using libevent directly, or using
+the periodic_timer_new() function. But you should avoid doing this
+for per-connection or per-circuit timers: Libevent's internal timer
+implementation uses a min-heap, and those tend to start scaling poorly
+once you have a few thousand entries.
+
+If you need to create a large number of fine-grained timers for some
+purpose, you should consider the mechanism in src/common/timers.c,
+which is optimized for the case where you have a large number of
+timers with not-too-long duration, many of which will be deleted
+before they actually expire. These timers should be reasonably
+accurate within a handful of milliseconds -- possibly better on some
+platforms. (The timers.c module uses William Ahern's timeout.c
+implementation as its backend, which is based on a hierarchical timing
+wheel algorithm. It's cool stuff; check it out.)
+
diff --git a/src/lib/evloop/timers.c b/src/lib/evloop/timers.c
index 4b2a96ef7d..11418e93fd 100644
--- a/src/lib/evloop/timers.c
+++ b/src/lib/evloop/timers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,7 +11,7 @@
* The main advantage of tor_timer_t over using libevent's timers is that
* they're way more efficient if we need to have thousands or millions of
* them. For more information, see
- * http://www.25thandclement.com/~william/projects/timeout.c.html
+ * https://www.25thandclement.com/~william/projects/timeout.c.html
*
* Periodic timers are available in the backend, but I've turned them off.
* We can turn them back on if needed.
@@ -48,7 +48,7 @@
#include <winsock2.h>
#endif
-struct timeout_cb {
+struct timeout_cb_t {
timer_cb_fn_t cb;
void *arg;
};
@@ -56,19 +56,21 @@ struct timeout_cb {
/*
* These definitions are for timeouts.c and timeouts.h.
*/
-#ifdef __GNUC__
+#ifdef COCCI
+#define TIMEOUT_PUBLIC
+#elif defined(__GNUC__)
/* We're not exposing any of the functions outside this file. */
#define TIMEOUT_PUBLIC __attribute__((__unused__)) static
#else
/* We're not exposing any of the functions outside this file. */
#define TIMEOUT_PUBLIC static
-#endif /* defined(__GNUC__) */
+#endif /* defined(COCCI) || ... */
/* We're not using periodic events. */
#define TIMEOUT_DISABLE_INTERVALS
/* We always know the global_timeouts object, so we don't need each timeout
* to keep a pointer to it. */
#define TIMEOUT_DISABLE_RELATIVE_ACCESS
-/* We're providing our own struct timeout_cb. */
+/* We're providing our own struct timeout_cb_t. */
#define TIMEOUT_CB_OVERRIDE
/* We're going to support timers that are pretty far out in advance. Making
* this big can be inefficient, but having a significant number of timers
diff --git a/src/lib/evloop/timers.h b/src/lib/evloop/timers.h
index 7595554204..dd55446121 100644
--- a/src/lib/evloop/timers.h
+++ b/src/lib/evloop/timers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,7 @@
#include "lib/testsupport/testsupport.h"
struct monotime_t;
+struct timeval;
typedef struct timeout tor_timer_t;
typedef void (*timer_cb_fn_t)(tor_timer_t *, void *,
const struct monotime_t *);
diff --git a/src/lib/evloop/token_bucket.c b/src/lib/evloop/token_bucket.c
index ec62d1b018..a2b330fddb 100644
--- a/src/lib/evloop/token_bucket.c
+++ b/src/lib/evloop/token_bucket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 dde9bd65a4..460dad23e4 100644
--- a/src/lib/evloop/token_bucket.h
+++ b/src/lib/evloop/token_bucket.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c
index 015b694290..603dddd5a3 100644
--- a/src/lib/evloop/workqueue.c
+++ b/src/lib/evloop/workqueue.c
@@ -44,13 +44,13 @@
#define WORKQUEUE_PRIORITY_LAST WQ_PRI_LOW
#define WORKQUEUE_N_PRIORITIES (((int) WORKQUEUE_PRIORITY_LAST)+1)
-TOR_TAILQ_HEAD(work_tailq_t, workqueue_entry_s);
+TOR_TAILQ_HEAD(work_tailq_t, workqueue_entry_t);
typedef struct work_tailq_t work_tailq_t;
-struct threadpool_s {
+struct threadpool_t {
/** An array of pointers to workerthread_t: one for each running worker
* thread. */
- struct workerthread_s **threads;
+ struct workerthread_t **threads;
/** Condition variable that we wait on when we have no work, and which
* gets signaled when our queue becomes nonempty. */
@@ -92,14 +92,14 @@ struct threadpool_s {
/** Number of bits needed to hold all legal values of workqueue_priority_t */
#define WORKQUEUE_PRIORITY_BITS 2
-struct workqueue_entry_s {
+struct workqueue_entry_t {
/** The next workqueue_entry_t that's pending on the same thread or
* reply queue. */
- TOR_TAILQ_ENTRY(workqueue_entry_s) next_work;
+ TOR_TAILQ_ENTRY(workqueue_entry_t) next_work;
/** The threadpool to which this workqueue_entry_t was assigned. This field
* is set when the workqueue_entry_t is created, and won't be cleared until
* after it's handled in the main thread. */
- struct threadpool_s *on_pool;
+ struct threadpool_t *on_pool;
/** True iff this entry is waiting for a worker to start processing it. */
uint8_t pending;
/** Priority of this entry. */
@@ -112,22 +112,22 @@ struct workqueue_entry_s {
void *arg;
};
-struct replyqueue_s {
+struct replyqueue_t {
/** Mutex to protect the answers field */
tor_mutex_t lock;
/** Doubly-linked list of answers that the reply queue needs to handle. */
- TOR_TAILQ_HEAD(, workqueue_entry_s) answers;
+ TOR_TAILQ_HEAD(, workqueue_entry_t) answers;
/** Mechanism to wake up the main thread when it is receiving answers. */
alert_sockets_t alert;
};
/** A worker thread represents a single thread in a thread pool. */
-typedef struct workerthread_s {
+typedef struct workerthread_t {
/** Which thread it this? In range 0..in_pool->n_threads-1 */
int index;
/** The pool this thread is a part of. */
- struct threadpool_s *in_pool;
+ struct threadpool_t *in_pool;
/** User-supplied state field that we pass to the worker functions of each
* work item. */
void *state;
diff --git a/src/lib/evloop/workqueue.h b/src/lib/evloop/workqueue.h
index d0ee8f2be2..43cfebf788 100644
--- a/src/lib/evloop/workqueue.h
+++ b/src/lib/evloop/workqueue.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,12 +13,12 @@
/** A replyqueue is used to tell the main thread about the outcome of
* work that we queued for the workers. */
-typedef struct replyqueue_s replyqueue_t;
+typedef struct replyqueue_t replyqueue_t;
/** A thread-pool manages starting threads and passing work to them. */
-typedef struct threadpool_s threadpool_t;
+typedef struct threadpool_t threadpool_t;
/** A workqueue entry represents a request that has been passed to a thread
* pool. */
-typedef struct workqueue_entry_s workqueue_entry_t;
+typedef struct workqueue_entry_t workqueue_entry_t;
/** Possible return value from a work function: */
typedef enum workqueue_reply_t {
diff --git a/src/lib/fdio/fdio.c b/src/lib/fdio/fdio.c
index 2d0864cc19..56e3818f5c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,9 +28,10 @@
#include <stdlib.h>
#include <stdio.h>
-/** @{ */
-/** Some old versions of Unix didn't define constants for these values,
+/* Some old versions of Unix didn't define constants for these values,
* and instead expect you to say 0, 1, or 2. */
+
+/** @cond */
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
@@ -40,7 +41,7 @@
#ifndef SEEK_END
#define SEEK_END 2
#endif
-/** @} */
+/** @endcond */
/** Return the position of <b>fd</b> with respect to the start of the file. */
off_t
diff --git a/src/lib/fdio/fdio.h b/src/lib/fdio/fdio.h
index 8395af353b..99bc33c64b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,9 @@
#define TOR_FDIO_H
#include <stddef.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
off_t tor_fd_getpos(int fd);
int tor_fd_setpos(int fd, off_t pos);
diff --git a/src/lib/fdio/lib_fdio.md b/src/lib/fdio/lib_fdio.md
new file mode 100644
index 0000000000..9fe4b4d2be
--- /dev/null
+++ b/src/lib/fdio/lib_fdio.md
@@ -0,0 +1,5 @@
+@dir /lib/fdio
+@brief lib/fdio: Code to read/write on file descriptors.
+
+(This module also handles sockets, on platforms where a socket is not a kind
+of fd.)
diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c
index 0d5d56b335..9583093c12 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -152,6 +152,7 @@ config_process_include(const char *path, int recursion_level, int extended,
int rv = -1;
SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) {
+ log_notice(LD_CONFIG, "Including configuration file \"%s\".", config_file);
config_line_t *included_config = NULL;
config_line_t *included_config_last = NULL;
if (config_get_included_config(config_file, recursion_level, extended,
diff --git a/src/lib/fs/conffile.h b/src/lib/fs/conffile.h
index 29115e1085..cbfe4ec7c9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 390836b048..3432df0299 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/dir.h b/src/lib/fs/dir.h
index 9ff81faa42..c4ab430891 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 b98a51a287..aeaeb5daea 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h
index ed983f3b3c..a109cd6248 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/freespace.c b/src/lib/fs/freespace.c
index ee0f93073d..511f2a0b98 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/lib_fs.md b/src/lib/fs/lib_fs.md
new file mode 100644
index 0000000000..3b5b0ac7d5
--- /dev/null
+++ b/src/lib/fs/lib_fs.md
@@ -0,0 +1,9 @@
+@dir /lib/fs
+@brief lib/fs: Files, filenames, directories, etc.
+
+This module is mostly a set of compatibility wrappers around
+operating-system-specific filesystem access.
+
+It also contains a set of convenience functions for safely writing to files,
+creating directories, and so on.
+
diff --git a/src/lib/fs/lockfile.c b/src/lib/fs/lockfile.c
index 933ff1e02f..c081f57a5d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/lockfile.h b/src/lib/fs/lockfile.h
index fc0281e253..91effd701d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/mmap.c b/src/lib/fs/mmap.c
index f71c0cff7a..cc1c40b7ab 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -42,8 +42,8 @@
* failure, return NULL. Sets errno properly, using ERANGE to mean
* "empty file". Must only be called on trusted Tor-owned files, as changing
* the underlying file's size causes unspecified behavior. */
-tor_mmap_t *
-tor_mmap_file(const char *filename)
+MOCK_IMPL(tor_mmap_t *,
+tor_mmap_file,(const char *filename))
{
int fd; /* router file */
char *string;
@@ -111,8 +111,8 @@ tor_mmap_file(const char *filename)
}
/** Release storage held for a memory mapping; returns 0 on success,
* or -1 on failure (and logs a warning). */
-int
-tor_munmap_file(tor_mmap_t *handle)
+MOCK_IMPL(int,
+tor_munmap_file,(tor_mmap_t *handle))
{
int res;
@@ -132,8 +132,8 @@ tor_munmap_file(tor_mmap_t *handle)
return res;
}
#elif defined(_WIN32)
-tor_mmap_t *
-tor_mmap_file(const char *filename)
+MOCK_IMPL(tor_mmap_t *,
+tor_mmap_file,(const char *filename))
{
TCHAR tfilename[MAX_PATH]= {0};
tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t));
@@ -213,8 +213,8 @@ tor_mmap_file(const char *filename)
}
/* Unmap the file, and return 0 for success or -1 for failure */
-int
-tor_munmap_file(tor_mmap_t *handle)
+MOCK_IMPL(int,
+tor_munmap_file,(tor_mmap_t *handle))
{
if (handle == NULL)
return 0;
diff --git a/src/lib/fs/mmap.h b/src/lib/fs/mmap.h
index 61aad544b2..e142bd78c3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,7 @@
#define TOR_MMAP_H
#include "lib/cc/compat_compiler.h"
+#include "lib/testsupport/testsupport.h"
#include <stddef.h>
#ifdef _WIN32
@@ -35,7 +36,7 @@ typedef struct tor_mmap_t {
} tor_mmap_t;
-tor_mmap_t *tor_mmap_file(const char *filename);
-int tor_munmap_file(tor_mmap_t *handle);
+MOCK_DECL(tor_mmap_t *, tor_mmap_file, (const char *filename));
+MOCK_DECL(int, tor_munmap_file, (tor_mmap_t *handle));
#endif /* !defined(TOR_MMAP_H) */
diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c
index 28dde62aea..0d57be4b06 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -255,9 +255,10 @@ alloc_getcwd(void)
#endif /* !defined(_WIN32) */
/** Expand possibly relative path <b>fname</b> to an absolute path.
- * Return a newly allocated string, possibly equal to <b>fname</b>. */
+ * Return a newly allocated string, which may be a duplicate of <b>fname</b>.
+ */
char *
-make_path_absolute(char *fname)
+make_path_absolute(const char *fname)
{
#ifdef _WIN32
char *absfname_malloced = _fullpath(NULL, fname, 1);
diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h
index 28a1838b88..f0e253c556 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,6 +25,6 @@ char *expand_filename(const char *filename);
int path_is_relative(const char *filename);
void clean_fname_for_stat(char *name);
int get_parent_directory(char *fname);
-char *make_path_absolute(char *fname);
+char *make_path_absolute(const char *fname);
#endif /* !defined(TOR_PATH_H) */
diff --git a/src/lib/fs/storagedir.c b/src/lib/fs/storagedir.c
index 2caddf1ad9..5e4f9ee257 100644
--- a/src/lib/fs/storagedir.c
+++ b/src/lib/fs/storagedir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/storagedir.h b/src/lib/fs/storagedir.h
index 7e6633a0bb..9997550b8f 100644
--- a/src/lib/fs/storagedir.h
+++ b/src/lib/fs/storagedir.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,7 +15,7 @@
typedef struct storage_dir_t storage_dir_t;
struct config_line_t;
-struct sandbox_cfg_elem;
+struct sandbox_cfg_elem_t;
struct tor_mmap_t;
struct smartlist_t;
@@ -25,7 +25,7 @@ void storage_dir_free_(storage_dir_t *d);
FREE_AND_NULL(storage_dir_t, storage_dir_free_, (d))
int storage_dir_register_with_sandbox(storage_dir_t *d,
- struct sandbox_cfg_elem **cfg);
+ struct sandbox_cfg_elem_t **cfg);
const struct smartlist_t *storage_dir_list(storage_dir_t *d);
uint64_t storage_dir_get_usage(storage_dir_t *d);
struct tor_mmap_t *storage_dir_map(storage_dir_t *d, const char *fname);
diff --git a/src/lib/fs/userdb.c b/src/lib/fs/userdb.c
index 95205c670e..40fc4dae97 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/userdb.h b/src/lib/fs/userdb.h
index 5e5ddb89a3..4341237c5f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/winlib.c b/src/lib/fs/winlib.c
index b7302bd4ca..65ccdae40b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/winlib.h b/src/lib/fs/winlib.h
index 7237226c76..27837ac46e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/geoip/country.h b/src/lib/geoip/country.h
index a24a1c4c0d..feab554a16 100644
--- a/src/lib/geoip/country.h
+++ b/src/lib/geoip/country.h
@@ -1,9 +1,14 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file country.h
+ * @brief Country type for geoip.
+ **/
+
#ifndef TOR_COUNTRY_H
#define TOR_COUNTRY_H
@@ -11,6 +16,7 @@
/** A signed integer representing a country code. */
typedef int16_t country_t;
+/** Maximum value for country_t. */
#define COUNTRY_MAX INT16_MAX
#endif /* !defined(TOR_COUNTRY_H) */
diff --git a/src/lib/geoip/geoip.c b/src/lib/geoip/geoip.c
index 70b1c2dc8c..ee03d5baa1 100644
--- a/src/lib/geoip/geoip.c
+++ b/src/lib/geoip/geoip.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -70,12 +70,18 @@ static smartlist_t *geoip_countries = NULL;
* The index is encoded in the pointer, and 1 is added so that NULL can mean
* not found. */
static strmap_t *country_idxplus1_by_lc_code = NULL;
-/** Lists of all known geoip_ipv4_entry_t and geoip_ipv6_entry_t, sorted
- * by their respective ip_low. */
-static smartlist_t *geoip_ipv4_entries = NULL, *geoip_ipv6_entries = NULL;
-
-/** SHA1 digest of the GeoIP files to include in extra-info descriptors. */
+/** List of all known geoip_ipv4_entry_t sorted
+ * by their respective ip_low values. */
+static smartlist_t *geoip_ipv4_entries = NULL;
+/** List of all known geoip_ipv6_entry_t, sorted by their respective
+ * ip_low values. */
+static smartlist_t *geoip_ipv6_entries = NULL;
+
+/** SHA1 digest of the IPv4 GeoIP file to include in extra-info
+ * descriptors. */
static char geoip_digest[DIGEST_LEN];
+/** SHA1 digest of the IPv6 GeoIP file to include in extra-info
+ * descriptors. */
static char geoip6_digest[DIGEST_LEN];
/** Return a list of geoip_country_t for all known countries. */
diff --git a/src/lib/geoip/geoip.h b/src/lib/geoip/geoip.h
index f872ebd25f..2fc7fae754 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -31,6 +31,7 @@ int geoip_get_country_by_ipv6(const struct in6_addr *addr);
/** A per-country GeoIP record. */
typedef struct geoip_country_t {
+ /** A nul-terminated two-letter country-code. */
char countrycode[3];
} geoip_country_t;
diff --git a/src/lib/geoip/lib_geoip.md b/src/lib/geoip/lib_geoip.md
new file mode 100644
index 0000000000..a3ee39d574
--- /dev/null
+++ b/src/lib/geoip/lib_geoip.md
@@ -0,0 +1,3 @@
+@dir /lib/geoip
+@brief lib/geoip: IP-to-country mapping
+
diff --git a/src/lib/intmath/addsub.c b/src/lib/intmath/addsub.c
index 12146f4e72..44613417fa 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/addsub.h b/src/lib/intmath/addsub.h
index 3f745d457d..bca911103b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/bits.c b/src/lib/intmath/bits.c
index 2158790e3f..dace9ffe18 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/bits.h b/src/lib/intmath/bits.h
index c1483a18b8..687651ba35 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/cmp.h b/src/lib/intmath/cmp.h
index 67a738861b..4e6c2b649a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/lib_intmath.md b/src/lib/intmath/lib_intmath.md
new file mode 100644
index 0000000000..4446b715cb
--- /dev/null
+++ b/src/lib/intmath/lib_intmath.md
@@ -0,0 +1,2 @@
+@dir /lib/intmath
+@brief lib/intmath: Integer mathematics.
diff --git a/src/lib/intmath/logic.h b/src/lib/intmath/logic.h
index b2f77462e1..b5fb79f66e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/muldiv.c b/src/lib/intmath/muldiv.c
index 6a292db7ba..875cf1bbf2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -69,6 +69,20 @@ gcd64(uint64_t a, uint64_t b)
return a;
}
+/** Return the unsigned integer product of <b>a</b> and <b>b</b>. If overflow
+ * is detected, return UINT64_MAX instead. */
+uint64_t
+tor_mul_u64_nowrap(uint64_t a, uint64_t b)
+{
+ if (a == 0 || b == 0) {
+ return 0;
+ } else if (PREDICT_UNLIKELY(UINT64_MAX / a < b)) {
+ return UINT64_MAX;
+ } else {
+ return a*b;
+ }
+}
+
/* Given a fraction *<b>numer</b> / *<b>denom</b>, simplify it.
* Requires that the denominator is greater than 0. */
void
diff --git a/src/lib/intmath/muldiv.h b/src/lib/intmath/muldiv.h
index 64500b6dce..43700cf1dc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,6 +18,8 @@ unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
+uint64_t tor_mul_u64_nowrap(uint64_t a, uint64_t b);
+
void simplify_fraction64(uint64_t *numer, uint64_t *denom);
/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b>
diff --git a/src/lib/intmath/weakrng.c b/src/lib/intmath/weakrng.c
index 99c9252c2b..a29a6a086b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/weakrng.h b/src/lib/intmath/weakrng.h
index 40941e59b2..0394e05f79 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,8 +19,11 @@ typedef struct tor_weak_rng_t {
uint32_t state;
} tor_weak_rng_t;
+#ifndef COCCI
#define TOR_WEAK_RNG_INIT {383745623}
+#endif
#define TOR_WEAK_RANDOM_MAX (INT_MAX)
+
void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed);
int32_t tor_weak_random(tor_weak_rng_t *weak_rng);
int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
diff --git a/src/lib/lib.md b/src/lib/lib.md
new file mode 100644
index 0000000000..4f77a4c1d0
--- /dev/null
+++ b/src/lib/lib.md
@@ -0,0 +1,131 @@
+@dir /lib
+@brief lib: low-level functionality.
+
+The "lib" directory contains low-level functionality. In general, this
+code is not necessarily Tor-specific, but is instead possibly useful for
+other applications.
+
+The modules in `lib` are currently well-factored: each one depends
+only on lower-level modules. You can see an up-to-date list of the
+modules, sorted from lowest to highest level, by running
+`./scripts/maint/practracker/includes.py --toposort`.
+
+As of this writing, the library modules are (from lowest to highest
+level):
+
+ - \refdir{lib/cc} -- Macros for managing the C compiler and
+ language.
+
+ - \refdir{lib/version} -- Holds the current version of Tor.
+
+ - \refdir{lib/testsupport} -- Helpers for making
+ test-only code, and test mocking support.
+
+ - \refdir{lib/defs} -- Lowest-level constants.
+
+ - \refdir{lib/subsys} -- Types used for declaring a
+ "subsystem". (_A subsystem is a module with support for initialization,
+ shutdown, configuration, and so on._)
+
+ - \refdir{lib/conf} -- For declaring configuration options.
+
+ - \refdir{lib/arch} -- For handling differences in CPU
+ architecture.
+
+ - \refdir{lib/err} -- Lowest-level error handling code.
+
+ - \refdir{lib/malloc} -- Memory management.
+ management.
+
+ - \refdir{lib/intmath} -- Integer mathematics.
+
+ - \refdir{lib/fdio} -- For
+ reading and writing n file descriptors.
+
+ - \refdir{lib/lock} -- Simple locking support.
+ (_Lower-level than the rest of the threading code._)
+
+ - \refdir{lib/ctime} -- Constant-time code to avoid
+ side-channels.
+
+ - \refdir{lib/string} -- Low-level string manipulation.
+
+ - \refdir{lib/wallclock} --
+ For inspecting and manipulating the current (UTC) time.
+
+ - \refdir{lib/osinfo} -- For inspecting the OS version
+ and capabilities.
+
+ - \refdir{lib/smartlist_core} -- The bare-bones
+ pieces of our dynamic array ("smartlist") implementation.
+
+ - \refdir{lib/log} -- Log messages to files, syslogs, etc.
+
+ - \refdir{lib/container} -- General purpose containers,
+ including dynamic arrays ("smartlists"), hashtables, bit arrays,
+ etc.
+
+ - \refdir{lib/trace} -- A general-purpose API
+ function-tracing functionality Tor. (_Currently not much used._)
+
+ - \refdir{lib/thread} -- Mid-level Threading.
+
+ - \refdir{lib/term} -- Terminal manipulation
+ (like reading a password from the user).
+
+ - \refdir{lib/memarea} -- A fast
+ "arena" style allocator, where the data is freed all at once.
+
+ - \refdir{lib/encoding} -- Encoding
+ data in various formats, datatypes, and transformations.
+
+ - \refdir{lib/dispatch} -- A general-purpose in-process
+ message delivery system.
+
+ - \refdir{lib/sandbox} -- Our Linux seccomp2 sandbox
+ implementation.
+
+ - \refdir{lib/pubsub} -- A publish/subscribe message passing system.
+
+ - \refdir{lib/fs} -- Files, filenames, directories, etc.
+
+ - \refdir{lib/confmgt} -- Parse, encode, and manipulate onfiguration files.
+
+ - \refdir{lib/crypt_ops} -- Cryptographic operations.
+
+ - \refdir{lib/meminfo} -- Functions for inspecting our
+ memory usage, if the malloc implementation exposes that to us.
+
+ - \refdir{lib/time} -- Higher level time functions, including
+ fine-gained and monotonic timers.
+
+ - \refdir{lib/math} -- Floating-point mathematical utilities.
+
+ - \refdir{lib/buf} -- An efficient byte queue.
+
+ - \refdir{lib/net} -- Networking code, including address
+ manipulation, compatibility wrappers, etc.
+
+ - \refdir{lib/compress} -- Wraps several compression libraries.
+
+ - \refdir{lib/geoip} -- IP-to-country mapping.
+
+ - \refdir{lib/tls} -- TLS library wrappers.
+
+ - \refdir{lib/evloop} -- Low-level event-loop.
+
+ - \refdir{lib/process} -- Launch and manage subprocesses.
+
+### What belongs in lib?
+
+In general, if you can imagine some program wanting the functionality
+you're writing, even if that program had nothing to do with Tor, your
+functionality belongs in lib.
+
+If it falls into one of the existing "lib" categories, your
+functionality belongs in lib.
+
+If you are using platform-specific `ifdef`s to manage compatibility
+issues among platforms, you should probably consider whether you can
+put your code into lib.
+
diff --git a/src/lib/llharden/.may_include b/src/lib/llharden/.may_include
new file mode 100644
index 0000000000..038237dadf
--- /dev/null
+++ b/src/lib/llharden/.may_include
@@ -0,0 +1,3 @@
+lib/llharden/*.h
+lib/subsys/*.h
+orconfig.h
diff --git a/src/lib/llharden/include.am b/src/lib/llharden/include.am
new file mode 100644
index 0000000000..0a4788c7dc
--- /dev/null
+++ b/src/lib/llharden/include.am
@@ -0,0 +1,19 @@
+
+noinst_LIBRARIES += src/lib/libtor-llharden.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-llharden-testing.a
+endif
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+src_lib_libtor_llharden_a_SOURCES = \
+ src/lib/llharden/winprocess_sys.c
+
+src_lib_libtor_llharden_testing_a_SOURCES = \
+ $(src_lib_libtor_llharden_a_SOURCES)
+src_lib_libtor_llharden_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_llharden_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/lib/llharden/winprocess_sys.h
diff --git a/src/lib/llharden/lib_llharden.md b/src/lib/llharden/lib_llharden.md
new file mode 100644
index 0000000000..69e9af5327
--- /dev/null
+++ b/src/lib/llharden/lib_llharden.md
@@ -0,0 +1,6 @@
+@dir /lib/llharden
+@brief lib/llharden: low-level unconditional process hardening
+
+This module contains process hardening code that we want to run before any
+other code, including configuration. It needs to be self-contained, since
+nothing else will be initialized at this point.
diff --git a/src/lib/process/winprocess_sys.c b/src/lib/llharden/winprocess_sys.c
index ad65886422..f2c88d8c75 100644
--- a/src/lib/process/winprocess_sys.c
+++ b/src/lib/llharden/winprocess_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,7 +8,7 @@
#include "orconfig.h"
#include "lib/subsys/subsys.h"
-#include "lib/process/winprocess_sys.h"
+#include "lib/llharden/winprocess_sys.h"
#include <stdbool.h>
#include <stddef.h>
@@ -58,6 +58,7 @@ subsys_winprocess_initialize(void)
const subsys_fns_t sys_winprocess = {
.name = "winprocess",
+ SUBSYS_DECLARE_LOCATION(),
/* HeapEnableTerminationOnCorruption and setdeppolicy() are security
* features, we want them to run first. */
.level = -100,
diff --git a/src/lib/process/winprocess_sys.h b/src/lib/llharden/winprocess_sys.h
index 7ab2aa04a6..bece1b3da9 100644
--- a/src/lib/process/winprocess_sys.h
+++ b/src/lib/llharden/winprocess_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 670bd0174c..b0084a3484 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e0c3d7cb78..5631993cc4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,6 +58,11 @@ void tor_mutex_init_nonrecursive(tor_mutex_t *m);
void tor_mutex_acquire(tor_mutex_t *m);
void tor_mutex_release(tor_mutex_t *m);
void tor_mutex_free_(tor_mutex_t *m);
+/**
+ * @copydoc tor_mutex_free_
+ *
+ * Additionally, set the pointer <b>m</b> to NULL.
+ **/
#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m))
void tor_mutex_uninit(tor_mutex_t *m);
diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c
index f82ad9f0e8..ac83c42a47 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,8 +17,14 @@
* "recursive" mutexes (i.e., once we can re-lock if we're already holding
* them.) */
static pthread_mutexattr_t attr_recursive;
+/**
+ * True iff <b>attr_recursive</b> has been initialized.
+ **/
static int attr_initialized = 0;
+/**
+ * Initialize the locking module, if it is not already initialized.
+ **/
void
tor_locking_init(void)
{
diff --git a/src/lib/lock/compat_mutex_winthreads.c b/src/lib/lock/compat_mutex_winthreads.c
index b0f5999e42..5fe6870a93 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/lock/lib_lock.md b/src/lib/lock/lib_lock.md
new file mode 100644
index 0000000000..6f6727bfc2
--- /dev/null
+++ b/src/lib/lock/lib_lock.md
@@ -0,0 +1,6 @@
+@dir /lib/lock
+@brief lib/lock: Simple locking support.
+
+This module is more low-level than the rest of the threading code, since it
+is needed by more intermediate-level modules.
+
diff --git a/src/lib/log/escape.c b/src/lib/log/escape.c
index 6ca01c6963..88ca52a78c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/escape.h b/src/lib/log/escape.h
index 0b9fc3406b..0d1eaef4c1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/lib_log.md b/src/lib/log/lib_log.md
new file mode 100644
index 0000000000..8740d6a02f
--- /dev/null
+++ b/src/lib/log/lib_log.md
@@ -0,0 +1,10 @@
+@dir /lib/log
+@brief lib/log: Log messages to files, syslogs, etc.
+
+You can think of this as the logical "midpoint" of the
+\refdir{lib} code": much of the higher-level code is higher-level
+_because_ it uses the logging module, and much of the lower-level code is
+specifically written to avoid having to log, because the logging module
+depends on it.
+
+
diff --git a/src/lib/log/log.c b/src/lib/log/log.c
index c53db46a8c..9ee87c0668 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -276,8 +276,8 @@ static int log_time_granularity = 1;
/** Define log time granularity for all logs to be <b>granularity_msec</b>
* milliseconds. */
-void
-set_log_time_granularity(int granularity_msec)
+MOCK_IMPL(void,
+set_log_time_granularity,(int granularity_msec))
{
log_time_granularity = granularity_msec;
tor_log_sigsafe_err_set_granularity(granularity_msec);
@@ -523,7 +523,7 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
* pass them, and some very old ones do not detect overflow so well.
* Regrettably, they call their maximum line length MAXLINE. */
#if MAXLINE < 64
-#warn "MAXLINE is a very low number; it might not be from syslog.h after all"
+#warning "MAXLINE is very low; it might not be from syslog.h."
#endif
char *m = msg_after_prefix;
if (msg_len >= MAXLINE)
@@ -665,20 +665,15 @@ tor_log_update_sigsafe_err_fds(void)
const logfile_t *lf;
int found_real_stderr = 0;
- /* log_fds and err_fds contain matching entries: log_fds are the fds used by
- * the log module, and err_fds are the fds used by the err module.
- * For stdio logs, the log_fd and err_fd values are identical.
- * For file logs, the err_fd is a dup() of the log_fd.
- */
- int log_fds[TOR_SIGSAFE_LOG_MAX_FDS];
- int err_fds[TOR_SIGSAFE_LOG_MAX_FDS];
+ /* The fds are the file descriptors of tor's stdout, stderr, and file
+ * logs. The log and err modules flush these fds during their shutdowns. */
+ int fds[TOR_SIGSAFE_LOG_MAX_FDS];
int n_fds;
LOCK_LOGS();
/* Reserve the first one for stderr. This is safe because when we daemonize,
- * we dup2 /dev/null to stderr.
- * For stderr, log_fds and err_fds are the same. */
- log_fds[0] = err_fds[0] = STDERR_FILENO;
+ * we dup2 /dev/null to stderr. */
+ fds[0] = STDERR_FILENO;
n_fds = 1;
for (lf = logfiles; lf; lf = lf->next) {
@@ -693,19 +688,11 @@ tor_log_update_sigsafe_err_fds(void)
(LD_BUG|LD_GENERAL)) {
if (lf->fd == STDERR_FILENO)
found_real_stderr = 1;
- /* Avoid duplicates by checking the log module fd against log_fds */
- if (int_array_contains(log_fds, n_fds, lf->fd))
+ /* Avoid duplicates by checking the log module fd against fds */
+ if (int_array_contains(fds, n_fds, lf->fd))
continue;
- /* Update log_fds using the log module's fd */
- log_fds[n_fds] = lf->fd;
- if (lf->needs_close) {
- /* File log fds are duplicated, because close_log() closes the log
- * module's fd. Both refer to the same file. */
- err_fds[n_fds] = dup(lf->fd);
- } else {
- /* stdio log fds are not closed by the log module. */
- err_fds[n_fds] = lf->fd;
- }
+ /* Update fds using the log module's fd */
+ fds[n_fds] = lf->fd;
n_fds++;
if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS)
break;
@@ -713,20 +700,19 @@ tor_log_update_sigsafe_err_fds(void)
}
if (!found_real_stderr &&
- int_array_contains(log_fds, n_fds, STDOUT_FILENO)) {
+ int_array_contains(fds, n_fds, STDOUT_FILENO)) {
/* Don't use a virtual stderr when we're also logging to stdout.
* If we reached max_fds logs, we'll now have (max_fds - 1) logs.
* That's ok, max_fds is large enough that most tor instances don't exceed
* it. */
raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */
--n_fds;
- log_fds[0] = log_fds[n_fds];
- err_fds[0] = err_fds[n_fds];
+ fds[0] = fds[n_fds];
}
UNLOCK_LOGS();
- tor_log_set_sigsafe_err_fds(err_fds, n_fds);
+ tor_log_set_sigsafe_err_fds(fds, n_fds);
}
/** Add to <b>out</b> a copy of every currently configured log file name. Used
@@ -835,6 +821,32 @@ logs_free_all(void)
* log mutex. */
}
+/** Flush the signal-safe log files.
+ *
+ * This function is safe to call from a signal handler. It is currenly called
+ * by the BUG() macros, when terminating the process on an abnormal condition.
+ */
+void
+logs_flush_sigsafe(void)
+{
+ /* If we don't have fsync() in unistd.h, we can't flush the logs. */
+#ifdef HAVE_FSYNC
+ logfile_t *victim, *next;
+ /* We can't LOCK_LOGS() in a signal handler, because it may call
+ * signal-unsafe functions. And we can't deallocate memory, either. */
+ next = logfiles;
+ logfiles = NULL;
+ while (next) {
+ victim = next;
+ next = next->next;
+ if (victim->needs_close) {
+ /* We can't do anything useful if the flush fails. */
+ (void)fsync(victim->fd);
+ }
+ }
+#endif /* defined(HAVE_FSYNC) */
+}
+
/** Remove and free the log entry <b>victim</b> from the linked-list
* logfiles (it is probably present, but it might not be due to thread
* racing issues). After this function is called, the caller shouldn't
@@ -907,9 +919,9 @@ set_log_severity_config(int loglevelMin, int loglevelMax,
/** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
* to <b>fd</b>. Copies <b>severity</b>. Helper: does no locking. */
-static void
-add_stream_log_impl(const log_severity_list_t *severity,
- const char *name, int fd)
+MOCK_IMPL(STATIC void,
+add_stream_log_impl,(const log_severity_list_t *severity,
+ const char *name, int fd))
{
logfile_t *lf;
lf = tor_malloc_zero(sizeof(logfile_t));
@@ -965,18 +977,16 @@ logs_set_domain_logging(int enabled)
UNLOCK_LOGS();
}
-/** Add a log handler to receive messages during startup (before the real
- * logs are initialized).
+/** Add a log handler to accept messages when no other log is configured.
*/
void
-add_temp_log(int min_severity)
+add_default_log(int min_severity)
{
log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
set_log_severity_config(min_severity, LOG_ERR, s);
LOCK_LOGS();
- add_stream_log_impl(s, "<temp>", fileno(stdout));
+ add_stream_log_impl(s, "<default>", fileno(stdout));
tor_free(s);
- logfiles->is_temporary = 1;
UNLOCK_LOGS();
}
@@ -1119,8 +1129,7 @@ flush_log_messages_from_startup(void)
UNLOCK_LOGS();
}
-/** Close any log handlers added by add_temp_log() or marked by
- * mark_logs_temp(). */
+/** Close any log handlers marked by mark_logs_temp(). */
void
close_temp_logs(void)
{
@@ -1172,10 +1181,10 @@ mark_logs_temp(void)
* opening the logfile failed, -1 is returned and errno is set appropriately
* (by open(2)). Takes ownership of fd.
*/
-int
-add_file_log(const log_severity_list_t *severity,
- const char *filename,
- int fd)
+MOCK_IMPL(int,
+add_file_log,(const log_severity_list_t *severity,
+ const char *filename,
+ int fd))
{
logfile_t *lf;
diff --git a/src/lib/log/log.h b/src/lib/log/log.h
index f09c63cdd9..aafbf9be2f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,9 +23,11 @@
#include <syslog.h>
#define LOG_WARN LOG_WARNING
#if LOG_DEBUG < LOG_ERR
+#ifndef COCCI
#error "Your syslog.h thinks high numbers are more important. " \
"We aren't prepared to deal with that."
#endif
+#endif /* LOG_DEBUG < LOG_ERR */
#else /* !defined(HAVE_SYSLOG_H) */
/* Note: Syslog's logging code refers to priorities, with 0 being the most
* important. Thus, all our comparisons needed to be reversed when we added
@@ -163,11 +165,11 @@ int parse_log_severity_config(const char **cfg,
log_severity_list_t *severity_out);
void set_log_severity_config(int minSeverity, int maxSeverity,
log_severity_list_t *severity_out);
-void add_stream_log(const log_severity_list_t *severity, const char *name,
- int fd);
-int add_file_log(const log_severity_list_t *severity,
- const char *filename,
- int fd);
+void add_stream_log(const log_severity_list_t *severity,
+ const char *name, int fd);
+MOCK_DECL(int, add_file_log,(const log_severity_list_t *severity,
+ const char *filename,
+ int fd));
#ifdef HAVE_SYSLOG_H
int add_syslog_log(const log_severity_list_t *severity,
@@ -184,7 +186,8 @@ void logs_set_domain_logging(int enabled);
int get_min_log_level(void);
void switch_logs_debug(void);
void logs_free_all(void);
-void add_temp_log(int min_severity);
+void logs_flush_sigsafe(void);
+void add_default_log(int min_severity);
void close_temp_logs(void);
void rollback_log_changes(void);
void mark_logs_temp(void);
@@ -193,7 +196,7 @@ void change_callback_log_severity(int loglevelMin, int loglevelMax,
void flush_pending_log_callbacks(void);
void flush_log_messages_from_startup(void);
void log_set_application_name(const char *name);
-void set_log_time_granularity(int granularity_msec);
+MOCK_DECL(void, set_log_time_granularity,(int granularity_msec));
void truncate_logs(void);
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
@@ -305,7 +308,9 @@ extern const log_domain_mask_t LD_GENERAL_;
MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain,
const char *funcname, const char *suffix, const char *format,
va_list ap) CHECK_PRINTF(5,0));
-#endif
+MOCK_DECL(STATIC void, add_stream_log_impl,(
+ const log_severity_list_t *severity, const char *name, int fd));
+#endif /* defined(LOG_PRIVATE) */
#if defined(LOG_PRIVATE) || defined(TOR_UNIT_TESTS)
/** Given a severity, yields an index into log_severity_list_t.masks to use
diff --git a/src/lib/log/log_sys.c b/src/lib/log/log_sys.c
index 826358546a..021c05d3e6 100644
--- a/src/lib/log/log_sys.c
+++ b/src/lib/log/log_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,6 +28,7 @@ subsys_logging_shutdown(void)
const subsys_fns_t sys_logging = {
.name = "log",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
/* Logging depends on threads, approx time, raw logging, and security.
* Most other lib modules depend on logging. */
diff --git a/src/lib/log/log_sys.h b/src/lib/log/log_sys.h
index 7043253066..523c2e5008 100644
--- a/src/lib/log/log_sys.h
+++ b/src/lib/log/log_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c
index 5eec742aa7..ac401fb398 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h
index 1db54ba726..e9b55d40dc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -45,7 +45,9 @@ typedef struct ratelim_t {
int n_calls_since_last_time;
} ratelim_t;
+#ifndef COCCI
#define RATELIM_INIT(r) { (r), 0, 0 }
+#endif
#define RATELIM_TOOMANY (16*1000*1000)
char *rate_limit_log(ratelim_t *lim, time_t now);
diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c
index af1ac40732..d698ddd8a6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -71,7 +71,6 @@ tor_set_failed_assertion_callback(void (*fn)(void))
/** Helper for tor_assert: report the assertion failure. */
void
-CHECK_PRINTF(5, 6)
tor_assertion_failed_(const char *fname, unsigned int line,
const char *func, const char *expr,
const char *fmt, ...)
@@ -104,7 +103,6 @@ tor_assertion_failed_(const char *fname, unsigned int line,
/** Helper for tor_assert_nonfatal: report the assertion failure. */
void
-CHECK_PRINTF(6, 7)
tor_bug_occurred_(const char *fname, unsigned int line,
const char *func, const char *expr,
int once, const char *fmt, ...)
@@ -163,7 +161,8 @@ tor_bug_occurred_(const char *fname, unsigned int line,
/**
* Call the tor_raw_abort_() function to close raw logs, then kill the current
- * process with a fatal error.
+ * process with a fatal error. But first, close the file-based log file
+ * descriptors, so error messages are written before process termination.
*
* (This is a separate function so that we declare it in util_bug.h without
* including torerr.h in all the users of util_bug.h)
@@ -171,6 +170,7 @@ tor_bug_occurred_(const char *fname, unsigned int line,
void
tor_abort_(void)
{
+ logs_flush_sigsafe();
tor_raw_abort_();
}
diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h
index 7eaa6173c8..6b27b36f03 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -131,7 +131,9 @@
#undef BUG
// Coverity defines this in global headers; let's override it. This is a
// magic coverity-only preprocessor thing.
+#ifndef COCCI
#nodef BUG(x) (x)
+#endif
#endif /* defined(__COVERITY__) */
#if defined(__COVERITY__) || defined(__clang_analyzer__)
@@ -140,6 +142,8 @@
#define ALL_BUGS_ARE_FATAL
#endif
+/** Define ALL_BUGS_ARE_FATAL if you want Tor to crash when any problem comes
+ * up, so you can get a coredump and track things down. */
#ifdef ALL_BUGS_ARE_FATAL
#define tor_assert_nonfatal_unreached() tor_assert(0)
#define tor_assert_nonfatal(cond) tor_assert((cond))
@@ -152,6 +156,9 @@
(tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \
tor_abort_(), 1) \
: 0)
+#ifndef COCCI
+#define IF_BUG_ONCE(cond) if (BUG(cond))
+#endif
#elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
#define tor_assert_nonfatal_unreached() STMT_NIL
#define tor_assert_nonfatal(cond) ((void)(cond))
@@ -162,6 +169,9 @@
#define tor_assert_nonfatal_unreached_once() STMT_NIL
#define tor_assert_nonfatal_once(cond) ((void)(cond))
#define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0)
+#ifndef COCCI
+#define IF_BUG_ONCE(cond) if (BUG(cond))
+#endif
#else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */
#define tor_assert_nonfatal_unreached() STMT_BEGIN \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0, NULL); \
@@ -198,8 +208,8 @@
(ASSERT_PREDICT_UNLIKELY_(cond) ? \
(tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0,NULL),1) \
: 0)
-#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
+#ifndef COCCI
#ifdef __GNUC__
#define IF_BUG_ONCE__(cond,var) \
if (( { \
@@ -208,7 +218,7 @@
if (bool_result && !var) { \
var = 1; \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
- "!("#cond")", 1, NULL); \
+ ("!("#cond")"), 1, NULL); \
} \
bool_result; } ))
#else /* !defined(__GNUC__) */
@@ -218,16 +228,18 @@
(var ? 1 : \
(var=1, \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
- "!("#cond")", 1, NULL), \
+ ("!("#cond")"), 1, NULL), \
1)) \
: 0)
#endif /* defined(__GNUC__) */
+#endif /* !defined(COCCI) */
+
#define IF_BUG_ONCE_VARNAME_(a) \
warning_logged_on_ ## a ## __
#define IF_BUG_ONCE_VARNAME__(a) \
IF_BUG_ONCE_VARNAME_(a)
-/** This macro behaves as 'if (bug(x))', except that it only logs its
+/** This macro behaves as 'if (BUG(x))', except that it only logs its
* warning once, no matter how many times it triggers.
*/
@@ -235,9 +247,15 @@
IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond), \
IF_BUG_ONCE_VARNAME__(__LINE__))
-/** Define this if you want Tor to crash when any problem comes up,
- * so you can get a coredump and track things down. */
-// #define tor_fragile_assert() tor_assert_unreached(0)
+#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.
+ * (But release builds would continue.)
+ *
+ * To get the same behaviour in recent tor versions, define
+ * ALL_BUGS_ARE_FATAL, and use any non-fatal assertion or *BUG() macro.
+ */
#define tor_fragile_assert() tor_assert_nonfatal_unreached_once()
void tor_assertion_failed_(const char *fname, unsigned int line,
diff --git a/src/lib/log/win32err.c b/src/lib/log/win32err.c
index 03d5c9fad2..8136813aab 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/win32err.h b/src/lib/log/win32err.h
index ecfa88792d..5c1386a64d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/malloc/lib_malloc.md b/src/lib/malloc/lib_malloc.md
new file mode 100644
index 0000000000..ff61722f02
--- /dev/null
+++ b/src/lib/malloc/lib_malloc.md
@@ -0,0 +1,76 @@
+@dir /lib/malloc
+@brief lib/malloc: Wrappers and utilities for memory management.
+
+
+Tor imposes a few light wrappers over C's native malloc and free
+functions, to improve convenience, and to allow wholescale replacement
+of malloc and free as needed.
+
+You should never use 'malloc', 'calloc', 'realloc, or 'free' on their
+own; always use the variants prefixed with 'tor_'.
+They are the same as the standard C functions, with the following
+exceptions:
+
+ * `tor_free(NULL)` is a no-op.
+ * `tor_free()` is a macro that takes an lvalue as an argument and sets it to
+ NULL after freeing it. To avoid this behavior, you can use `tor_free_()`
+ instead.
+ * tor_malloc() and friends fail with an assertion if they are asked to
+ allocate a value so large that it is probably an underflow.
+ * It is always safe to `tor_malloc(0)`, regardless of whether your libc
+ allows it.
+ * `tor_malloc()`, `tor_realloc()`, and friends are never allowed to fail.
+ Instead, Tor will die with an assertion. This means that you never
+ need to check their return values. See the next subsection for
+ information on why we think this is a good idea.
+
+We define additional general-purpose memory allocation functions as well:
+
+ * `tor_malloc_zero(x)` behaves as `calloc(1, x)`, except the it makes clear
+ the intent to allocate a single zeroed-out value.
+ * `tor_reallocarray(x,y)` behaves as the OpenBSD reallocarray function.
+ Use it for cases when you need to realloc() in a multiplication-safe
+ way.
+
+And specific-purpose functions as well:
+
+ * `tor_strdup()` and `tor_strndup()` behaves as the underlying libc
+ functions, but use `tor_malloc()` instead of the underlying function.
+ * `tor_memdup()` copies a chunk of memory of a given size.
+ * `tor_memdup_nulterm()` copies a chunk of memory of a given size, then
+ NUL-terminates it just to be safe.
+
+#### Why assert on allocation failure?
+
+Why don't we allow `tor_malloc()` and its allies to return NULL?
+
+First, it's error-prone. Many programmers forget to check for NULL return
+values, and testing for `malloc()` failures is a major pain.
+
+Second, it's not necessarily a great way to handle OOM conditions. It's
+probably better (we think) to have a memory target where we dynamically free
+things ahead of time in order to stay under the target. Trying to respond to
+an OOM at the point of `tor_malloc()` failure, on the other hand, would involve
+a rare operation invoked from deep in the call stack. (Again, that's
+error-prone and hard to debug.)
+
+Third, thanks to the rise of Linux and other operating systems that allow
+memory to be overcommitted, you can't actually ever rely on getting a NULL
+from `malloc()` when you're out of memory; instead you have to use an approach
+closer to tracking the total memory usage.
+
+#### Conventions for your own allocation functions.
+
+Whenever you create a new type, the convention is to give it a pair of
+`x_new()` and `x_free_()` functions, named after the type.
+
+Calling `x_free(NULL)` should always be a no-op.
+
+There should additionally be an `x_free()` macro, defined in terms of
+`x_free_()`. This macro should set its lvalue to NULL. You can define it
+using the FREE_AND_NULL macro, as follows:
+
+```
+#define x_free(ptr) FREE_AND_NULL(x_t, x_free_, (ptr))
+```
+
diff --git a/src/lib/malloc/malloc.c b/src/lib/malloc/malloc.c
index 8628acfc97..9c9d600260 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/malloc/malloc.h b/src/lib/malloc/malloc.h
index 39a45901a1..80e8091adc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 9559cbe2d4..628966012a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -78,8 +78,8 @@
#endif /* defined(HAVE_MINHERIT) || ... */
#if defined(HAVE_MINHERIT) && !defined(FLAG_ZERO) && !defined(FLAG_NOINHERIT)
-#warn "minherit() is defined, but we couldn't find the right flag for it."
-#warn "This is probably a bug in Tor's support for this platform."
+#warning "minherit() is defined, but FLAG_ZERO/NOINHERIT are not."
+#warning "This is probably a bug in Tor's support for this platform."
#endif
/**
diff --git a/src/lib/malloc/map_anon.h b/src/lib/malloc/map_anon.h
index 4c4690e12f..0354668d65 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/fp.c b/src/lib/math/fp.c
index 49a2a6a2ca..c09555209e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -74,7 +74,7 @@ clamp_double_to_int64(double number)
branches that are not taken.
*/
#define PROBLEMATIC_FLOAT_CONVERSION_WARNING
-DISABLE_GCC_WARNING(float-conversion)
+DISABLE_GCC_WARNING("-Wfloat-conversion")
#endif /* (defined(MINGW_ANY)||defined(__FreeBSD__)) && GCC_VERSION >= 409 */
/*
@@ -84,7 +84,7 @@ DISABLE_GCC_WARNING(float-conversion)
#if defined(__clang__)
#if __has_warning("-Wdouble-promotion")
#define PROBLEMATIC_DOUBLE_PROMOTION_WARNING
-DISABLE_GCC_WARNING(double-promotion)
+DISABLE_GCC_WARNING("-Wdouble-promotion")
#endif
#endif /* defined(__clang__) */
@@ -115,10 +115,10 @@ DISABLE_GCC_WARNING(double-promotion)
return signbit(number) ? INT64_MIN : INT64_MAX;
#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING
-ENABLE_GCC_WARNING(double-promotion)
+ENABLE_GCC_WARNING("-Wdouble-promotion")
#endif
#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
-ENABLE_GCC_WARNING(float-conversion)
+ENABLE_GCC_WARNING("-Wfloat-conversion")
#endif
}
@@ -128,16 +128,16 @@ tor_isinf(double x)
{
/* Same as above, work around the "double promotion" warnings */
#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
-DISABLE_GCC_WARNING(float-conversion)
+DISABLE_GCC_WARNING("-Wfloat-conversion")
#endif
#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING
-DISABLE_GCC_WARNING(double-promotion)
+DISABLE_GCC_WARNING("-Wdouble-promotion")
#endif
return isinf(x);
#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING
-ENABLE_GCC_WARNING(double-promotion)
+ENABLE_GCC_WARNING("-Wdouble-promotion")
#endif
#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
-ENABLE_GCC_WARNING(float-conversion)
+ENABLE_GCC_WARNING("-Wfloat-conversion")
#endif
}
diff --git a/src/lib/math/fp.h b/src/lib/math/fp.h
index a73789c945..0a7a685485 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/laplace.c b/src/lib/math/laplace.c
index 302edb20b8..a0e67384e6 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,7 +29,7 @@ sample_laplace_distribution(double mu, double b, double p)
tor_assert(p >= 0.0 && p < 1.0);
/* This is the "inverse cumulative distribution function" from:
- * http://en.wikipedia.org/wiki/Laplace_distribution */
+ * https://en.wikipedia.org/wiki/Laplace_distribution */
if (p <= 0.0) {
/* Avoid taking log(0.0) == -INFINITY, as some processors or compiler
* options can cause the program to trap. */
diff --git a/src/lib/math/laplace.h b/src/lib/math/laplace.h
index 02b0e890f0..e0dd166bbd 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/lib_math.md b/src/lib/math/lib_math.md
new file mode 100644
index 0000000000..9cc256d24b
--- /dev/null
+++ b/src/lib/math/lib_math.md
@@ -0,0 +1,6 @@
+@dir /lib/math
+@brief lib/math: Floating-point math utilities.
+
+This module includes a bunch of floating-point compatibility code, and
+implementations for several probability distributions.
+
diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c
index d44dc28265..31d485120e 100644
--- a/src/lib/math/prob_distr.c
+++ b/src/lib/math/prob_distr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -52,14 +52,15 @@
#include <math.h>
#include <stddef.h>
+#ifndef COCCI
/** Declare a function that downcasts from a generic dist struct to the actual
* subtype probablity distribution it represents. */
#define DECLARE_PROB_DISTR_DOWNCAST_FN(name) \
static inline \
- const struct name * \
- dist_to_const_##name(const struct dist *obj) { \
+ const struct name##_t * \
+ dist_to_const_##name(const struct dist_t *obj) { \
tor_assert(obj->ops == &name##_ops); \
- return SUBTYPE_P(obj, struct name, base); \
+ return SUBTYPE_P(obj, struct name ## _t, base); \
}
DECLARE_PROB_DISTR_DOWNCAST_FN(uniform)
DECLARE_PROB_DISTR_DOWNCAST_FN(geometric)
@@ -67,6 +68,7 @@ DECLARE_PROB_DISTR_DOWNCAST_FN(logistic)
DECLARE_PROB_DISTR_DOWNCAST_FN(log_logistic)
DECLARE_PROB_DISTR_DOWNCAST_FN(genpareto)
DECLARE_PROB_DISTR_DOWNCAST_FN(weibull)
+#endif /* !defined(COCCI) */
/**
* Count number of one bits in 32-bit word.
@@ -178,8 +180,8 @@ clz32(uint32_t x)
/**
* Compute the logistic function: f(x) = 1/(1 + e^{-x}) = e^x/(1 + e^x).
- * Maps a log-odds-space probability in [-\infty, +\infty] into a direct-space
- * probability in [0,1]. Inverse of logit.
+ * Maps a log-odds-space probability in [-infinity, +infinity] into a
+ * direct-space probability in [0,1]. Inverse of logit.
*
* Ill-conditioned for large x; the identity logistic(-x) = 1 -
* logistic(x) and the function logistichalf(x) = logistic(x) - 1/2 may
@@ -266,7 +268,7 @@ logistic(double x)
/**
* Compute the logit function: log p/(1 - p). Defined on [0,1]. Maps
* a direct-space probability in [0,1] to a log-odds-space probability
- * in [-\infty, +\infty]. Inverse of logistic.
+ * in [-infinity, +infinity]. Inverse of logistic.
*
* Ill-conditioned near 1/2 and 1; the identity logit(1 - p) =
* -logit(p) and the function logithalf(p0) = logit(1/2 + p0) may help
@@ -488,7 +490,7 @@ random_uniform_01(void)
/* Functions for specific probability distributions start here: */
/*
- * Logistic(mu, sigma) distribution, supported on (-\infty,+\infty)
+ * Logistic(mu, sigma) distribution, supported on (-infinity,+infinity)
*
* This is the uniform distribution on [0,1] mapped into log-odds
* space, scaled by sigma and translated by mu.
@@ -546,7 +548,7 @@ isf_logistic(double p, double mu, double sigma)
}
/*
- * LogLogistic(alpha, beta) distribution, supported on (0, +\infty).
+ * LogLogistic(alpha, beta) distribution, supported on (0, +infinity).
*
* This is the uniform distribution on [0,1] mapped into odds space,
* scaled by positive alpha and shaped by positive beta.
@@ -687,7 +689,7 @@ isf_log_logistic(double p, double alpha, double beta)
}
/*
- * Weibull(lambda, k) distribution, supported on (0, +\infty).
+ * Weibull(lambda, k) distribution, supported on (0, +infinity).
*
* pdf(x) = (k/lambda) (x/lambda)^{k - 1} e^{-(x/lambda)^k}
* cdf(x) = 1 - e^{-(x/lambda)^k}
@@ -753,7 +755,7 @@ isf_weibull(double p, double lambda, double k)
}
/*
- * GeneralizedPareto(mu, sigma, xi), supported on (mu, +\infty) for
+ * GeneralizedPareto(mu, sigma, xi), supported on (mu, +infinity) for
* nonnegative xi, or (mu, mu - sigma/xi) for negative xi.
*
* Samples:
@@ -793,19 +795,19 @@ cdf_genpareto(double x, double mu, double sigma, double xi)
/*
* log(1 + xi x_0)/xi
- * = (-1/xi) \sum_{n=1}^\infty (-xi x_0)^n/n
- * = (-1/xi) (-xi x_0 + \sum_{n=2}^\infty (-xi x_0)^n/n)
- * = x_0 - (1/xi) \sum_{n=2}^\infty (-xi x_0)^n/n
- * = x_0 - x_0 \sum_{n=2}^\infty (-xi x_0)^{n-1}/n
+ * = (-1/xi) \sum_{n=1}^infinity (-xi x_0)^n/n
+ * = (-1/xi) (-xi x_0 + \sum_{n=2}^infinity (-xi x_0)^n/n)
+ * = x_0 - (1/xi) \sum_{n=2}^infinity (-xi x_0)^n/n
+ * = x_0 - x_0 \sum_{n=2}^infinity (-xi x_0)^{n-1}/n
* = x_0 (1 - d),
*
- * where d = \sum_{n=2}^\infty (-xi x_0)^{n-1}/n. If |xi| <
+ * where d = \sum_{n=2}^infinity (-xi x_0)^{n-1}/n. If |xi| <
* eps/4|x_0|, then
*
- * |d| <= \sum_{n=2}^\infty (eps/4)^{n-1}/n
- * <= \sum_{n=2}^\infty (eps/4)^{n-1}
- * = \sum_{n=1}^\infty (eps/4)^n
- * = (eps/4) \sum_{n=0}^\infty (eps/4)^n
+ * |d| <= \sum_{n=2}^infinity (eps/4)^{n-1}/n
+ * <= \sum_{n=2}^infinity (eps/4)^{n-1}
+ * = \sum_{n=1}^infinity (eps/4)^n
+ * = (eps/4) \sum_{n=0}^infinity (eps/4)^n
* = (eps/4)/(1 - eps/4)
* < eps/2
*
@@ -855,20 +857,20 @@ icdf_genpareto(double p, double mu, double sigma, double xi)
* for xi near zero (note f(xi) --> -log U as xi --> 0), write
* the absolutely convergent Taylor expansion
*
- * f(xi) = (1/xi)*(-xi log U + \sum_{n=2}^\infty (-xi log U)^n/n!
- * = -log U + (1/xi)*\sum_{n=2}^\infty (-xi log U)^n/n!
- * = -log U + \sum_{n=2}^\infty xi^{n-1} (-log U)^n/n!
- * = -log U - log U \sum_{n=2}^\infty (-xi log U)^{n-1}/n!
- * = -log U (1 + \sum_{n=2}^\infty (-xi log U)^{n-1}/n!).
+ * f(xi) = (1/xi)*(-xi log U + \sum_{n=2}^infinity (-xi log U)^n/n!
+ * = -log U + (1/xi)*\sum_{n=2}^infinity (-xi log U)^n/n!
+ * = -log U + \sum_{n=2}^infinity xi^{n-1} (-log U)^n/n!
+ * = -log U - log U \sum_{n=2}^infinity (-xi log U)^{n-1}/n!
+ * = -log U (1 + \sum_{n=2}^infinity (-xi log U)^{n-1}/n!).
*
- * Let d = \sum_{n=2}^\infty (-xi log U)^{n-1}/n!. What do we
+ * Let d = \sum_{n=2}^infinity (-xi log U)^{n-1}/n!. What do we
* lose if we discard it and use -log U as an approximation to
* f(xi)? If |xi| < eps/-4log U, then
*
- * |d| <= \sum_{n=2}^\infty |xi log U|^{n-1}/n!
- * <= \sum_{n=2}^\infty (eps/4)^{n-1}/n!
- * <= \sum_{n=1}^\infty (eps/4)^n
- * = (eps/4) \sum_{n=0}^\infty (eps/4)^n
+ * |d| <= \sum_{n=2}^infinity |xi log U|^{n-1}/n!
+ * <= \sum_{n=2}^infinity (eps/4)^{n-1}/n!
+ * <= \sum_{n=1}^infinity (eps/4)^n
+ * = (eps/4) \sum_{n=0}^infinity (eps/4)^n
* = (eps/4)/(1 - eps/4)
* < eps/2,
*
@@ -1098,10 +1100,10 @@ sample_logistic(uint32_t s, double t, double p0)
* We carve up the interval (0, 1) into subregions to compute
* the inverse CDF precisely:
*
- * A = (0, 1/(1 + e)] ---> (-\infty, -1]
+ * A = (0, 1/(1 + e)] ---> (-infinity, -1]
* B = [1/(1 + e), 1/2] ---> [-1, 0]
* C = [1/2, 1 - 1/(1 + e)] ---> [0, 1]
- * D = [1 - 1/(1 + e), 1) ---> [1, +\infty)
+ * D = [1 - 1/(1 + e), 1) ---> [1, +infinity)
*
* Cases D and C are mirror images of cases A and B,
* respectively, so we choose between them by the sign chosen
@@ -1234,19 +1236,19 @@ sample_genpareto(uint32_t s, double p0, double xi)
* Write f(xi) = (e^{xi x} - 1)/xi for xi near zero as the
* absolutely convergent Taylor series
*
- * f(x) = (1/xi) (xi x + \sum_{n=2}^\infty (xi x)^n/n!)
- * = x + (1/xi) \sum_{n=2}^\inty (xi x)^n/n!
- * = x + \sum_{n=2}^\infty xi^{n-1} x^n/n!
- * = x + x \sum_{n=2}^\infty (xi x)^{n-1}/n!
- * = x (1 + \sum_{n=2}^\infty (xi x)^{n-1}/n!).
+ * f(x) = (1/xi) (xi x + \sum_{n=2}^infinity (xi x)^n/n!)
+ * = x + (1/xi) \sum_{n=2}^infinity (xi x)^n/n!
+ * = x + \sum_{n=2}^infinity xi^{n-1} x^n/n!
+ * = x + x \sum_{n=2}^infinity (xi x)^{n-1}/n!
+ * = x (1 + \sum_{n=2}^infinity (xi x)^{n-1}/n!).
*
- * d = \sum_{n=2}^\infty (xi x)^{n-1}/n! is the relative error
+ * d = \sum_{n=2}^infinity (xi x)^{n-1}/n! is the relative error
* of f(x) from x. If |xi| < eps/4x, then
*
- * |d| <= \sum_{n=2}^\infty |xi x|^{n-1}/n!
- * <= \sum_{n=2}^\infty (eps/4)^{n-1}/n!
- * <= \sum_{n=1}^\infty (eps/4)
- * = (eps/4) \sum_{n=0}^\infty (eps/4)^n
+ * |d| <= \sum_{n=2}^infinity |xi x|^{n-1}/n!
+ * <= \sum_{n=2}^infinity (eps/4)^{n-1}/n!
+ * <= \sum_{n=1}^infinity (eps/4)
+ * = (eps/4) \sum_{n=0}^infinity (eps/4)^n
* = (eps/4)/(1 - eps/4)
* < eps/2,
*
@@ -1282,15 +1284,16 @@ sample_genpareto_locscale(uint32_t s, double p0, double mu, double sigma,
/**
* Deterministically sample from the geometric distribution with
* per-trial success probability p.
- *
+ **/
+// clang-format off
+/*
* XXX Quantify the error (KL divergence?) of this
* ceiling-of-exponential sampler from a true geometric distribution,
* which we could get by rejection sampling. Relevant papers:
*
* John F. Monahan, `Accuracy in Random Number Generation',
* Mathematics of Computation 45(172), October 1984, pp. 559--568.
-*https://pdfs.semanticscholar.org/aca6/74b96da1df77b2224e8cfc5dd6d61a471632.pdf
- *
+https://pdfs.semanticscholar.org/aca6/74b96da1df77b2224e8cfc5dd6d61a471632.pdf
* Karl Bringmann and Tobias Friedrich, `Exact and Efficient
* Generation of Geometric Random Variates and Random Graphs', in
* Proceedings of the 40th International Colloaquium on Automata,
@@ -1299,6 +1302,7 @@ sample_genpareto_locscale(uint32_t s, double p0, double mu, double sigma,
* https://doi.org/10.1007/978-3-642-39206-1_23
* https://people.mpi-inf.mpg.de/~kbringma/paper/2013ICALP-1.pdf
*/
+// clang-format on
static double
sample_geometric(uint32_t s, double p0, double p)
{
@@ -1324,42 +1328,42 @@ sample_geometric(uint32_t s, double p0, double p)
/** Returns the name of the distribution in <b>dist</b>. */
const char *
-dist_name(const struct dist *dist)
+dist_name(const struct dist_t *dist)
{
return dist->ops->name;
}
/* Sample a value from <b>dist</b> and return it. */
double
-dist_sample(const struct dist *dist)
+dist_sample(const struct dist_t *dist)
{
return dist->ops->sample(dist);
}
/** Compute the CDF of <b>dist</b> at <b>x</b>. */
double
-dist_cdf(const struct dist *dist, double x)
+dist_cdf(const struct dist_t *dist, double x)
{
return dist->ops->cdf(dist, x);
}
/** Compute the SF (Survival function) of <b>dist</b> at <b>x</b>. */
double
-dist_sf(const struct dist *dist, double x)
+dist_sf(const struct dist_t *dist, double x)
{
return dist->ops->sf(dist, x);
}
/** Compute the iCDF (Inverse CDF) of <b>dist</b> at <b>x</b>. */
double
-dist_icdf(const struct dist *dist, double p)
+dist_icdf(const struct dist_t *dist, double p)
{
return dist->ops->icdf(dist, p);
}
/** Compute the iSF (Inverse Survival function) of <b>dist</b> at <b>x</b>. */
double
-dist_isf(const struct dist *dist, double p)
+dist_isf(const struct dist_t *dist, double p)
{
return dist->ops->isf(dist, p);
}
@@ -1367,18 +1371,18 @@ dist_isf(const struct dist *dist, double p)
/** Functions for uniform distribution */
static double
-uniform_sample(const struct dist *dist)
+uniform_sample(const struct dist_t *dist)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *U = dist_to_const_uniform(dist);
double p0 = random_uniform_01();
return sample_uniform_interval(p0, U->a, U->b);
}
static double
-uniform_cdf(const struct dist *dist, double x)
+uniform_cdf(const struct dist_t *dist, double x)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *U = dist_to_const_uniform(dist);
if (x < U->a)
return 0;
else if (x < U->b)
@@ -1388,9 +1392,9 @@ uniform_cdf(const struct dist *dist, double x)
}
static double
-uniform_sf(const struct dist *dist, double x)
+uniform_sf(const struct dist_t *dist, double x)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *U = dist_to_const_uniform(dist);
if (x > U->b)
return 0;
@@ -1401,24 +1405,24 @@ uniform_sf(const struct dist *dist, double x)
}
static double
-uniform_icdf(const struct dist *dist, double p)
+uniform_icdf(const struct dist_t *dist, double p)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *U = dist_to_const_uniform(dist);
double w = U->b - U->a;
return (p < 0.5 ? (U->a + w*p) : (U->b - w*(1 - p)));
}
static double
-uniform_isf(const struct dist *dist, double p)
+uniform_isf(const struct dist_t *dist, double p)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *U = dist_to_const_uniform(dist);
double w = U->b - U->a;
return (p < 0.5 ? (U->b - w*p) : (U->a + w*(1 - p)));
}
-const struct dist_ops uniform_ops = {
+const struct dist_ops_t uniform_ops = {
.name = "uniform",
.sample = uniform_sample,
.cdf = uniform_cdf,
@@ -1434,9 +1438,9 @@ const struct dist_ops uniform_ops = {
/** Functions for logistic distribution: */
static double
-logistic_sample(const struct dist *dist)
+logistic_sample(const struct dist_t *dist)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double t = random_uniform_01();
double p0 = random_uniform_01();
@@ -1445,34 +1449,34 @@ logistic_sample(const struct dist *dist)
}
static double
-logistic_cdf(const struct dist *dist, double x)
+logistic_cdf(const struct dist_t *dist, double x)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
return cdf_logistic(x, L->mu, L->sigma);
}
static double
-logistic_sf(const struct dist *dist, double x)
+logistic_sf(const struct dist_t *dist, double x)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
return sf_logistic(x, L->mu, L->sigma);
}
static double
-logistic_icdf(const struct dist *dist, double p)
+logistic_icdf(const struct dist_t *dist, double p)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
return icdf_logistic(p, L->mu, L->sigma);
}
static double
-logistic_isf(const struct dist *dist, double p)
+logistic_isf(const struct dist_t *dist, double p)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
return isf_logistic(p, L->mu, L->sigma);
}
-const struct dist_ops logistic_ops = {
+const struct dist_ops_t logistic_ops = {
.name = "logistic",
.sample = logistic_sample,
.cdf = logistic_cdf,
@@ -1484,9 +1488,9 @@ const struct dist_ops logistic_ops = {
/** Functions for log-logistic distribution: */
static double
-log_logistic_sample(const struct dist *dist)
+log_logistic_sample(const struct dist_t *dist)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *LL = dist_to_const_log_logistic(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
@@ -1494,34 +1498,34 @@ log_logistic_sample(const struct dist *dist)
}
static double
-log_logistic_cdf(const struct dist *dist, double x)
+log_logistic_cdf(const struct dist_t *dist, double x)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *LL = dist_to_const_log_logistic(dist);
return cdf_log_logistic(x, LL->alpha, LL->beta);
}
static double
-log_logistic_sf(const struct dist *dist, double x)
+log_logistic_sf(const struct dist_t *dist, double x)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *LL = dist_to_const_log_logistic(dist);
return sf_log_logistic(x, LL->alpha, LL->beta);
}
static double
-log_logistic_icdf(const struct dist *dist, double p)
+log_logistic_icdf(const struct dist_t *dist, double p)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *LL = dist_to_const_log_logistic(dist);
return icdf_log_logistic(p, LL->alpha, LL->beta);
}
static double
-log_logistic_isf(const struct dist *dist, double p)
+log_logistic_isf(const struct dist_t *dist, double p)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *LL = dist_to_const_log_logistic(dist);
return isf_log_logistic(p, LL->alpha, LL->beta);
}
-const struct dist_ops log_logistic_ops = {
+const struct dist_ops_t log_logistic_ops = {
.name = "log logistic",
.sample = log_logistic_sample,
.cdf = log_logistic_cdf,
@@ -1533,9 +1537,9 @@ const struct dist_ops log_logistic_ops = {
/** Functions for Weibull distribution */
static double
-weibull_sample(const struct dist *dist)
+weibull_sample(const struct dist_t *dist)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
@@ -1543,34 +1547,34 @@ weibull_sample(const struct dist *dist)
}
static double
-weibull_cdf(const struct dist *dist, double x)
+weibull_cdf(const struct dist_t *dist, double x)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
return cdf_weibull(x, W->lambda, W->k);
}
static double
-weibull_sf(const struct dist *dist, double x)
+weibull_sf(const struct dist_t *dist, double x)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
return sf_weibull(x, W->lambda, W->k);
}
static double
-weibull_icdf(const struct dist *dist, double p)
+weibull_icdf(const struct dist_t *dist, double p)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
return icdf_weibull(p, W->lambda, W->k);
}
static double
-weibull_isf(const struct dist *dist, double p)
+weibull_isf(const struct dist_t *dist, double p)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
return isf_weibull(p, W->lambda, W->k);
}
-const struct dist_ops weibull_ops = {
+const struct dist_ops_t weibull_ops = {
.name = "Weibull",
.sample = weibull_sample,
.cdf = weibull_cdf,
@@ -1582,9 +1586,9 @@ const struct dist_ops weibull_ops = {
/** Functions for generalized Pareto distributions */
static double
-genpareto_sample(const struct dist *dist)
+genpareto_sample(const struct dist_t *dist)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *GP = dist_to_const_genpareto(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
@@ -1592,34 +1596,34 @@ genpareto_sample(const struct dist *dist)
}
static double
-genpareto_cdf(const struct dist *dist, double x)
+genpareto_cdf(const struct dist_t *dist, double x)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *GP = dist_to_const_genpareto(dist);
return cdf_genpareto(x, GP->mu, GP->sigma, GP->xi);
}
static double
-genpareto_sf(const struct dist *dist, double x)
+genpareto_sf(const struct dist_t *dist, double x)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *GP = dist_to_const_genpareto(dist);
return sf_genpareto(x, GP->mu, GP->sigma, GP->xi);
}
static double
-genpareto_icdf(const struct dist *dist, double p)
+genpareto_icdf(const struct dist_t *dist, double p)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *GP = dist_to_const_genpareto(dist);
return icdf_genpareto(p, GP->mu, GP->sigma, GP->xi);
}
static double
-genpareto_isf(const struct dist *dist, double p)
+genpareto_isf(const struct dist_t *dist, double p)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *GP = dist_to_const_genpareto(dist);
return isf_genpareto(p, GP->mu, GP->sigma, GP->xi);
}
-const struct dist_ops genpareto_ops = {
+const struct dist_ops_t genpareto_ops = {
.name = "generalized Pareto",
.sample = genpareto_sample,
.cdf = genpareto_cdf,
@@ -1631,9 +1635,9 @@ const struct dist_ops genpareto_ops = {
/** Functions for geometric distribution on number of trials before success */
static double
-geometric_sample(const struct dist *dist)
+geometric_sample(const struct dist_t *dist)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
@@ -1641,9 +1645,9 @@ geometric_sample(const struct dist *dist)
}
static double
-geometric_cdf(const struct dist *dist, double x)
+geometric_cdf(const struct dist_t *dist, double x)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
if (x < 1)
return 0;
@@ -1652,9 +1656,9 @@ geometric_cdf(const struct dist *dist, double x)
}
static double
-geometric_sf(const struct dist *dist, double x)
+geometric_sf(const struct dist_t *dist, double x)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
if (x < 1)
return 0;
@@ -1663,22 +1667,22 @@ geometric_sf(const struct dist *dist, double x)
}
static double
-geometric_icdf(const struct dist *dist, double p)
+geometric_icdf(const struct dist_t *dist, double p)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
return log1p(-p)/log1p(-G->p);
}
static double
-geometric_isf(const struct dist *dist, double p)
+geometric_isf(const struct dist_t *dist, double p)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
return log(p)/log1p(-G->p);
}
-const struct dist_ops geometric_ops = {
+const struct dist_ops_t geometric_ops = {
.name = "geometric (1-based)",
.sample = geometric_sample,
.cdf = geometric_cdf,
diff --git a/src/lib/math/prob_distr.h b/src/lib/math/prob_distr.h
index 7254dc8623..a036073b93 100644
--- a/src/lib/math/prob_distr.h
+++ b/src/lib/math/prob_distr.h
@@ -15,13 +15,13 @@
/**
* Container for distribution parameters for sampling, CDF, &c.
*/
-struct dist {
- const struct dist_ops *ops;
+struct dist_t {
+ const struct dist_ops_t *ops;
};
/**
- * Untyped initializer element for struct dist using the specified
- * struct dist_ops pointer. Don't actually use this directly -- use
+ * Untyped initializer element for struct dist_t using the specified
+ * struct dist_ops_t pointer. Don't actually use this directly -- use
* the type-specific macro built out of DIST_BASE_TYPED below -- but if
* you did use this directly, it would be something like:
*
@@ -61,46 +61,46 @@ struct dist {
#endif /* defined(__COVERITY__) */
/**
-* Typed initializer element for struct dist using the specified struct
-* dist_ops pointer. Don't actually use this directly -- use a
+* Typed initializer element for struct dist_t using the specified struct
+* dist_ops_t pointer. Don't actually use this directly -- use a
* type-specific macro built out of it -- but if you did use this
* directly, it would be something like:
*
-* struct weibull mydist = {
-* DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull),
-* .lambda = ...,
-* .k = ...,
-* };
+* struct weibull mydist = {
+* DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull_t),
+* .lambda = ...,
+* .k = ...,
+* };
*
* If you want to define a distribution type, define a canonical set of
* operations and define a type-specific initializer element like so:
*
-* struct foo {
-* struct dist base;
-* int omega;
-* double tau;
-* double phi;
-* };
+* struct foo_t {
+* struct dist_t base;
+* int omega;
+* double tau;
+* double phi;
+* };
*
-* struct dist_ops foo_ops = ...;
+* struct dist_ops_t foo_ops = ...;
*
-* #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo)
+* #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo_t)
*
* Then users can do:
*
-* struct foo mydist = {
-* FOO(mydist),
-* .omega = ...,
-* .tau = ...,
-* .phi = ...,
-* };
+* struct foo_t mydist = {
+* FOO(mydist),
+* .omega = ...,
+* .tau = ...,
+* .phi = ...,
+* };
*
* If you accidentally write
*
-* struct bar mydist = {
-* FOO(mydist),
-* ...
-* };
+* struct bar_t mydist = {
+* FOO(mydist),
+* ...
+* };
*
* then the compiler will report a type mismatch in the sizeof
* expression, which otherwise evaporates at runtime.
@@ -110,107 +110,107 @@ struct dist {
/**
* Generic operations on distributions. These simply defer to the
- * corresponding dist_ops function. In the parlance of C++, these call
+ * corresponding dist_ops_t function. In the parlance of C++, these call
* virtual member functions.
*/
-const char *dist_name(const struct dist *);
-double dist_sample(const struct dist *);
-double dist_cdf(const struct dist *, double x);
-double dist_sf(const struct dist *, double x);
-double dist_icdf(const struct dist *, double p);
-double dist_isf(const struct dist *, double p);
+const char *dist_name(const struct dist_t *);
+double dist_sample(const struct dist_t *);
+double dist_cdf(const struct dist_t *, double x);
+double dist_sf(const struct dist_t *, double x);
+double dist_icdf(const struct dist_t *, double p);
+double dist_isf(const struct dist_t *, double p);
/**
* Set of operations on a potentially parametric family of
* distributions. In the parlance of C++, this would be called a
* `vtable' and the members are virtual member functions.
*/
-struct dist_ops {
+struct dist_ops_t {
const char *name;
- double (*sample)(const struct dist *);
- double (*cdf)(const struct dist *, double x);
- double (*sf)(const struct dist *, double x);
- double (*icdf)(const struct dist *, double p);
- double (*isf)(const struct dist *, double p);
+ double (*sample)(const struct dist_t *);
+ double (*cdf)(const struct dist_t *, double x);
+ double (*sf)(const struct dist_t *, double x);
+ double (*icdf)(const struct dist_t *, double p);
+ double (*isf)(const struct dist_t *, double p);
};
/* Geometric distribution on positive number of trials before first success */
-struct geometric {
- struct dist base;
+struct geometric_t {
+ struct dist_t base;
double p; /* success probability */
};
-extern const struct dist_ops geometric_ops;
+extern const struct dist_ops_t geometric_ops;
#define GEOMETRIC(OBJ) \
- DIST_BASE_TYPED(&geometric_ops, OBJ, struct geometric)
+ DIST_BASE_TYPED(&geometric_ops, OBJ, struct geometric_t)
/* Pareto distribution */
-struct genpareto {
- struct dist base;
+struct genpareto_t {
+ struct dist_t base;
double mu;
double sigma;
double xi;
};
-extern const struct dist_ops genpareto_ops;
+extern const struct dist_ops_t genpareto_ops;
#define GENPARETO(OBJ) \
- DIST_BASE_TYPED(&genpareto_ops, OBJ, struct genpareto)
+ DIST_BASE_TYPED(&genpareto_ops, OBJ, struct genpareto_t)
/* Weibull distribution */
-struct weibull {
- struct dist base;
+struct weibull_t {
+ struct dist_t base;
double lambda;
double k;
};
-extern const struct dist_ops weibull_ops;
+extern const struct dist_ops_t weibull_ops;
#define WEIBULL(OBJ) \
- DIST_BASE_TYPED(&weibull_ops, OBJ, struct weibull)
+ DIST_BASE_TYPED(&weibull_ops, OBJ, struct weibull_t)
/* Log-logistic distribution */
-struct log_logistic {
- struct dist base;
+struct log_logistic_t {
+ struct dist_t base;
double alpha;
double beta;
};
-extern const struct dist_ops log_logistic_ops;
+extern const struct dist_ops_t log_logistic_ops;
#define LOG_LOGISTIC(OBJ) \
- DIST_BASE_TYPED(&log_logistic_ops, OBJ, struct log_logistic)
+ DIST_BASE_TYPED(&log_logistic_ops, OBJ, struct log_logistic_t)
/* Logistic distribution */
-struct logistic {
- struct dist base;
+struct logistic_t {
+ struct dist_t base;
double mu;
double sigma;
};
-extern const struct dist_ops logistic_ops;
+extern const struct dist_ops_t logistic_ops;
#define LOGISTIC(OBJ) \
- DIST_BASE_TYPED(&logistic_ops, OBJ, struct logistic)
+ DIST_BASE_TYPED(&logistic_ops, OBJ, struct logistic_t)
/* Uniform distribution */
-struct uniform {
- struct dist base;
+struct uniform_t {
+ struct dist_t base;
double a;
double b;
};
-extern const struct dist_ops uniform_ops;
+extern const struct dist_ops_t uniform_ops;
#define UNIFORM(OBJ) \
- DIST_BASE_TYPED(&uniform_ops, OBJ, struct uniform)
+ DIST_BASE_TYPED(&uniform_ops, OBJ, struct uniform_t)
/** Only by unittests */
diff --git a/src/lib/memarea/lib_memarea.md b/src/lib/memarea/lib_memarea.md
new file mode 100644
index 0000000000..fe5cb8293f
--- /dev/null
+++ b/src/lib/memarea/lib_memarea.md
@@ -0,0 +1,28 @@
+@dir /lib/memarea
+@brief lib/memarea: A fast arena-style allocator.
+
+This module has a fast "arena" style allocator, where memory is freed all at
+once. This kind of allocation is very fast and avoids fragmentation, at the
+expense of requiring all the data to be freed at the same time. We use this
+for parsing and diff calculations.
+
+It's often handy to allocate a large number of tiny objects, all of which
+need to disappear at the same time. You can do this in tor using the
+memarea.c abstraction, which uses a set of grow-only buffers for allocation,
+and only supports a single "free" operation at the end.
+
+Using memareas also helps you avoid memory fragmentation. You see, some libc
+malloc implementations perform badly on the case where a large number of
+small temporary objects are allocated at the same time as a few long-lived
+objects of similar size. But if you use tor_malloc() for the long-lived ones
+and a memarea for the temporary object, the malloc implementation is likelier
+to do better.
+
+To create a new memarea, use `memarea_new()`. To drop all the storage from a
+memarea, and invalidate its pointers, use `memarea_drop_all()`.
+
+The allocation functions `memarea_alloc()`, `memarea_alloc_zero()`,
+`memarea_memdup()`, `memarea_strdup()`, and `memarea_strndup()` are analogous
+to the similarly-named malloc() functions. There is intentionally no
+`memarea_free()` or `memarea_realloc()`.
+
diff --git a/src/lib/memarea/memarea.c b/src/lib/memarea/memarea.c
index f3bb79a1e2..4d26c20eeb 100644
--- a/src/lib/memarea/memarea.c
+++ b/src/lib/memarea/memarea.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2019, The Tor Project, Inc. */
+/* Copyright (c) 2008-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -39,7 +39,7 @@
#elif MEMAREA_ALIGN == 8
#define MEMAREA_ALIGN_MASK ((uintptr_t)7)
#else
-#error "void* is neither 4 nor 8 bytes long. I don't know how to align stuff."
+#error "void* is neither 4 nor 8 bytes long."
#endif /* MEMAREA_ALIGN == 4 || ... */
#if defined(__GNUC__) && defined(FLEXIBLE_ARRAY_MEMBER)
diff --git a/src/lib/memarea/memarea.h b/src/lib/memarea/memarea.h
index 9c23cf62e9..8b5e63e6b3 100644
--- a/src/lib/memarea/memarea.h
+++ b/src/lib/memarea/memarea.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2019, The Tor Project, Inc. */
+/* Copyright (c) 2008-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,6 +16,9 @@ typedef struct memarea_t memarea_t;
memarea_t *memarea_new(void);
void memarea_drop_all_(memarea_t *area);
+/** @copydoc memarea_drop_all_
+ *
+ * Additionally, set <b>area</b> to NULL. */
#define memarea_drop_all(area) \
do { \
memarea_drop_all_(area); \
diff --git a/src/lib/meminfo/lib_meminfo.md b/src/lib/meminfo/lib_meminfo.md
new file mode 100644
index 0000000000..87f509d648
--- /dev/null
+++ b/src/lib/meminfo/lib_meminfo.md
@@ -0,0 +1,5 @@
+@dir /lib/meminfo
+@brief lib/meminfo: Inspecting malloc() usage.
+
+Only available when malloc() provides mallinfo() or something similar.
+
diff --git a/src/lib/meminfo/meminfo.c b/src/lib/meminfo/meminfo.c
index bff71c2f05..0c5e0ed665 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -37,7 +37,7 @@
#include <sys/sysctl.h>
#endif
-DISABLE_GCC_WARNING(aggregate-return)
+DISABLE_GCC_WARNING("-Waggregate-return")
/** Call the platform malloc info function, and dump the results to the log at
* level <b>severity</b>. If no such function exists, do nothing. */
void
@@ -58,7 +58,7 @@ tor_log_mallinfo(int severity)
(void)severity;
#endif /* defined(HAVE_MALLINFO) */
}
-ENABLE_GCC_WARNING(aggregate-return)
+ENABLE_GCC_WARNING("-Waggregate-return")
#if defined(HW_PHYSMEM64)
/* OpenBSD and NetBSD define this */
diff --git a/src/lib/meminfo/meminfo.h b/src/lib/meminfo/meminfo.h
index 9580640f4d..a5ebfd5a6a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/.may_include b/src/lib/net/.may_include
index e4368f799b..6e9af9737a 100644
--- a/src/lib/net/.may_include
+++ b/src/lib/net/.may_include
@@ -14,4 +14,5 @@ lib/net/*.h
lib/string/*.h
lib/subsys/*.h
lib/testsupport/*.h
-lib/malloc/*.h \ No newline at end of file
+lib/malloc/*.h
+lib/smartlist_core/*.h
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index 41017935e1..6d46f9b955 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -97,7 +97,7 @@
* work correctly. Bail out here if we've found a platform where AF_UNSPEC
* isn't 0. */
#if AF_UNSPEC != 0
-#error We rely on AF_UNSPEC being 0. Let us know about your platform, please!
+#error "We rely on AF_UNSPEC being 0. Yours isn't. Please tell us more!"
#endif
CTASSERT(AF_UNSPEC == 0);
@@ -608,7 +608,8 @@ tor_addr_parse_mask_ports(const char *s,
family = AF_INET;
tor_addr_from_ipv4h(addr_out, 0);
} else if (flags & TAPMP_STAR_IPV6_ONLY) {
- static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ static uint8_t nil_bytes[16] =
+ { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
family = AF_INET6;
tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
} else {
@@ -629,7 +630,7 @@ tor_addr_parse_mask_ports(const char *s,
tor_addr_from_ipv4h(addr_out, 0);
any_flag = 1;
} else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) {
- static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ static uint8_t nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
family = AF_INET6;
tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
any_flag = 1;
@@ -817,8 +818,12 @@ tor_addr_is_loopback(const tor_addr_t *addr)
/* Is addr valid?
* Checks that addr is non-NULL and not tor_addr_is_null().
- * If for_listening is true, IPv4 addr 0.0.0.0 is allowed.
- * It means "bind to all addresses on the local machine". */
+ * If for_listening is true, all IPv4 and IPv6 addresses are valid, including
+ * 0.0.0.0 (for IPv4) and :: (for IPv6). When listening, these addresses mean
+ * "bind to all addresses on the local machine".
+ * Otherwise, 0.0.0.0 and :: are invalid, because they are null addresses.
+ * All unspecified and unix addresses are invalid, regardless of for_listening.
+ */
int
tor_addr_is_valid(const tor_addr_t *addr, int for_listening)
{
@@ -827,10 +832,11 @@ tor_addr_is_valid(const tor_addr_t *addr, int for_listening)
return 0;
}
- /* Only allow IPv4 0.0.0.0 for_listening. */
- if (for_listening && addr->family == AF_INET
- && tor_addr_to_ipv4h(addr) == 0) {
- return 1;
+ /* Allow all IPv4 and IPv6 addresses, when for_listening is true */
+ if (for_listening) {
+ if (addr->family == AF_INET || addr->family == AF_INET6) {
+ return 1;
+ }
}
/* Otherwise, the address is valid if it's not tor_addr_is_null() */
@@ -882,7 +888,7 @@ tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr)
/** Set <b>dest</b> to equal the IPv6 address in the 16 bytes at
* <b>ipv6_bytes</b>. */
void
-tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes)
+tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *ipv6_bytes)
{
tor_assert(dest);
tor_assert(ipv6_bytes);
@@ -895,7 +901,21 @@ tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes)
void
tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6)
{
- tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr);
+ tor_addr_from_ipv6_bytes(dest, in6->s6_addr);
+}
+
+/** Set the 16 bytes at <b>dest</b> to equal the IPv6 address <b>src</b>.
+ * <b>src</b> must be an IPv6 address, if it is not, log a warning, and clear
+ * <b>dest</b>. */
+void
+tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src)
+{
+ tor_assert(dest);
+ tor_assert(src);
+ memset(dest, 0, 16);
+ IF_BUG_ONCE(src->family != AF_INET6)
+ return;
+ memcpy(dest, src->addr.in6_addr.s6_addr, 16);
}
/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>.
@@ -1169,25 +1189,67 @@ fmt_addr_impl(const tor_addr_t *addr, int decorate)
const char *
fmt_addrport(const tor_addr_t *addr, uint16_t port)
{
- /* Add space for a colon and up to 5 digits. */
- static char buf[TOR_ADDR_BUF_LEN + 6];
+ static char buf[TOR_ADDRPORT_BUF_LEN];
tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port);
return buf;
}
/** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4
* addresses. Also not thread-safe, also clobbers its return buffer on
- * repeated calls. */
+ * repeated calls. Clean internal buffer and return empty string on failure. */
const char *
fmt_addr32(uint32_t addr)
{
static char buf[INET_NTOA_BUF_LEN];
struct in_addr in;
+ int success;
+
in.s_addr = htonl(addr);
- tor_inet_ntoa(&in, buf, sizeof(buf));
+
+ success = tor_inet_ntoa(&in, buf, sizeof(buf));
+ tor_assertf_nonfatal(success >= 0,
+ "Failed to convert IP 0x%08X (HBO) to string", addr);
+
+ IF_BUG_ONCE(success < 0) {
+ memset(buf, 0, INET_NTOA_BUF_LEN);
+ }
+
return buf;
}
+/** Return a string representing the family of <b>addr</b>.
+ *
+ * This string is a string constant, and must not be freed.
+ * This function is thread-safe.
+ */
+const char *
+fmt_addr_family(const tor_addr_t *addr)
+{
+ static int default_bug_once = 0;
+
+ IF_BUG_ONCE(!addr)
+ return "NULL pointer";
+
+ switch (tor_addr_family(addr)) {
+ case AF_INET6:
+ return "IPv6";
+ case AF_INET:
+ return "IPv4";
+ case AF_UNIX:
+ return "UNIX socket";
+ case AF_UNSPEC:
+ return "unspecified";
+ default:
+ if (!default_bug_once) {
+ log_warn(LD_BUG, "Called with unknown address family %d",
+ (int)tor_addr_family(addr));
+ default_bug_once = 1;
+ }
+ return "unknown";
+ }
+ //return "(unreachable code)";
+}
+
/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string
* may be an IPv4 address, or an IPv6 address surrounded by square brackets.
*
@@ -1393,7 +1455,7 @@ get_interface_addresses_win32(int severity, sa_family_t family)
/* This is defined on Mac OS X */
#ifndef _SIZEOF_ADDR_IFREQ
-#define _SIZEOF_ADDR_IFREQ sizeof
+#define _SIZEOF_ADDR_IFREQ(x) sizeof(x)
#endif
/* Free ifc->ifc_buf safely. */
@@ -1412,10 +1474,10 @@ ifconf_free_ifc_buf(struct ifconf *ifc)
* into smartlist of <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
-ifreq_to_smartlist(char *buf, size_t buflen)
+ifreq_to_smartlist(const uint8_t *buf, size_t buflen)
{
smartlist_t *result = smartlist_new();
- char *end = buf + buflen;
+ const uint8_t *end = buf + buflen;
/* These acrobatics are due to alignment issues which trigger
* undefined behaviour traps on OSX. */
@@ -1489,7 +1551,7 @@ get_interface_addresses_ioctl(int severity, sa_family_t family)
/* Ensure we have least IFREQ_SIZE bytes unused at the end. Otherwise, we
* don't know if we got everything during ioctl. */
} while (mult * IFREQ_SIZE - ifc.ifc_len <= IFREQ_SIZE);
- result = ifreq_to_smartlist(ifc.ifc_buf, ifc.ifc_len);
+ result = ifreq_to_smartlist((const uint8_t *)ifc.ifc_buf, ifc.ifc_len);
done:
if (fd >= 0)
@@ -1642,11 +1704,15 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr))
* Ideally, we want the default route, see #12377 for details */
SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) {
tor_addr_copy(addr, a);
+ const bool is_internal = tor_addr_is_internal(a, 0);
rv = 0;
+ log_debug(LD_NET, "Found %s interface address '%s'",
+ (is_internal ? "internal" : "external"), fmt_addr(addr));
+
/* If we found a non-internal address, declare success. Otherwise,
* keep looking. */
- if (!tor_addr_is_internal(a, 0))
+ if (!is_internal)
break;
} SMARTLIST_FOREACH_END(a);
@@ -1943,17 +2009,24 @@ parse_port_range(const char *port, uint16_t *port_min_out,
}
/** Given a host-order <b>addr</b>, call tor_inet_ntop() on it
- * and return a strdup of the resulting address.
+ * and return a strdup of the resulting address. Return NULL if
+ * tor_inet_ntop() fails.
*/
char *
tor_dup_ip(uint32_t addr)
{
+ const char *ip_str;
char buf[TOR_ADDR_BUF_LEN];
struct in_addr in;
in.s_addr = htonl(addr);
- tor_inet_ntop(AF_INET, &in, buf, sizeof(buf));
- return tor_strdup(buf);
+ ip_str = tor_inet_ntop(AF_INET, &in, buf, sizeof(buf));
+
+ tor_assertf_nonfatal(ip_str, "Failed to duplicate IP %08X", addr);
+ if (ip_str)
+ return tor_strdup(buf);
+
+ return NULL;
}
/**
@@ -2002,7 +2075,7 @@ tor_addr_port_new(const tor_addr_t *addr, uint16_t port)
return ap;
}
-/** Return true iff <a>a</b> and <b>b</b> are the same address and port */
+/** Return true iff <b>a</b> and <b>b</b> are the same address and port */
int
tor_addr_port_eq(const tor_addr_port_t *a,
const tor_addr_port_t *b)
diff --git a/src/lib/net/address.h b/src/lib/net/address.h
index 9b826c8359..e5016ee4fe 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -62,6 +62,7 @@
typedef uint8_t maskbits_t;
struct in_addr;
+
/** Holds an IPv4 or IPv6 address. (Uses less memory than struct
* sockaddr_storage.) */
typedef struct tor_addr_t
@@ -103,6 +104,10 @@ int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out);
void tor_addr_make_unspec(tor_addr_t *a);
void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
+#define tor_addr_port_make_null(addr, port, family) \
+ (void)(tor_addr_make_null(addr, family), (port) = 0)
+#define tor_addr_port_make_null_ap(ap, family) \
+ tor_addr_port_make_null(&(ap)->addr, (ap)->port, family)
char *tor_sockaddr_to_str(const struct sockaddr *sa);
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
@@ -133,6 +138,7 @@ tor_addr_to_in6_assert(const tor_addr_t *a)
* Requires that <b>x</b> is actually an IPv6 address.
*/
#define tor_addr_to_in6_addr16(x) S6_ADDR16(*tor_addr_to_in6_assert(x))
+
/** Given an IPv6 address <b>x</b>, yield it as an array of uint32_t.
*
* Requires that <b>x</b> is actually an IPv6 address.
@@ -146,6 +152,7 @@ tor_addr_to_ipv4n(const tor_addr_t *a)
{
return a->family == AF_INET ? a->addr.in_addr.s_addr : 0;
}
+
/** Return an IPv4 address in host order for <b>a</b>, or 0 if
* <b>a</b> is not an IPv4 address. */
static inline uint32_t
@@ -153,10 +160,11 @@ tor_addr_to_ipv4h(const tor_addr_t *a)
{
return ntohl(tor_addr_to_ipv4n(a));
}
+
/** Given an IPv6 address, return its mapped IPv4 address in host order, or
* 0 if <b>a</b> is not an IPv6 address.
*
- * (Does not check whether the address is really a mapped address */
+ * (Does not check whether the address is really a mapped address.) */
static inline uint32_t
tor_addr_to_mapped_ipv4h(const tor_addr_t *a)
{
@@ -165,21 +173,21 @@ tor_addr_to_mapped_ipv4h(const tor_addr_t *a)
// Work around an incorrect NULL pointer dereference warning in
// "clang --analyze" due to limited analysis depth
addr32 = tor_addr_to_in6_addr32(a);
- // To improve performance, wrap this assertion in:
- // #if !defined(__clang_analyzer__) || PARANOIA
tor_assert(addr32);
return ntohl(addr32[3]);
} else {
return 0;
}
}
+
/** Return the address family of <b>a</b>. Possible values are:
- * AF_INET6, AF_INET, AF_UNSPEC. */
+ * AF_INET6, AF_INET, AF_UNSPEC, AF_UNIX. */
static inline sa_family_t
tor_addr_family(const tor_addr_t *a)
{
return a->family;
}
+
/** Return an in_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
* an IPv4 address. */
static inline const struct in_addr *
@@ -187,6 +195,7 @@ tor_addr_to_in(const tor_addr_t *a)
{
return a->family == AF_INET ? &a->addr.in_addr : NULL;
}
+
/** Return true iff <b>a</b> is an IPv4 address equal to the host-ordered
* address in <b>u</b>. */
static inline int
@@ -204,24 +213,39 @@ tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u)
*/
#define TOR_ADDR_BUF_LEN 48
+/** Length of a buffer containing an IP address along with a port number and
+ * a seperating colon.
+ *
+ * This allows enough space for
+ * "[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]:12345",
+ * plus a terminating NUL.
+ */
+#define TOR_ADDRPORT_BUF_LEN (TOR_ADDR_BUF_LEN + 6)
+
char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC;
/** Wrapper function of fmt_addr_impl(). It does not decorate IPv6
* addresses. */
#define fmt_addr(a) fmt_addr_impl((a), 0)
+
/** Wrapper function of fmt_addr_impl(). It decorates IPv6
* addresses. */
#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1)
+
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
-const char * fmt_addr32(uint32_t addr);
+#define fmt_addrport_ap(ap) fmt_addrport(&(ap)->addr, (ap)->port)
+const char *fmt_addr32(uint32_t addr);
+const char *fmt_addr_family(const tor_addr_t *addr);
MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
tor_addr_t *addr));
+
struct smartlist_t;
-void interface_address6_list_free_(struct smartlist_t * addrs);// XXXX
+void interface_address6_list_free_(struct smartlist_t * addrs);
#define interface_address6_list_free(addrs) \
FREE_AND_NULL(struct smartlist_t, interface_address6_list_free_, (addrs))
+
MOCK_DECL(struct smartlist_t *,get_interface_address6_list,(int severity,
sa_family_t family,
int include_internal));
@@ -246,6 +270,7 @@ int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
uint64_t tor_addr_hash(const tor_addr_t *addr);
struct sipkey;
uint64_t tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr);
+
int tor_addr_is_v4(const tor_addr_t *addr);
int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
const char *filename, int lineno);
@@ -276,21 +301,25 @@ int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
int tor_addr_parse_mask_ports(const char *s, unsigned flags,
tor_addr_t *addr_out, maskbits_t *mask_out,
uint16_t *port_min_out, uint16_t *port_max_out);
+
const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len,
int decorate);
int tor_addr_parse(tor_addr_t *addr, const char *src);
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src);
void tor_addr_copy_tight(tor_addr_t *dest, const tor_addr_t *src);
+
void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr);
/** Set <b>dest</b> to the IPv4 address encoded in <b>v4addr</b> in host
* order. */
#define tor_addr_from_ipv4h(dest, v4addr) \
tor_addr_from_ipv4n((dest), htonl(v4addr))
-void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes);
+void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *bytes);
/** Set <b>dest</b> to the IPv4 address incoded in <b>in</b>. */
#define tor_addr_from_in(dest, in) \
tor_addr_from_ipv4n((dest), (in)->s_addr);
void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6);
+void tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src);
+
int tor_addr_is_null(const tor_addr_t *addr);
int tor_addr_is_loopback(const tor_addr_t *addr);
@@ -299,6 +328,7 @@ int tor_addr_is_valid_ipv4n(uint32_t v4n_addr, int for_listening);
#define tor_addr_is_valid_ipv4h(v4h_addr, for_listening) \
tor_addr_is_valid_ipv4n(htonl(v4h_addr), (for_listening))
int tor_port_is_valid(uint16_t port, int for_listening);
+
/* Are addr and port both valid? */
#define tor_addr_port_is_valid(addr, port, for_listening) \
(tor_addr_is_valid((addr), (for_listening)) && \
@@ -329,9 +359,11 @@ int parse_port_range(const char *port, uint16_t *port_min_out,
uint16_t *port_max_out);
int addr_mask_get_bits(uint32_t mask);
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
+
MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr));
#define interface_address_list_free(lst)\
interface_address6_list_free(lst)
+
/** Return a smartlist of the IPv4 addresses of all interfaces on the server.
* Excludes loopback and multicast addresses. Only includes internal addresses
* if include_internal is true. (Note that a relay behind NAT may use an
@@ -377,8 +409,8 @@ STATIC struct smartlist_t *get_interface_addresses_win32(int severity,
#endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */
#ifdef HAVE_IFCONF_TO_SMARTLIST
-STATIC struct smartlist_t *ifreq_to_smartlist(char *ifr,
- size_t buflen);
+STATIC struct smartlist_t *ifreq_to_smartlist(const uint8_t *ifr,
+ size_t buflen);
STATIC struct smartlist_t *get_interface_addresses_ioctl(int severity,
sa_family_t family);
#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
diff --git a/src/lib/net/alertsock.c b/src/lib/net/alertsock.c
index cc59d7d893..537fdcaee4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/alertsock.h b/src/lib/net/alertsock.h
index 4d0d0dd57c..dab4273cf1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 cfe1a7dc26..4dbf491e1a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -76,7 +76,7 @@ read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most,
chunk->datalen += read_result;
log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result,
(int)buf->datalen);
- tor_assert(read_result < INT_MAX);
+ tor_assert(read_result <= BUF_MAX_LEN);
return (int)read_result;
}
}
@@ -103,9 +103,9 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most,
tor_assert(reached_eof);
tor_assert(SOCKET_OK(fd));
- if (BUG(buf->datalen >= INT_MAX))
+ if (BUG(buf->datalen > BUF_MAX_LEN))
return -1;
- if (BUG(buf->datalen >= INT_MAX - at_most))
+ if (BUG(buf->datalen > BUF_MAX_LEN - at_most))
return -1;
while (at_most > total_read) {
@@ -127,7 +127,7 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most,
check();
if (r < 0)
return r; /* Error */
- tor_assert(total_read+r < INT_MAX);
+ tor_assert(total_read+r <= BUF_MAX_LEN);
total_read += r;
if ((size_t)r < readlen) { /* eof, block, or no more to read. */
break;
@@ -170,7 +170,7 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
} else {
*buf_flushlen -= write_result;
buf_drain(buf, write_result);
- tor_assert(write_result < INT_MAX);
+ tor_assert(write_result <= BUF_MAX_LEN);
return (int)write_result;
}
}
@@ -217,7 +217,7 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz,
if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */
break;
}
- tor_assert(flushed < INT_MAX);
+ tor_assert(flushed <= BUF_MAX_LEN);
return (int)flushed;
}
diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h
index 5058dd0a26..a45c23a273 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/gethostname.c b/src/lib/net/gethostname.c
index e54a1ea16e..001d95391d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/gethostname.h b/src/lib/net/gethostname.h
index b3b77b0589..90f8056779 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/inaddr.c b/src/lib/net/inaddr.c
index d9ae7cd562..d50ac2440c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,7 +11,9 @@
#include "lib/net/inaddr.h"
#include "lib/cc/torint.h"
+#include "lib/container/smartlist.h"
#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
#include "lib/net/inaddr_st.h"
#include "lib/string/compat_ctype.h"
#include "lib/string/compat_string.h"
@@ -35,12 +37,31 @@
* (Like inet_aton(str,addr), but works on Windows and Solaris.)
*/
int
-tor_inet_aton(const char *str, struct in_addr* addr)
+tor_inet_aton(const char *str, struct in_addr *addr)
{
- unsigned a,b,c,d;
+ unsigned a, b, c, d;
char more;
- if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4)
+ bool is_octal = false;
+ smartlist_t *sl = NULL;
+
+ if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a, &b, &c, &d, &more) != 4)
+ return 0;
+
+ /* Parse the octets and check them for leading zeros. */
+ sl = smartlist_new();
+ smartlist_split_string(sl, str, ".", 0, 0);
+ SMARTLIST_FOREACH(sl, const char *, octet, {
+ is_octal = (strlen(octet) > 1 && octet[0] == '0');
+ if (is_octal) {
+ break;
+ }
+ });
+ SMARTLIST_FOREACH(sl, char *, octet, tor_free(octet));
+ smartlist_free(sl);
+
+ if (is_octal)
return 0;
+
if (a > 255) return 0;
if (b > 255) return 0;
if (c > 255) return 0;
diff --git a/src/lib/net/inaddr.h b/src/lib/net/inaddr.h
index 602573944c..8d6766eb5d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 230f29a63a..b9ee2b86cf 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/lib_net.md b/src/lib/net/lib_net.md
new file mode 100644
index 0000000000..b61878d827
--- /dev/null
+++ b/src/lib/net/lib_net.md
@@ -0,0 +1,6 @@
+@dir /lib/net
+@brief lib/net: Low-level network-related code.
+
+This module includes address manipulation, compatibility wrappers,
+convenience functions, and so on.
+
diff --git a/src/lib/net/nettypes.h b/src/lib/net/nettypes.h
index 60039bac09..953673d4c3 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e0a2625d73..e95c3ba819 100644
--- a/src/lib/net/network_sys.c
+++ b/src/lib/net/network_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -37,9 +37,10 @@ subsys_network_shutdown(void)
const subsys_fns_t sys_network = {
.name = "network",
+ SUBSYS_DECLARE_LOCATION(),
/* Network depends on logging, and a lot of other modules depend on network.
*/
- .level = -80,
+ .level = -55,
.supported = true,
.initialize = subsys_network_initialize,
.shutdown = subsys_network_shutdown,
diff --git a/src/lib/net/network_sys.h b/src/lib/net/network_sys.h
index 43e62592ca..734533c7e8 100644
--- a/src/lib/net/network_sys.h
+++ b/src/lib/net/network_sys.h
@@ -1,8 +1,8 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file log_network.h
+ * \file network_sys.h
* \brief Declare subsystem object for the network module.
**/
diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c
index 442bc4a6b3..68a8c01ef4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -372,11 +372,11 @@ static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
cached_getaddrinfo_item_hash,
- cached_getaddrinfo_items_eq)
+ cached_getaddrinfo_items_eq);
HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
cached_getaddrinfo_item_hash,
cached_getaddrinfo_items_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
/** If true, don't try to cache getaddrinfo results. */
static int sandbox_getaddrinfo_cache_disabled = 0;
diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h
index b979b2fb41..ef3d9fa176 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c
index e1b82251ed..adc060a735 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,7 +9,6 @@
* sockets.
**/
-#define SOCKET_PRIVATE
#include "lib/net/socket.h"
#include "lib/net/socketpair.h"
#include "lib/net/address.h"
diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h
index 53a9f1bb92..46735fdef0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/socketpair.c b/src/lib/net/socketpair.c
index f3a0c3770a..d4310020cb 100644
--- a/src/lib/net/socketpair.c
+++ b/src/lib/net/socketpair.c
@@ -1,6 +1,11 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+
+/**
+ * @file socketpair.c
+ * @brief Replacement socketpair() for systems that lack it
+ **/
#include "lib/cc/torint.h"
#include "lib/net/socketpair.h"
diff --git a/src/lib/net/socketpair.h b/src/lib/net/socketpair.h
index 5820606973..b07016ab94 100644
--- a/src/lib/net/socketpair.h
+++ b/src/lib/net/socketpair.h
@@ -1,11 +1,16 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_SOCKETPAIR_H
#define TOR_SOCKETPAIR_H
+/**
+ * @file socketpair.h
+ * @brief Header for socketpair.c
+ **/
+
#include "orconfig.h"
#include "lib/testsupport/testsupport.h"
#include "lib/net/nettypes.h"
diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h
index e55119e0b0..90c4305d29 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,6 +27,17 @@ typedef enum {
SOCKS5_TTL_EXPIRED = 0x06,
SOCKS5_COMMAND_NOT_SUPPORTED = 0x07,
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08,
+
+ /* Extended error code (see prop304). Only used if the SocksPort flag
+ * "ExtendedErrors" is set. */
+ SOCKS5_HS_NOT_FOUND = 0xF0,
+ SOCKS5_HS_IS_INVALID = 0xF1,
+ SOCKS5_HS_INTRO_FAILED = 0xF2,
+ SOCKS5_HS_REND_FAILED = 0xF3,
+ SOCKS5_HS_MISSING_CLIENT_AUTH = 0xF4,
+ SOCKS5_HS_BAD_CLIENT_AUTH = 0xF5,
+ SOCKS5_HS_BAD_ADDRESS = 0xF6,
+ SOCKS5_HS_INTRO_TIMEDOUT = 0xF7,
} socks5_reply_status_t;
#endif /* !defined(TOR_SOCKS5_STATUS_H) */
diff --git a/src/lib/osinfo/lib_osinfo.md b/src/lib/osinfo/lib_osinfo.md
new file mode 100644
index 0000000000..0678ecc21e
--- /dev/null
+++ b/src/lib/osinfo/lib_osinfo.md
@@ -0,0 +1,8 @@
+@dir /lib/osinfo
+@brief lib/osinfo: For inspecting the OS version and capabilities.
+
+In general, we use this module when we're telling the user what operating
+system they are running. We shouldn't make decisions based on the output of
+these checks: instead, we should have more specific checks, either at compile
+time or run time, based on the observed system behavior.
+
diff --git a/src/lib/osinfo/uname.c b/src/lib/osinfo/uname.c
index 34860c407a..f7f5ede307 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,6 +27,40 @@ static char uname_result[256];
/** True iff uname_result is set. */
static int uname_result_is_set = 0;
+#ifdef _WIN32
+/** Table to map claimed windows versions into human-readable windows
+ * versions. */
+static struct {
+ unsigned major;
+ unsigned minor;
+ const char *client_version;
+ const char *server_version;
+} win_version_table[] = {
+ /* This table must be sorted in descending order.
+ * Sources:
+ * https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
+ * https://docs.microsoft.com/en-us/windows/desktop/api/winnt/
+ * ns-winnt-_osversioninfoexa#remarks
+ */
+ /* Windows Server 2019 is indistinguishable from Windows Server 2016
+ * using GetVersionEx().
+ { 10, 0, NULL, "Windows Server 2019" }, */
+ // clang-format off
+ { 10, 0, "Windows 10", "Windows Server 2016" },
+ { 6, 3, "Windows 8.1", "Windows Server 2012 R2" },
+ { 6, 2, "Windows 8", "Windows Server 2012" },
+ { 6, 1, "Windows 7", "Windows Server 2008 R2" },
+ { 6, 0, "Windows Vista", "Windows Server 2008" },
+ { 5, 2, "Windows XP Professional", "Windows Server 2003" },
+ /* Windows XP did not have a server version, but we need something here */
+ { 5, 1, "Windows XP", "Windows XP Server" },
+ { 5, 0, "Windows 2000 Professional", "Windows 2000 Server" },
+ /* Earlier versions are not supported by GetVersionEx(). */
+ { 0, 0, NULL, NULL }
+ // clang-format on
+};
+#endif /* defined(_WIN32) */
+
/** Return a pointer to a description of our platform.
*/
MOCK_IMPL(const char *,
@@ -49,31 +83,6 @@ get_uname,(void))
int is_client = 0;
int is_server = 0;
const char *plat = NULL;
- static struct {
- unsigned major; unsigned minor;
- const char *client_version; const char *server_version;
- } win_version_table[] = {
- /* This table must be sorted in descending order.
- * Sources:
- * https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
- * https://docs.microsoft.com/en-us/windows/desktop/api/winnt/
- * ns-winnt-_osversioninfoexa#remarks
- */
- /* Windows Server 2019 is indistinguishable from Windows Server 2016
- * using GetVersionEx().
- { 10, 0, NULL, "Windows Server 2019" }, */
- { 10, 0, "Windows 10", "Windows Server 2016" },
- { 6, 3, "Windows 8.1", "Windows Server 2012 R2" },
- { 6, 2, "Windows 8", "Windows Server 2012" },
- { 6, 1, "Windows 7", "Windows Server 2008 R2" },
- { 6, 0, "Windows Vista", "Windows Server 2008" },
- { 5, 2, "Windows XP Professional", "Windows Server 2003" },
- /* Windows XP did not have a server version, but we need something here */
- { 5, 1, "Windows XP", "Windows XP Server" },
- { 5, 0, "Windows 2000 Professional", "Windows 2000 Server" },
- /* Earlier versions are not supported by GetVersionEx(). */
- { 0, 0, NULL, NULL }
- };
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
diff --git a/src/lib/osinfo/uname.h b/src/lib/osinfo/uname.h
index 443a30d358..c6b1f43235 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/daemon.c b/src/lib/process/daemon.c
index ae34b5bcb8..b3b98a297e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/daemon.h b/src/lib/process/daemon.h
index 423c498837..23f3117898 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/env.c b/src/lib/process/env.c
index 3912ade197..517b655a5e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,7 +16,6 @@
#include "lib/container/smartlist.h"
#include "lib/log/util_bug.h"
#include "lib/log/log.h"
-#include "lib/malloc/malloc.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
diff --git a/src/lib/process/env.h b/src/lib/process/env.h
index 19c2235970..7838dcaa90 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/include.am b/src/lib/process/include.am
index af5f99617b..18876b3f54 100644
--- a/src/lib/process/include.am
+++ b/src/lib/process/include.am
@@ -16,8 +16,7 @@ src_lib_libtor_process_a_SOURCES = \
src/lib/process/process_win32.c \
src/lib/process/restrict.c \
src/lib/process/setuid.c \
- src/lib/process/waitpid.c \
- src/lib/process/winprocess_sys.c
+ src/lib/process/waitpid.c
src_lib_libtor_process_testing_a_SOURCES = \
$(src_lib_libtor_process_a_SOURCES)
@@ -35,5 +34,4 @@ noinst_HEADERS += \
src/lib/process/process_win32.h \
src/lib/process/restrict.h \
src/lib/process/setuid.h \
- src/lib/process/waitpid.h \
- src/lib/process/winprocess_sys.h
+ src/lib/process/waitpid.h
diff --git a/src/lib/process/lib_process.md b/src/lib/process/lib_process.md
new file mode 100644
index 0000000000..354129e70e
--- /dev/null
+++ b/src/lib/process/lib_process.md
@@ -0,0 +1,2 @@
+@dir /lib/process
+@brief lib/process: Launch and manage subprocesses.
diff --git a/src/lib/process/pidfile.c b/src/lib/process/pidfile.c
index 1b9d1c6d25..e7d9d2c47a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/pidfile.h b/src/lib/process/pidfile.h
index af59041f80..d04302df3a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process.c b/src/lib/process/process.c
index 2194a603ff..12c1f9a772 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -550,6 +550,7 @@ process_vprintf(process_t *process,
char *data;
size = tor_vasprintf(&data, format, args);
+ tor_assert(data != NULL);
process_write(process, (uint8_t *)data, size);
tor_free(data);
}
diff --git a/src/lib/process/process.h b/src/lib/process/process.h
index 05c091a5bf..8879ec4f21 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,6 +15,8 @@
#include "lib/malloc/malloc.h"
#include "lib/string/printf.h"
+#include <stdbool.h>
+
/** Maximum number of bytes to write to a process' stdin. */
#define PROCESS_MAX_WRITE (1024)
@@ -35,8 +37,8 @@ typedef enum {
const char *process_status_to_string(process_status_t status);
typedef enum {
- /** Pass complete \n-terminated lines to the
- * callback (with the \n or \r\n removed). */
+ /** Pass complete newline-terminated lines to the
+ * callback (with the LF or CRLF removed). */
PROCESS_PROTOCOL_LINE,
/** Pass the raw response from read() to the callback. */
@@ -127,18 +129,19 @@ void process_notify_event_exit(process_t *process,
process_exit_code_t);
#ifdef PROCESS_PRIVATE
-MOCK_DECL(STATIC int, process_read_stdout, (process_t *, buf_t *));
-MOCK_DECL(STATIC int, process_read_stderr, (process_t *, buf_t *));
-MOCK_DECL(STATIC void, process_write_stdin, (process_t *, buf_t *));
+struct buf_t;
+MOCK_DECL(STATIC int, process_read_stdout, (process_t *, struct buf_t *));
+MOCK_DECL(STATIC int, process_read_stderr, (process_t *, struct buf_t *));
+MOCK_DECL(STATIC void, process_write_stdin, (process_t *, struct buf_t *));
STATIC void process_read_data(process_t *process,
- buf_t *buffer,
+ struct buf_t *buffer,
process_read_callback_t callback);
STATIC void process_read_buffer(process_t *process,
- buf_t *buffer,
+ struct buf_t *buffer,
process_read_callback_t callback);
STATIC void process_read_lines(process_t *process,
- buf_t *buffer,
+ struct buf_t *buffer,
process_read_callback_t callback);
#endif /* defined(PROCESS_PRIVATE) */
diff --git a/src/lib/process/process_sys.c b/src/lib/process/process_sys.c
index 3c809a00e8..c8332ba91e 100644
--- a/src/lib/process/process_sys.c
+++ b/src/lib/process/process_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,7 +26,8 @@ subsys_process_shutdown(void)
const subsys_fns_t sys_process = {
.name = "process",
- .level = -35,
+ SUBSYS_DECLARE_LOCATION(),
+ .level = -18,
.supported = true,
.initialize = subsys_process_initialize,
.shutdown = subsys_process_shutdown
diff --git a/src/lib/process/process_sys.h b/src/lib/process/process_sys.h
index b7a116d838..97b3aaebd0 100644
--- a/src/lib/process/process_sys.h
+++ b/src/lib/process/process_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 8191bdc1f0..2b47e1874d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 da40b3e567..a6b8304d48 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 7e4082ad13..8683e17fc2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 a50d86df5b..0f264c8710 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/restrict.c b/src/lib/process/restrict.c
index fda284f3d9..cd2a1c57b5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -85,7 +85,7 @@ tor_set_max_memlock(void)
{
/* Future consideration for Windows is probably SetProcessWorkingSetSize
* This is similar to setting the memory rlimit of RLIMIT_MEMLOCK
- * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx
+ * https://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx
*/
struct rlimit limit;
@@ -128,7 +128,7 @@ tor_mlockall(void)
* Future consideration for Windows may be VirtualLock
* VirtualLock appears to implement mlock() but not mlockall()
*
- * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx
+ * https://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx
*/
#ifdef HAVE_UNIX_MLOCKALL
@@ -190,7 +190,7 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
/* Define some maximum connections values for systems where we cannot
* automatically determine a limit. Re Cygwin, see
- * http://archives.seul.org/or/talk/Aug-2006/msg00210.html
+ * https://archives.seul.org/or/talk/Aug-2006/msg00210.html
* For an iPhone, 9999 should work. For Windows and all other unknown
* systems we use 15000 as the default. */
#ifndef HAVE_GETRLIMIT
diff --git a/src/lib/process/restrict.h b/src/lib/process/restrict.h
index 8491c99044..6173d5a438 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/setuid.c b/src/lib/process/setuid.c
index 3c94ce4bac..3cfd520a4f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -64,7 +64,7 @@ log_credential_status(void)
/* log UIDs */
#ifdef HAVE_GETRESUID
- if (getresuid(&ruid, &euid, &suid) != 0 ) {
+ if (getresuid(&ruid, &euid, &suid) != 0) {
log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno));
return -1;
} else {
@@ -85,7 +85,7 @@ log_credential_status(void)
/* log GIDs */
#ifdef HAVE_GETRESGID
- if (getresgid(&rgid, &egid, &sgid) != 0 ) {
+ if (getresgid(&rgid, &egid, &sgid) != 0) {
log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno));
return -1;
} else {
diff --git a/src/lib/process/setuid.h b/src/lib/process/setuid.h
index a2125d2d06..fec35a1216 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/waitpid.c b/src/lib/process/waitpid.c
index 2b38481aeb..33798f65f0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,9 +58,9 @@ process_map_entries_eq_(const waitpid_callback_t *a,
static HT_HEAD(process_map, waitpid_callback_t) process_map = HT_INITIALIZER();
HT_PROTOTYPE(process_map, waitpid_callback_t, node, process_map_entry_hash_,
- process_map_entries_eq_)
+ process_map_entries_eq_);
HT_GENERATE2(process_map, waitpid_callback_t, node, process_map_entry_hash_,
- process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_)
+ process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_);
/**
* Begin monitoring the child pid <b>pid</b> to see if we get a SIGCHLD for
diff --git a/src/lib/process/waitpid.h b/src/lib/process/waitpid.h
index 5faef468c1..171cf206fb 100644
--- a/src/lib/process/waitpid.h
+++ b/src/lib/process/waitpid.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2019, The Tor Project, Inc. */
+/* Copyright (c) 2011-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/lib_pubsub.md b/src/lib/pubsub/lib_pubsub.md
new file mode 100644
index 0000000000..3f4c473436
--- /dev/null
+++ b/src/lib/pubsub/lib_pubsub.md
@@ -0,0 +1,14 @@
+@dir /lib/pubsub
+@brief lib/pubsub: Publish-subscribe message passing.
+
+This module wraps the \refdir{lib/dispatch} module, to provide a more
+ergonomic and type-safe approach to message passing.
+
+In general, we favor this mechanism for cases where higher-level modules
+need to be notified when something happens in lower-level modules. (The
+alternative would be calling up from the lower-level modules, which
+would be error-prone; or maintaining lists of function-pointers, which
+would be clumsy and tend to complicate the call graph.)
+
+See pubsub.c for more information.
+
diff --git a/src/lib/pubsub/pub_binding_st.h b/src/lib/pubsub/pub_binding_st.h
index d841bf3f54..d7c562fc35 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/publish_subscribe.md b/src/lib/pubsub/publish_subscribe.md
new file mode 100644
index 0000000000..bb05b100b1
--- /dev/null
+++ b/src/lib/pubsub/publish_subscribe.md
@@ -0,0 +1,144 @@
+
+@page publish_subscribe Publish-subscribe message passing in Tor
+
+@tableofcontents
+
+## Introduction
+
+Tor has introduced a generic publish-subscribe mechanism for delivering
+messages internally. It is meant to help us improve the modularity of
+our code, by avoiding direct coupling between modules that don't
+actually need to invoke one another.
+
+This publish-subscribe mechanism is *not* meant for handing
+multithreading or multiprocess issues, thought we hope that eventually
+it might be extended and adapted for that purpose. Instead, we use
+publish-subscribe today to decouple modules that shouldn't be calling
+each other directly.
+
+For example, there are numerous parts of our code that might need to
+take action when a circuit is completed: a controller might need to be
+informed, an onion service negotiation might need to be attached, a
+guard might need to be marked as working, or a client connection might
+need to be attached. But many of those actions occur at a higher layer
+than circuit completion: calling them directly is a layering violation,
+and makes our code harder to understand and analyze.
+
+But with message-passing, we can invert this layering violation: circuit
+completion can become a "message" that the circuit code publishes, and
+to which higher-level layers subscribe. This means that circuit
+handling can be decoupled from higher-level modules, and stay nice and
+simple. (@ref pubsub_notyet "1")
+
+> @anchor pubsub_notyet 1. Unfortunately, like most of our code, circuit
+> handling is _not_ yet refactored to use publish-subscribe throughout.
+> Instead, layer violations of the type described here are pretty common
+> in Tor today. To see a small part of what happens when a circuit is
+> completed today, have a look at circuit_build_no_more_hops() and its
+> associated code.
+
+## Channels and delivery policies
+
+To work with messages, especially when refactoring existing code, you'll
+need to understand "channels" and "delivery policies".
+
+Every message is delivered on a "message channel". Each channel
+(conceptually) a queue-like structure that can support an arbitrarily
+number of message types. Where channels vary is their delivery
+mechanisms, and their guarantees about when messages are processed.
+
+Currently, three delivery policies are possible:
+
+ - `DELIV_PROMPT` -- causes messages to be processed via a callback in
+ Tor's event loop. This is generally the best choice, since it
+ avoids unexpected growth of the stack.
+
+ - `DELIV_IMMEDIATE` -- causes messages to be processed immediately
+ on the call stack when they are published. This choice grows the
+ stack, and can lead to unexpected complexity in the call graph.
+ We should only use it when necessary.
+
+ - `DELIV_NEVER` -- causes messages not to be delivered by the message
+ dispatch system at all. Instead, some other part of the code must
+ call dispatch_flush() to get the messages delivered.
+
+See mainloop_pubsub.c and mainloop_pubsub.h for more information and
+implementation details.
+
+## Layers: Dispatch vs publish-subsubscribe vs mainloop.
+
+At the lowest level, messages are sent via the "dispatcher" module in
+@refdir{lib/dispatch}. For performance, this dispatcher works with a
+untyped messages. Publishers, subscribers, channels, and messages are
+distinguished by short integers. Associated data is handled as
+dynamically-typed data pointers, and its types are also stored as short
+integers.
+
+Naturally, this results in a type-unsafe C API, so most other modules
+shouldn't invoke @refdir{lib/dispatch} directly. At a higher level,
+@refdir{lib/pubsub} defines a set of functions and macros that make
+messages named and type-safe. This is the one that other modules should
+use when they want to send or receive a message.
+
+The two modules above do not handle message delivery. Instead, the
+dispatch module takes a callback that it can invoke when a channel
+becomes nonempty, and defines a dispatch_flush() function to deliver all
+the messages queued in a channel. The work of actually making sure that
+dispatch_flush() is called when appropriate falls to the main loop,
+which needs to integrate the message dispatcher with the rest of our
+events and callbacks. This work happens in mainloop_pubsub.c.
+
+
+## How to publish and subscribe
+
+This section gives an overview of how to make new messages and how to
+use them. For full details, see pubsub_macros.h.
+
+Before anybody can publish or subscribe to a message, the message must
+be declared, typically in a header. This uses DECLARE_MESSAGE() or
+DECLARE_MESSAGE_INT().
+
+Only subsystems can publish or subscribe messages. For more information
+about the subsystems architecture, see @ref initialization.
+
+To publish a message, you must:
+ - Include the header that declares the message.
+ - Declare a set of helper functions via DECLARE_PUBLISH(). These
+ must be visible wherever you call PUBLISH().
+ - Call PUBLISH() to actually send a message.
+ - Connect your subsystem to the dispatcher by calling
+ DISPATCH_ADD_PUB() from your subsystem's subsys_fns_t.add_pubsub
+ callback.
+
+To subscribe to a message, you must:
+ - Include the header that declares the message.
+ - Declare a callback function to be invoked when the message is delivered.
+ - Use DISPATCH_SUBSCRIBE at file scope to define a set of wrapper
+ functions to call your callback function with the appropriate type.
+ - Connect your subsystem to the dispatcher by calling
+ DISPATCH_ADD_SUB() from your subsystem's subsys_fns_t.add_pubsub
+ callback.
+
+Again, the file-level documentation for pubsub_macros.h describes how to
+declare a message, how to publish it, and how to subscribe to it.
+
+## Designing good messages
+
+**Frequency**:
+The publish-subscribe system uses a few function calls
+and allocations for each message sent. This makes it unsuitable for
+very-high-bandwidth events, like "receiving a single data cell" or "a
+socket has become writable." It's fine, however, for events that
+ordinarily happen a bit less frequently than that, like a circuit
+getting finished, a new connection getting opened, or so on.
+
+**Semantics**:
+A message should declare that something has happened or is happening,
+not that something in particular should be done.
+
+For example, suppose you want to set up a message so that onion services
+clean up their replay caches whenever we're low on memory. The event
+should be something like `memory_low`, not `clean_up_replay_caches`.
+The latter name would imply that the publisher knew who was subscribing
+to the message and what they intended to do about it, which would be a
+layering violation.
diff --git a/src/lib/pubsub/pubsub.h b/src/lib/pubsub/pubsub.h
index 5346b07517..d0a4d317f3 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e44b7d76ec..3c134f015c 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 5a0c5f5bd3..2781b8251a 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -85,6 +85,11 @@ struct dispatch_t *pubsub_builder_finalize(pubsub_builder_t *,
**/
void pubsub_items_clear_bindings(pubsub_items_t *items);
+/**
+ * @copydoc pubsub_items_free_
+ *
+ * Additionally, set the pointer <b>cfg</b> to NULL.
+ **/
#define pubsub_items_free(cfg) \
FREE_AND_NULL(pubsub_items_t, pubsub_items_free_, (cfg))
void pubsub_items_free_(pubsub_items_t *cfg);
diff --git a/src/lib/pubsub/pubsub_builder_st.h b/src/lib/pubsub/pubsub_builder_st.h
index 545aa3f3ef..57de1240ee 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 bf1196df2c..dbcbb14746 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,7 +9,9 @@
* @brief Enforce various requirements on a pubsub_builder.
**/
+/** @{ */
#define PUBSUB_PRIVATE
+/** @} */
#include "lib/dispatch/dispatch_naming.h"
#include "lib/dispatch/msgtypes.h"
diff --git a/src/lib/pubsub/pubsub_connect.h b/src/lib/pubsub/pubsub_connect.h
index 0ad106044e..b0d6ae7e92 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 53c6e49565..9912c1ae89 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 357e59fd54..e5ffbe501a 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -163,7 +163,7 @@
* hookfn with the appropriate arguments.
*/
-/* Macro to declare common elements shared by DECLARE_MESSAGE and
+/** Macro to declare common elements shared by DECLARE_MESSAGE and
* DECLARE_MESSAGE_INT. Don't call this directly.
*
* Note that the "msg_arg_name" string constant is defined in each
@@ -288,7 +288,7 @@
( 0 ? (publish_fn__ ##messagename((msg_arg_type__##messagename)0), 1) \
: 1)
-/*
+/**
* This macro is for internal use. It backs DISPATCH_ADD_PUB*()
*/
#define DISPATCH_ADD_PUB_(connector, channel, messagename, flags) \
@@ -322,7 +322,7 @@
#define DISPATCH_ADD_PUB_EXCL(connector, channel, messagename) \
DISPATCH_ADD_PUB_(connector, channel, messagename, DISP_FLAG_EXCL)
-/*
+/**
* This macro is for internal use. It backs DISPATCH_ADD_SUB*()
*/
#define DISPATCH_ADD_SUB_(connector, channel, messagename, flags) \
@@ -334,7 +334,7 @@
(flags), \
__FILE__, \
__LINE__)
-/*
+/**
* Use a given connector and channel name to declare that this subsystem will
* receive a given message type.
*
diff --git a/src/lib/pubsub/pubsub_publish.c b/src/lib/pubsub/pubsub_publish.c
index 454a335a78..84c7dae02c 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-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 0686a465de..d9d6fa9ba5 100644
--- a/src/lib/pubsub/pubsub_publish.h
+++ b/src/lib/pubsub/pubsub_publish.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file pubsub_publish.h
+ * @brief Header for pubsub_publish.c
+ **/
+
#ifndef TOR_PUBSUB_PUBLISH_H
#define TOR_PUBSUB_PUBLISH_H
diff --git a/src/lib/sandbox/lib_sandbox.md b/src/lib/sandbox/lib_sandbox.md
new file mode 100644
index 0000000000..dd168c9b13
--- /dev/null
+++ b/src/lib/sandbox/lib_sandbox.md
@@ -0,0 +1,15 @@
+@dir /lib/sandbox
+@brief lib/sandbox: Linux seccomp2-based sandbox.
+
+This module uses Linux's seccomp2 facility via the
+[`libseccomp` library](https://github.com/seccomp/libseccomp), to restrict
+the set of system calls that Tor is allowed to invoke while it is running.
+
+Because there are many libc versions that invoke different system calls, and
+because handling strings is quite complex, this module is more complex and
+less portable than it needs to be.
+
+A better architecture would put the responsibility for invoking tricky system
+calls (like open()) in another, less restricted process, and give that
+process responsibility for enforcing our sandbox rules.
+
diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c
index 3515e8854e..d4f0da8397 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -82,7 +82,7 @@
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
#define USE_BACKTRACE
-#define EXPOSE_CLEAN_BACKTRACE
+#define BACKTRACE_PRIVATE
#include "lib/err/backtrace.h"
#endif /* defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && ... */
@@ -117,6 +117,10 @@
#endif /* defined(__i386__) || ... */
+#ifdef M_SYSCALL
+#define SYSCALL_NAME_DEBUGGING
+#endif
+
/**Determines if at least one sandbox is active.*/
static int sandbox_active = 0;
/** Holds the parameter list configuration for the sandbox.*/
@@ -133,6 +137,10 @@ static sandbox_cfg_t *filter_dynamic = NULL;
* the high bits of the value might get masked out improperly. */
#define SCMP_CMP_MASKED(a,b,c) \
SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c))
+/* For negative constants, the rule to add depends on the glibc version. */
+#define SCMP_CMP_NEG(a,op,b) (libc_negative_constant_needs_cast() ? \
+ (SCMP_CMP((a), (op), (unsigned int)(b))) : \
+ (SCMP_CMP_STR((a), (op), (b))))
/** Variable used for storing all syscall numbers that will be allowed with the
* stage 1 general Tor sandbox.
@@ -166,6 +174,7 @@ static int filter_nopar_gen[] = {
#ifdef __NR_fstat64
SCMP_SYS(fstat64),
#endif
+ SCMP_SYS(fsync),
SCMP_SYS(futex),
SCMP_SYS(getdents),
SCMP_SYS(getdents64),
@@ -265,13 +274,27 @@ static int filter_nopar_gen[] = {
SCMP_SYS(listen),
SCMP_SYS(connect),
SCMP_SYS(getsockname),
+#ifdef ENABLE_NSS
+#ifdef __NR_getpeername
+ SCMP_SYS(getpeername),
+#endif
+#endif
SCMP_SYS(recvmsg),
SCMP_SYS(recvfrom),
SCMP_SYS(sendto),
SCMP_SYS(unlink),
+#ifdef __NR_unlinkat
+ SCMP_SYS(unlinkat),
+#endif
SCMP_SYS(poll)
};
+/* opendir is not a syscall but it will use either open or openat. We do not
+ * want the decision to allow open/openat to be the callers reponsability, so
+ * we create a phony syscall number for opendir and sb_opendir will choose the
+ * correct syscall. */
+#define PHONY_OPENDIR_SYSCALL -2
+
/* These macros help avoid the error where the number of filters we add on a
* single rule don't match the arg_cnt param. */
#define seccomp_rule_add_0(ctx,act,call) \
@@ -425,31 +448,59 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
#endif
#endif
-/* Return true if we think we're running with a libc that always uses
- * openat on linux. */
+/* Return true the libc version is greater or equal than
+ * <b>major</b>.<b>minor</b>. Returns false otherwise. */
static int
-libc_uses_openat_for_everything(void)
+is_libc_at_least(int major, int minor)
{
#ifdef CHECK_LIBC_VERSION
const char *version = gnu_get_libc_version();
if (version == NULL)
return 0;
- int major = -1;
- int minor = -1;
+ int libc_major = -1;
+ int libc_minor = -1;
- tor_sscanf(version, "%d.%d", &major, &minor);
- if (major >= 3)
+ tor_sscanf(version, "%d.%d", &libc_major, &libc_minor);
+ if (libc_major > major)
return 1;
- else if (major == 2 && minor >= 26)
+ else if (libc_major == major && libc_minor >= minor)
return 1;
else
return 0;
#else /* !defined(CHECK_LIBC_VERSION) */
+ (void)major;
+ (void)minor;
return 0;
#endif /* defined(CHECK_LIBC_VERSION) */
}
+/* Return true if we think we're running with a libc that uses openat for the
+ * open function on linux. */
+static int
+libc_uses_openat_for_open(void)
+{
+ return is_libc_at_least(2, 26);
+}
+
+/* Return true if we think we're running with a libc that uses openat for the
+ * opendir function on linux. */
+static int
+libc_uses_openat_for_opendir(void)
+{
+ // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive)
+ return is_libc_at_least(2, 27) ||
+ (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22));
+}
+
+/* Return true if we think we're running with a libc that needs to cast
+ * negative arguments like AT_FDCWD for seccomp rules. */
+static int
+libc_negative_constant_needs_cast(void)
+{
+ return is_libc_at_least(2, 27);
+}
+
/** Allow a single file to be opened. If <b>use_openat</b> is true,
* we're using a libc that remaps all the opens into openats. */
static int
@@ -457,7 +508,7 @@ allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file)
{
if (use_openat) {
return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
- SCMP_CMP(0, SCMP_CMP_EQ, (unsigned int)AT_FDCWD),
+ SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
SCMP_CMP_STR(1, SCMP_CMP_EQ, file));
} else {
return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open),
@@ -475,7 +526,7 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
int rc;
sandbox_cfg_t *elem = NULL;
- int use_openat = libc_uses_openat_for_everything();
+ int use_openat = libc_uses_openat_for_open();
// for each dynamic parameter filters
for (elem = filter; elem != NULL; elem = elem->next) {
@@ -593,7 +644,7 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
if (param != NULL && param->prot == 1 && param->syscall
== SCMP_SYS(openat)) {
rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
- SCMP_CMP(0, SCMP_CMP_EQ, AT_FDCWD),
+ SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value),
SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|
O_CLOEXEC));
@@ -608,6 +659,30 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return 0;
}
+static int
+sb_opendir(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
+ == PHONY_OPENDIR_SYSCALL) {
+ rc = allow_file_open(ctx, libc_uses_openat_for_opendir(), param->value);
+ if (rc != 0) {
+ log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
+ "libseccomp error %d", rc);
+ return rc;
+ }
+ }
+ }
+
+ return 0;
+}
+
/**
* Function responsible for setting up the socket syscall for
* the seccomp filter sandbox.
@@ -648,6 +723,15 @@ sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
}
}
+#ifdef ENABLE_NSS
+ rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
+ SCMP_CMP(0, SCMP_CMP_EQ, PF_INET),
+ SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM),
+ SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
+ if (rc)
+ return rc;
+#endif
+
rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM),
@@ -1113,6 +1197,7 @@ static sandbox_filter_func_t filter_func[] = {
sb_chmod,
sb_open,
sb_openat,
+ sb_opendir,
sb_rename,
#ifdef __NR_fcntl64
sb_fcntl64,
@@ -1432,6 +1517,19 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
return 0;
}
+int
+sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir)
+{
+ sandbox_cfg_t *elem = NULL;
+
+ elem = new_element(PHONY_OPENDIR_SYSCALL, dir);
+
+ elem->next = *cfg;
+ *cfg = elem;
+
+ return 0;
+}
+
/**
* Function responsible for going through the parameter syscall filters and
* call each function pointer in the list.
@@ -1530,8 +1628,10 @@ install_syscall_filter(sandbox_cfg_t* cfg)
return (rc < 0 ? -rc : rc);
}
+#ifdef SYSCALL_NAME_DEBUGGING
#include "lib/sandbox/linux_syscalls.inc"
+/** Return a string containing the name of a given syscall (if we know it) */
static const char *
get_syscall_name(int syscall_num)
{
@@ -1549,6 +1649,28 @@ get_syscall_name(int syscall_num)
}
}
+/** Return the syscall number from a ucontext_t that we got in a signal
+ * handler (if we know how to do that). */
+static int
+get_syscall_from_ucontext(const ucontext_t *ctx)
+{
+ return (int) ctx->uc_mcontext.M_SYSCALL;
+}
+#else
+static const char *
+get_syscall_name(int syscall_num)
+{
+ (void) syscall_num;
+ return "unknown";
+}
+static int
+get_syscall_from_ucontext(const ucontext_t *ctx)
+{
+ (void) ctx;
+ return -1;
+}
+#endif
+
#ifdef USE_BACKTRACE
#define MAX_DEPTH 256
static void *syscall_cb_buf[MAX_DEPTH];
@@ -1564,7 +1686,6 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context)
{
ucontext_t *ctx = (ucontext_t *) (void_context);
const char *syscall_name;
- int syscall;
#ifdef USE_BACKTRACE
size_t depth;
int n_fds, i;
@@ -1579,7 +1700,7 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context)
if (!ctx)
return;
- syscall = (int) ctx->uc_mcontext.M_SYSCALL;
+ int syscall = get_syscall_from_ucontext(ctx);
#ifdef USE_BACKTRACE
depth = backtrace(syscall_cb_buf, MAX_DEPTH);
@@ -1737,6 +1858,13 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
}
int
+sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir)
+{
+ (void)cfg; (void)dir;
+ return 0;
+}
+
+int
sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file)
{
(void)cfg; (void)file;
diff --git a/src/lib/sandbox/sandbox.h b/src/lib/sandbox/sandbox.h
index b4ae6e5c07..a2b3227b90 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,10 +29,10 @@
#define USE_LIBSECCOMP
#endif
-struct sandbox_cfg_elem;
+struct sandbox_cfg_elem_t;
/** Typedef to structure used to manage a sandbox configuration. */
-typedef struct sandbox_cfg_elem sandbox_cfg_t;
+typedef struct sandbox_cfg_elem_t sandbox_cfg_t;
/**
* Linux definitions
@@ -58,7 +58,7 @@ typedef enum {
* Configuration parameter structure associated with the LIBSECCOMP2
* implementation.
*/
-typedef struct smp_param {
+typedef struct smp_param_t {
/** syscall associated with parameter. */
int syscall;
@@ -77,7 +77,7 @@ typedef struct smp_param {
* It is implemented as a linked list of parameters. Currently only controls
* parameters for open, openat, execve, stat64.
*/
-struct sandbox_cfg_elem {
+struct sandbox_cfg_elem_t {
/** Sandbox implementation which dictates the parameter type. */
SB_IMPL implem;
@@ -85,7 +85,7 @@ struct sandbox_cfg_elem {
smp_param_t *param;
/** Next element of the configuration*/
- struct sandbox_cfg_elem *next;
+ struct sandbox_cfg_elem_t *next;
};
/** Function pointer defining the prototype of a filter function.*/
@@ -136,6 +136,13 @@ int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2);
int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file);
/**
+ * Function used to add a opendir allowed filename to a supplied configuration.
+ * The (char*) specifies the path to the allowed dir; we steal the pointer to
+ * that dir.
+ */
+int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir);
+
+/**
* Function used to add a stat/stat64 allowed filename to a configuration.
* The (char*) specifies the path to the allowed file; that pointer is stolen.
*/
diff --git a/src/lib/smartlist_core/lib_smartlist_core.md b/src/lib/smartlist_core/lib_smartlist_core.md
new file mode 100644
index 0000000000..c031dd6f24
--- /dev/null
+++ b/src/lib/smartlist_core/lib_smartlist_core.md
@@ -0,0 +1,10 @@
+@dir /lib/smartlist_core
+@brief lib/smartlist_core: Minimal dynamic array implementation
+
+A `smartlist_t` is a dynamic array type for holding `void *`. We use it
+throughout the rest of the codebase.
+
+There are higher-level pieces in \refdir{lib/container} but
+the ones in lib/smartlist_core are used by the logging code, and therefore
+cannot use the logging code.
+
diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c
index 6b0a305a93..571d17aa5d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 36f23e2009..de6fe69d3a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 a1fbcd444c..03edb80f05 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 c9cf59851f..b76b87406d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e2cc7245b7..fc964201e9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 f5d82be3ae..a7668bfbfb 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,6 +29,7 @@ const uint32_t TOR_ISPRINT_TABLE[8] =
{ 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 };
const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 };
const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 };
+/**@}*/
/** Upper-casing and lowercasing tables to map characters to upper/lowercase
* equivalents. Used by tor_toupper() and tor_tolower(). */
diff --git a/src/lib/string/compat_ctype.h b/src/lib/string/compat_ctype.h
index dbddd356c1..53ee6066f8 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 187f784be5..2bd3c2f2b4 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 ffc892c3e5..f05265bdcc 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/lib_string.md b/src/lib/string/lib_string.md
new file mode 100644
index 0000000000..98e3e652ed
--- /dev/null
+++ b/src/lib/string/lib_string.md
@@ -0,0 +1,13 @@
+@dir /lib/string
+@brief lib/string: Low-level string manipulation.
+
+We have a number of compatibility functions here: some are for handling
+functionality that is not implemented (or not implemented the same) on every
+platform; some are for providing locale-independent versions of libc
+functions that would otherwise be defined differently for different users.
+
+Other functions here are for common string-manipulation operations that we do
+in the rest of the codebase.
+
+Any string function high-level enough to need logging belongs in a
+higher-level module.
diff --git a/src/lib/string/parse_int.c b/src/lib/string/parse_int.c
index fbdd554a47..11ce0fa415 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,6 +9,7 @@
**/
#include "lib/string/parse_int.h"
+#include "lib/cc/compat_compiler.h"
#include <errno.h>
#include <stdlib.h>
@@ -17,6 +18,7 @@
/* Helper: common code to check whether the result of a strtol or strtoul or
* strtoll is correct. */
#define CHECK_STRTOX_RESULT() \
+ STMT_BEGIN \
/* Did an overflow occur? */ \
if (errno == ERANGE) \
goto err; \
@@ -38,7 +40,8 @@
err: \
if (ok) *ok = 0; \
if (next) *next = endptr; \
- return 0
+ return 0; \
+ STMT_END
/** Extract a long from the start of <b>s</b>, in the given numeric
* <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal,
diff --git a/src/lib/string/parse_int.h b/src/lib/string/parse_int.h
index 50d48b44c5..27939ade61 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c
index 26203932e4..86d860935e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/printf.h b/src/lib/string/printf.h
index 6e90770f81..5ab751b338 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/scanf.c b/src/lib/string/scanf.c
index 1bc39b5182..89d1683204 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/scanf.h b/src/lib/string/scanf.h
index b642e242db..67e9c5eb78 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/strings.md b/src/lib/string/strings.md
new file mode 100644
index 0000000000..b22574a05a
--- /dev/null
+++ b/src/lib/string/strings.md
@@ -0,0 +1,102 @@
+
+@page strings String processing in Tor
+
+Since you're reading about a C program, you probably expected this
+section: it's full of functions for manipulating the (notoriously
+dubious) C string abstraction. I'll describe some often-missed
+highlights here.
+
+### Comparing strings and memory chunks ###
+
+We provide strcmpstart() and strcmpend() to perform a strcmp with the start
+or end of a string.
+
+ tor_assert(!strcmpstart("Hello world","Hello"));
+ tor_assert(!strcmpend("Hello world","world"));
+
+ tor_assert(!strcasecmpstart("HELLO WORLD","Hello"));
+ tor_assert(!strcasecmpend("HELLO WORLD","world"));
+
+To compare two string pointers, either of which might be NULL, use
+strcmp_opt().
+
+To search for a string or a chunk of memory within a non-null
+terminated memory block, use tor_memstr or tor_memmem respectively.
+
+We avoid using memcmp() directly, since it tends to be used in cases
+when having a constant-time operation would be better. Instead, we
+recommend tor_memeq() and tor_memneq() for when you need a
+constant-time operation. In cases when you need a fast comparison,
+and timing leaks are not a danger, you can use fast_memeq() and
+fast_memneq().
+
+It's a common pattern to take a string representing one or more lines
+of text, and search within it for some other string, at the start of a
+line. You could search for "\\ntarget", but that would miss the first
+line. Instead, use find_str_at_start_of_line.
+
+### Parsing text ###
+
+Over the years, we have accumulated lots of ways to parse text --
+probably too many. Refactoring them to be safer and saner could be a
+good project! The one that seems most error-resistant is tokenizing
+text with smartlist_split_strings(). This function takes a smartlist,
+a string, and a separator, and splits the string along occurrences of
+the separator, adding new strings for the sub-elements to the given
+smartlist.
+
+To handle time, you can use one of the functions mentioned above in
+"Parsing and encoding time values".
+
+For numbers in general, use the tor_parse_{long,ulong,double,uint64}
+family of functions. Each of these can be called in a few ways. The
+most general is as follows:
+
+ const int BASE = 10;
+ const int MINVAL = 10, MAXVAL = 10000;
+ const char *next;
+ int ok;
+ long lng = tor_parse_long("100", BASE, MINVAL, MAXVAL, &ok, &next);
+
+The return value should be ignored if "ok" is set to false. The input
+string needs to contain an entire number, or it's considered
+invalid... unless the "next" pointer is available, in which case extra
+characters at the end are allowed, and "next" is set to point to the
+first such character.
+
+### Generating blocks of text ###
+
+For not-too-large blocks of text, we provide tor_asprintf(), which
+behaves like other members of the sprintf() family, except that it
+always allocates enough memory on the heap for its output.
+
+For larger blocks: Rather than using strlcat and strlcpy to build
+text, or keeping pointers to the interior of a memory block, we
+recommend that you use the smartlist_* functions to build a smartlist
+full of substrings in order. Then you can concatenate them into a
+single string with smartlist_join_strings(), which also takes optional
+separator and terminator arguments.
+
+Alternatively, you might find it more convenient (and more
+allocation-efficient) to use the buffer API in buffers.c: Construct a buf_t
+object, add your data to it with buf_add_string(), buf_add_printf(), and so
+on, then call buf_extract() to get the resulting output.
+
+As a convenience, we provide smartlist_add_asprintf(), which combines
+the two methods above together. Many of the cryptographic digest
+functions also accept a not-yet-concatenated smartlist of strings.
+
+### Logging helpers ###
+
+Often we'd like to log a value that comes from an untrusted source.
+To do this, use escaped() to escape the nonprintable characters and
+other confusing elements in a string, and surround it by quotes. (Use
+esc_for_log() if you need to allocate a new string.)
+
+It's also handy to put memory chunks into hexadecimal before logging;
+you can use hex_str(memory, length) for that.
+
+The escaped() and hex_str() functions both provide outputs that are
+only valid till they are next invoked; they are not threadsafe.
+
+*/
diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c
index f5061a11d2..c8f12d780e 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -506,6 +506,23 @@ validate_char(const uint8_t *c, uint8_t len)
int
string_is_utf8(const char *str, size_t len)
{
+ // If str is NULL, don't try to read it
+ if (!str) {
+ // We could test for this case, but the low-level logs would produce
+ // confusing test output.
+ // LCOV_EXCL_START
+ if (len) {
+ // Use the low-level logging function, so that the log module can
+ // validate UTF-8 (if needed in future code)
+ tor_log_err_sigsafe(
+ "BUG: string_is_utf8() called with NULL str but non-zero len.");
+ // Since it's a bug, we should probably reject this string
+ return false;
+ }
+ // LCOV_EXCL_STOP
+ return true;
+ }
+
for (size_t i = 0; i < len;) {
uint8_t num_bytes = bytes_in_char(str[i]);
if (num_bytes == 0) // Invalid leading byte found.
@@ -530,8 +547,8 @@ string_is_utf8(const char *str, size_t len)
int
string_is_utf8_no_bom(const char *str, size_t len)
{
- if (len >= 3 && (!strcmpstart(str, "\uFEFF") ||
- !strcmpstart(str, "\uFFFE"))) {
+ if (str && len >= 3 && (!strcmpstart(str, "\uFEFF") ||
+ !strcmpstart(str, "\uFFFE"))) {
return false;
}
return string_is_utf8(str, len);
diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h
index b3c6841d41..e89233df88 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/subsys/initialization.md b/src/lib/subsys/initialization.md
new file mode 100644
index 0000000000..012ab7000d
--- /dev/null
+++ b/src/lib/subsys/initialization.md
@@ -0,0 +1,75 @@
+
+@page initialization Initialization and shutdown
+
+@tableofcontents
+
+@section overview Overview
+
+Tor has a single entry point: tor_run_main() in main.c. All the ways of
+starting a Tor process (ntmain.c, tor_main.c, and tor_api.c) work by invoking tor_run_main().
+
+The tor_run_main() function normally exits (@ref init_exceptwhen "1") by
+returning: not by calling abort() or exit(). Before it returns, it calls
+tor_cleanup() in shutdown.c.
+
+Conceptually, there are several stages in running Tor.
+
+1. First, we initialize those modules that do not depend on the
+ configuration. This happens in the first half of tor_run_main(), and the
+ first half of tor_init(). (@ref init_pending_refactor "2")
+
+2. Second, we parse the command line and our configuration, and configure
+ systems that depend on our configuration or state. This configuration
+ happens midway through tor_init(), which invokes
+ options_init_from_torrc(). We then initialize more systems from the
+ second half of tor_init().
+
+3. At this point we may exit early if we have been asked to do something
+ requiring no further initialization, like printing our version number or
+ creating a new signing key. Otherwise, we proceed to run_tor_main_loop(),
+ which initializes some network-specific parts of Tor, grabs some
+ daemon-only resources (like the data directory lock) and starts Tor itself
+ running.
+
+
+> @anchor init_exceptwhen 1. tor_run_main() _can_ terminate with a call to
+> abort() or exit(), but only when crashing due to a bug, or when forking to
+> run as a daemon.
+
+> @anchor init_pending_refactor 2. The pieces of code that I'm describing as
+> "the first part of tor_init()" and so on deserve to be functions with their
+> own name. I'd like to refactor them, but before I do so, there is some
+> slight reorganization that needs to happen. Notably, the
+> nt_service_parse_options() call ought logically to be later in our
+> initialization sequence. See @ticket{32447} for our refactoring progress.
+
+
+@section subsys Subsystems and initialization
+
+Our current convention is to use the subsystem mechanism to initialize and
+clean up pieces of Tor. The more recently updated pieces of Tor will use
+this mechanism. For examples, see e.g. time_sys.c or log_sys.c.
+
+In simplest terms, a **subsytem** is a logically separate part of Tor that
+can be initialized, shut down, managed, and configured somewhat independently
+of the rest of the program.
+
+The subsys_fns_t type describes a subsystem and a set of functions that
+initialize it, desconstruct it, and so on. To define a subsystem, we declare
+a `const` instance of subsys_fns_t. See the documentation for subsys_fns_t
+for a full list of these functions.
+
+After defining a subsytem, it must be inserted in subsystem_list.c. At that
+point, table-driven mechanisms in subsysmgr.c will invoke its functions when
+appropriate.
+
+@subsection vsconfig Initialization versus configuration
+
+We note that the initialization phase of Tor occurs before any configuration
+is read from disk -- and therefore before any other files are read from
+disk. Therefore, any behavior that depends on Tor's configuration or state
+must occur _after_ the initialization process, during configuration.
+
+
+
+
diff --git a/src/lib/subsys/lib_subsys.md b/src/lib/subsys/lib_subsys.md
new file mode 100644
index 0000000000..764d25d1b6
--- /dev/null
+++ b/src/lib/subsys/lib_subsys.md
@@ -0,0 +1,32 @@
+@dir /lib/subsys
+@brief lib/subsys: Types for declaring a "subsystem".
+
+## Subsystems in Tor
+
+A subsystem is a module with support for initialization, shutdown,
+configuration, and so on.
+
+Many parts of Tor can be initialized, cleaned up, and configured somewhat
+independently through a table-driven mechanism. Each such part is called a
+"subsystem".
+
+To declare a subsystem, make a global `const` instance of the `subsys_fns_t`
+type, filling in the function pointer fields that you require with ones
+corresponding to your subsystem. Any function pointers left as "NULL" will
+be a no-op. Each system must have a name and a "level", which corresponds to
+the order in which it is initialized. (See `app/main/subsystem_list.c` for a
+list of current subsystems and their levels.)
+
+Then, insert your subsystem in the list in `app/main/subsystem_list.c`. It
+will need to occupy a position corresponding to its level.
+
+At this point, your subsystem will be handled like the others: it will get
+initialized at startup, torn down at exit, and so on.
+
+Historical note: Not all of Tor's code is currently handled as
+subsystems. As you work with older code, you may see some parts of the code
+that are initialized from `tor_init()` or `run_tor_main_loop()` or
+`tor_run_main()`; and torn down from `tor_cleanup()`. We aim to migrate
+these to subsystems over time; please don't add any new code that follows
+this pattern.
+
diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h
index 21f984f32d..62c0de026d 100644
--- a/src/lib/subsys/subsys.h
+++ b/src/lib/subsys/subsys.h
@@ -1,14 +1,20 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file subsys.h
+ * @brief Types used to declare a subsystem.
+ **/
+
#ifndef TOR_SUBSYS_T
#define TOR_SUBSYS_T
#include <stdbool.h>
struct pubsub_connector_t;
+struct config_format_t;
/**
* A subsystem is a part of Tor that is initialized, shut down, configured,
@@ -17,8 +23,16 @@ struct pubsub_connector_t;
* All callbacks are optional -- if a callback is set to NULL, the subsystem
* manager will treat it as a no-op.
*
- * You should use c99 named-field initializers with this structure: we
- * will be adding more fields, often in the middle of the structure.
+ * You should use c99 named-field initializers with this structure, for
+ * readability and safety. (There are a lot of functions here, all of them
+ * optional, and many of them with similar signatures.)
+ *
+ * See @ref initialization for more information about initialization and
+ * shutdown in Tor.
+ *
+ * To make a new subsystem, you declare a const instance of this type, and
+ * include it on the list in subsystem_list.c. The code that manages these
+ * subsystems is in subsysmgr.c.
**/
typedef struct subsys_fns_t {
/**
@@ -28,6 +42,11 @@ typedef struct subsys_fns_t {
const char *name;
/**
+ * The file in which the subsystem object is declared. Used for debugging.
+ **/
+ const char *location;
+
+ /**
* Whether this subsystem is supported -- that is, whether it is compiled
* into Tor. For most subsystems, this should be true.
**/
@@ -49,7 +68,7 @@ typedef struct subsys_fns_t {
* it is only for global state or pre-configuration state.
*
* (If you need to do any setup that depends on configuration, you'll need
- * to declare a configuration callback. (Not yet designed))
+ * to declare a configuration callback instead. (Not yet designed))
*
* This function MUST NOT have any parts that can fail.
**/
@@ -57,22 +76,49 @@ typedef struct subsys_fns_t {
/**
* Connect a subsystem to the message dispatch system.
+ *
+ * This function should use the macros in @refdir{lib/pubsub} to register a
+ * set of messages that this subsystem may publish, and may subscribe to.
+ *
+ * See pubsub_macros.h for more information, and for examples.
**/
int (*add_pubsub)(struct pubsub_connector_t *);
/**
* Perform any necessary pre-fork cleanup. This function may not fail.
+ *
+ * On Windows (and any other platforms without fork()), this function will
+ * never be invoked. Otherwise it is used when we are about to start
+ * running as a background daemon, or when we are about to run a unit test
+ * in a subprocess. Unlike the subsys_fns_t.postfork callback, it is run
+ * from the parent process.
+ *
+ * Note that we do not invoke this function when the child process's only
+ * purpose is to call exec() and run another program.
*/
void (*prefork)(void);
/**
* Perform any necessary post-fork setup. This function may not fail.
+ *
+ * On Windows (and any other platforms without fork()), this function will
+ * never be invoked. Otherwise it is used when we are about to start
+ * running as a background daemon, or when we are about to run a unit test
+ * in a subprocess. Unlike the subsys_fns_t.prefork callback, it is run
+ * from the child process.
+ *
+ * Note that we do not invoke this function when the child process's only
+ * purpose is to call exec() and run another program.
*/
void (*postfork)(void);
/**
* Free any thread-local resources held by this subsystem. Called before
* the thread exits.
+ *
+ * This function is not allowed to fail.
+ *
+ * \bug Note that this callback is currently buggy: See \ticket{32103}.
*/
void (*thread_cleanup)(void);
@@ -80,16 +126,93 @@ typedef struct subsys_fns_t {
* Free all resources held by this subsystem.
*
* This function is not allowed to fail.
+ *
+ * Subsystems are shut down when Tor is about to exit or return control to
+ * an embedding program. This callback must return the process to a state
+ * such that subsys_fns_t.init will succeed if invoked again.
**/
void (*shutdown)(void);
+ /**
+ * A config_format_t describing all of the torrc fields owned by this
+ * subsystem.
+ *
+ * This object, if present, is registered in a confmgr_t for Tor's options,
+ * and used to parse option fields from the command line and torrc file.
+ **/
+ const struct config_format_t *options_format;
+
+ /**
+ * A config_format_t describing all of the DataDir/state fields owned by
+ * this subsystem.
+ *
+ * This object, if present, is registered in a confmgr_t for Tor's state,
+ * and used to parse state fields from the DataDir/state file.
+ **/
+ const struct config_format_t *state_format;
+
+ /**
+ * Receive an options object as defined by options_format. Return 0
+ * on success, -1 on failure.
+ *
+ * It is safe to store the pointer to the object until set_options()
+ * is called again.
+ *
+ * This function is only called after all the validation code defined
+ * by subsys_fns_t.options_format has passed.
+ **/
+ int (*set_options)(void *);
+
+ /* XXXX Add an implementation for options_act_reversible() later in this
+ * branch. */
+
+ /**
+ * Receive a state object as defined by state_format. Return 0 on success,
+ * -1 on failure.
+ *
+ * It is safe to store the pointer to the object; set_state() is only
+ * called on startup.
+ *
+ * This function is only called after all the validation code defined
+ * by subsys_fns_t.state_format has passed.
+ *
+ * This function will only be called once per invocation of Tor, since
+ * Tor does not reload its state while it is running.
+ **/
+ int (*set_state)(void *);
+
+ /**
+ * Update any information that needs to be stored in the provided state
+ * object (as defined by state_format). Return 0 on success, -1 on failure.
+ *
+ * The object provided here will be the same one as provided earlier to
+ * set_state(). This method is called when we are about to save the state
+ * to disk.
+ **/
+ int (*flush_state)(void *);
} subsys_fns_t;
+#ifndef COCCI
+/**
+ * Macro to declare a subsystem's location.
+ **/
+#define SUBSYS_DECLARE_LOCATION() \
+ .location = __FILE__
+#endif /* !defined(COCCI) */
+
+/**
+ * Lowest allowed subsystem level.
+ **/
#define MIN_SUBSYS_LEVEL -100
+/**
+ * Highest allowed subsystem level.
+ **/
#define MAX_SUBSYS_LEVEL 100
-/* All tor "libraries" (in src/libs) should have a subsystem level equal to or
- * less than this value. */
+/**
+ * All tor "libraries" (in src/libs) should have a subsystem level equal to or
+ * less than this value.
+ */
#define SUBSYS_LEVEL_LIBS -10
#endif /* !defined(TOR_SUBSYS_T) */
diff --git a/src/lib/term/getpass.c b/src/lib/term/getpass.c
index 8741344acf..d2d6cb2b7b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/term/getpass.h b/src/lib/term/getpass.h
index aa597ec423..b080ad2473 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/term/lib_term.md b/src/lib/term/lib_term.md
new file mode 100644
index 0000000000..f96d25ffe8
--- /dev/null
+++ b/src/lib/term/lib_term.md
@@ -0,0 +1,2 @@
+@dir /lib/term
+@brief lib/term: Terminal operations (password input).
diff --git a/src/lib/testsupport/lib_testsupport.md b/src/lib/testsupport/lib_testsupport.md
new file mode 100644
index 0000000000..7358e6a80f
--- /dev/null
+++ b/src/lib/testsupport/lib_testsupport.md
@@ -0,0 +1,2 @@
+@dir /lib/testsupport
+@brief lib/testsupport: Helpers for test-only code and for function mocking.
diff --git a/src/lib/testsupport/testsupport.h b/src/lib/testsupport/testsupport.h
index 90b7c43b19..165c497f71 100644
--- a/src/lib/testsupport/testsupport.h
+++ b/src/lib/testsupport/testsupport.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,17 +15,42 @@
#ifndef TOR_TESTSUPPORT_H
#define TOR_TESTSUPPORT_H
-#ifdef TOR_UNIT_TESTS
/** The "STATIC" macro marks a function or variable that is static when
* building Tor for production, but non-static when building the unit
- * tests. */
+ * tests.
+ *
+ * For example, a function declared as:
+ *
+ * STATIC int internal_function(void);
+ *
+ * should be only visible for the file on which it is declared, and in the
+ * unit tests.
+ */
+#ifdef TOR_UNIT_TESTS
#define STATIC
-#define EXTERN(type, name) extern type name;
#else /* !defined(TOR_UNIT_TESTS) */
#define STATIC static
-#define EXTERN(type, name)
#endif /* defined(TOR_UNIT_TESTS) */
+/** The "EXTERN" macro is used along with "STATIC" for variables declarations:
+ * it expands to an extern declaration when Tor building unit tests, and to
+ * nothing otherwise.
+ *
+ * For example, to declare a variable as visible only visible in one
+ * file and in the unit tests, you would put this in the header:
+ *
+ * EXTERN(int, local_variable)
+ *
+ * and this in the source:
+ *
+ * STATIC int local_variable;
+ */
+#ifdef TOR_UNIT_TESTS
+#define EXTERN(type, name) extern type name;
+#else
+#define EXTERN(type, name)
+#endif
+
/** Quick and dirty macros to implement test mocking.
*
* To use them, suppose that you have a function you'd like to mock
@@ -70,32 +95,42 @@
*
* @{ */
#ifdef TOR_UNIT_TESTS
+/** Declare a mocked function. For use in headers. */
#define MOCK_DECL(rv, funcname, arglist) \
rv funcname ##__real arglist; \
extern rv(*funcname) arglist
+/** Define the implementation of a mocked function. */
#define MOCK_IMPL(rv, funcname, arglist) \
rv(*funcname) arglist = funcname ##__real; \
rv funcname ##__real arglist
+/** As MOCK_DECL(), but allow attributes. */
#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \
rv funcname ##__real arglist attr; \
extern rv(*funcname) arglist
-#define MOCK_IMPL(rv, funcname, arglist) \
- rv(*funcname) arglist = funcname ##__real; \
- rv funcname ##__real arglist
+/**
+ * Replace <b>func</b> (a mockable function) with a replacement function.
+ *
+ * Only usable when Tor has been built for unit tests. */
#define MOCK(func, replacement) \
do { \
(func) = (replacement); \
} while (0)
+/** Replace <b>func</b> (a mockable function) with its original value.
+ *
+ * Only usable when Tor has been built for unit tests. */
#define UNMOCK(func) \
do { \
func = func ##__real; \
} while (0)
#else /* !defined(TOR_UNIT_TESTS) */
+/** Declare a mocked function. For use in headers. */
#define MOCK_DECL(rv, funcname, arglist) \
rv funcname arglist
-#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \
+/** As MOCK_DECL(), but allow */
+#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \
rv funcname arglist attr
-#define MOCK_IMPL(rv, funcname, arglist) \
+/** Define the implementation of a mocked function. */
+#define MOCK_IMPL(rv, funcname, arglist) \
rv funcname arglist
#endif /* defined(TOR_UNIT_TESTS) */
/** @} */
diff --git a/src/lib/thread/compat_pthreads.c b/src/lib/thread/compat_pthreads.c
index 6f7ecd17da..d143b80252 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 5c8ffa55c6..75ade9c9f2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -129,9 +129,8 @@ subsys_threads_initialize(void)
const subsys_fns_t sys_threads = {
.name = "threads",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
- /* Threads is used by logging, which is a diagnostic feature, we want it to
- * init right after low-level error handling and approx time. */
- .level = -95,
+ .level = -89,
.initialize = subsys_threads_initialize,
};
diff --git a/src/lib/thread/compat_winthreads.c b/src/lib/thread/compat_winthreads.c
index f0b1430e84..2ca5620d23 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/thread/lib_thread.md b/src/lib/thread/lib_thread.md
new file mode 100644
index 0000000000..5870ad790f
--- /dev/null
+++ b/src/lib/thread/lib_thread.md
@@ -0,0 +1,7 @@
+@dir /lib/thread
+@brief lib/thread: Mid-level threading.
+
+This module contains compatibility and convenience code for multithreading,
+except for low-level locks (which are in \refdir{lib/lock} and
+workqueue/threadpool code (which belongs in \refdir{lib/evloop}.)
+
diff --git a/src/lib/thread/numcpus.c b/src/lib/thread/numcpus.c
index b293d965d2..18454ce3ad 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/thread/numcpus.h b/src/lib/thread/numcpus.h
index 2f1ea16eb9..65e6c430cf 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 c0daf2b5e9..6206fac9d6 100644
--- a/src/lib/thread/thread_sys.h
+++ b/src/lib/thread/thread_sys.h
@@ -1,8 +1,8 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file threads_sys.h
+ * \file thread_sys.h
* \brief Declare subsystem object for threads library
**/
diff --git a/src/lib/thread/threading.md b/src/lib/thread/threading.md
new file mode 100644
index 0000000000..a1058c97de
--- /dev/null
+++ b/src/lib/thread/threading.md
@@ -0,0 +1,26 @@
+
+@page threading Threading in Tor
+
+Tor is based around a single main thread and one or more worker
+threads. We aim (with middling success) to use worker threads for
+CPU-intensive activities and the main thread for our networking.
+Fortunately (?) we have enough cryptography that moving what we can
+of the cryptographic processes to the workers should achieve good
+parallelism under most loads. Unfortunately, we only have a small
+fraction of our cryptography done in our worker threads right now.
+
+Our threads-and-workers abstraction is defined in workqueue.c, which
+combines a work queue with a thread pool, and integrates the
+signalling with libevent. Tor's main instance of a work queue is
+instantiated in cpuworker.c. It will probably need some refactoring
+as more types of work are added.
+
+On a lower level, we provide locks with tor_mutex_t in \refdir{lib/lock}, and
+higher-level locking/threading tools in \refdir{lib/thread}, including
+conditions (tor_cond_t), thread-local storage (tor_threadlocal_t), and more.
+
+
+Try to minimize sharing between threads: it is usually best to simply
+make the worker "own" all the data it needs while the work is in
+progress, and to give up ownership when it's complete.
+
diff --git a/src/lib/thread/threads.h b/src/lib/thread/threads.h
index 4b42b9abd9..fcc0c23a87 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -63,7 +63,7 @@ int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex,
void tor_cond_signal_one(tor_cond_t *cond);
void tor_cond_signal_all(tor_cond_t *cond);
-typedef struct tor_threadlocal_s {
+typedef struct tor_threadlocal_t {
#ifdef _WIN32
DWORD index;
#else
@@ -106,7 +106,9 @@ void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value);
typedef struct atomic_counter_t {
atomic_size_t val;
} atomic_counter_t;
+#ifndef COCCI
#define ATOMIC_LINKAGE static
+#endif
#else /* !defined(HAVE_WORKING_STDATOMIC) */
typedef struct atomic_counter_t {
tor_mutex_t mutex;
diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c
index ab45224a7f..6bbad4f98a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 4d16effd29..5089e16ca5 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/lib_time.md b/src/lib/time/lib_time.md
new file mode 100644
index 0000000000..8e58aafcd8
--- /dev/null
+++ b/src/lib/time/lib_time.md
@@ -0,0 +1,9 @@
+@dir /lib/time
+@brief lib/time: Higher-level time functions
+
+This includes both fine-grained timers and monotonic timers, along with
+wrappers for them to try to improve efficiency.
+
+For "what time is it" in UTC, see \refdir{lib/wallclock}. For parsing and
+encoding times and dates, see \refdir{lib/encoding}.
+
diff --git a/src/lib/time/time_sys.c b/src/lib/time/time_sys.c
index 8b9aa2856c..1c1bc4cd18 100644
--- a/src/lib/time/time_sys.c
+++ b/src/lib/time/time_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,6 +20,7 @@ subsys_time_initialize(void)
const subsys_fns_t sys_time = {
.name = "time",
+ SUBSYS_DECLARE_LOCATION(),
/* Monotonic time depends on logging, and a lot of other modules depend on
* monotonic time. */
.level = -80,
diff --git a/src/lib/time/time_sys.h b/src/lib/time/time_sys.h
index 6a860ffd08..f2401e1911 100644
--- a/src/lib/time/time_sys.h
+++ b/src/lib/time/time_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/tvdiff.c b/src/lib/time/tvdiff.c
index d7c245f57a..cbad5a48b8 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/tvdiff.h b/src/lib/time/tvdiff.h
index 657cb99553..e779e758f1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 ed0f821ce8..b92a14d6a1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -68,10 +68,10 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
check_no_tls_errors();
- IF_BUG_ONCE(buf->datalen >= INT_MAX)
- return -1;
- IF_BUG_ONCE(buf->datalen >= INT_MAX - at_most)
- return -1;
+ IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN)
+ return TOR_TLS_ERROR_MISC;
+ IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN - at_most)
+ return TOR_TLS_ERROR_MISC;
while (at_most > total_read) {
size_t readlen = at_most - total_read;
@@ -90,7 +90,7 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
r = read_to_chunk_tls(buf, chunk, tls, readlen);
if (r < 0)
return r; /* Error */
- tor_assert(total_read+r < INT_MAX);
+ tor_assert(total_read+r <= BUF_MAX_LEN);
total_read += r;
if ((size_t)r < readlen) /* eof, block, or no more to read. */
break;
@@ -177,6 +177,6 @@ buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen,
if (r == 0) /* Can't flush any more now. */
break;
} while (sz > 0);
- tor_assert(flushed < INT_MAX);
+ tor_assert(flushed <= BUF_MAX_LEN);
return (int)flushed;
}
diff --git a/src/lib/tls/buffers_tls.h b/src/lib/tls/buffers_tls.h
index 65788c3f34..587426801d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/lib_tls.md b/src/lib/tls/lib_tls.md
new file mode 100644
index 0000000000..26fea723f9
--- /dev/null
+++ b/src/lib/tls/lib_tls.md
@@ -0,0 +1,11 @@
+@dir /lib/tls
+@brief lib/tls: TLS library wrappers
+
+This module has compatibility wrappers around the library (NSS or OpenSSL,
+depending on configuration) that Tor uses to implement the TLS link security
+protocol.
+
+It also implements the logic for some legacy TLS protocol usage we used to
+support in old versions of Tor, involving conditional delivery of certificate
+chains (v1 link protocol) and conditional renegotiation (v2 link protocol).
+
diff --git a/src/lib/tls/nss_countbytes.c b/src/lib/tls/nss_countbytes.c
index 7761727acd..4b98df80ec 100644
--- a/src/lib/tls/nss_countbytes.c
+++ b/src/lib/tls/nss_countbytes.c
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019, The Tor Project Inc. */
+/* Copyright 2018-2020, 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 47f220c4c1..36ed55e10d 100644
--- a/src/lib/tls/nss_countbytes.h
+++ b/src/lib/tls/nss_countbytes.h
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019, The Tor Project, Inc. */
+/* Copyright 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index 1aff40c437..9e70e54725 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -1,8 +1,13 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file tortls.c
+ * @brief Shared functionality for our TLS backends.
+ **/
+
#define TORTLS_PRIVATE
#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
@@ -451,6 +456,7 @@ subsys_tortls_shutdown(void)
const subsys_fns_t sys_tortls = {
.name = "tortls",
+ SUBSYS_DECLARE_LOCATION(),
.level = -50,
.shutdown = subsys_tortls_shutdown
};
diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h
index 799bd6aaeb..517cdc17dd 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TORTLS_H
@@ -81,6 +81,7 @@ void tor_tls_free_all(void);
void tor_tls_init(void);
void tls_log_errors(tor_tls_t *tls, int severity, int domain,
const char *doing);
+const char *tor_tls_get_last_error_msg(const tor_tls_t *tls);
int tor_tls_context_init(unsigned flags,
crypto_pk_t *client_identity,
crypto_pk_t *server_identity,
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
index 866483a94c..3f56f181ee 100644
--- a/src/lib/tls/tortls_internal.h
+++ b/src/lib/tls/tortls_internal.h
@@ -1,11 +1,18 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file tortls_internal.h
+ * @brief Declare internal functions for lib/tls
+ **/
+
#ifndef TORTLS_INTERNAL_H
#define TORTLS_INTERNAL_H
+#include "lib/tls/x509.h"
+
int tor_errno_to_tls_error(int e);
#ifdef ENABLE_OPENSSL
int tor_tls_get_error(tor_tls_t *tls, int r, int extra,
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
index 1436442e1c..c873367f6f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -34,7 +34,7 @@
#include "lib/tls/nss_countbytes.h"
#include "lib/log/util_bug.h"
-DISABLE_GCC_WARNING(strict-prototypes)
+DISABLE_GCC_WARNING("-Wstrict-prototypes")
#include <prio.h>
// For access to rar sockets.
#include <private/pprio.h>
@@ -42,7 +42,7 @@ DISABLE_GCC_WARNING(strict-prototypes)
#include <sslt.h>
#include <sslproto.h>
#include <certt.h>
-ENABLE_GCC_WARNING(strict-prototypes)
+ENABLE_GCC_WARNING("-Wstrict-prototypes")
static SECStatus always_accept_cert_cb(void *, PRFileDesc *, PRBool, PRBool);
@@ -369,6 +369,8 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain,
(void)tls;
PRErrorCode code = PORT_GetError();
+ if (tls)
+ tls->last_error = code;
const char *addr = tls ? tls->address : NULL;
const char *string = PORT_ErrorToString(code);
@@ -391,6 +393,17 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain,
with, addr);
}
}
+const char *
+tor_tls_get_last_error_msg(const tor_tls_t *tls)
+{
+ IF_BUG_ONCE(!tls) {
+ return NULL;
+ }
+ if (tls->last_error == 0) {
+ return NULL;
+ }
+ return PORT_ErrorToString((PRErrorCode)tls->last_error);
+}
tor_tls_t *
tor_tls_new(tor_socket_t sock, int is_server)
@@ -418,6 +431,16 @@ tor_tls_new(tor_socket_t sock, int is_server)
return NULL;
}
+ /* even if though the socket is already nonblocking, we need to tell NSS
+ * about the fact, so that it knows what to do when it says EAGAIN. */
+ PRSocketOptionData data;
+ data.option = PR_SockOpt_Nonblocking;
+ data.value.non_blocking = 1;
+ if (PR_SetSocketOption(ssl, &data) != PR_SUCCESS) {
+ PR_Close(ssl);
+ return NULL;
+ }
+
tor_tls_t *tls = tor_malloc_zero(sizeof(tor_tls_t));
tls->magic = TOR_TLS_MAGIC;
tls->context = ctx;
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index 5bafcf676d..2269714141 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -37,7 +37,7 @@
/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
* srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/opensslv.h>
@@ -54,7 +54,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/bn.h>
#include <openssl/rsa.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#include "lib/tls/tortls.h"
#include "lib/tls/tortls_st.h"
@@ -245,10 +245,30 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
unsigned long err;
while ((err = ERR_get_error()) != 0) {
+ if (tls)
+ tls->last_error = err;
tor_tls_log_one_error(tls, err, severity, domain, doing);
}
}
+/**
+ * Return a string representing more detail about the last error received
+ * on TLS.
+ *
+ * May return null if no error was found.
+ **/
+const char *
+tor_tls_get_last_error_msg(const tor_tls_t *tls)
+{
+ IF_BUG_ONCE(!tls) {
+ return NULL;
+ }
+ if (tls->last_error == 0) {
+ return NULL;
+ }
+ return (const char*)ERR_reason_error_string(tls->last_error);
+}
+
#define CATCH_SYSCALL 1
#define CATCH_ZERO 2
@@ -464,7 +484,9 @@ static const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
/** List of ciphers that clients should advertise, omitting items that
* our OpenSSL doesn't know about. */
static const char CLIENT_CIPHER_LIST[] =
+#ifndef COCCI
#include "lib/tls/ciphers.inc"
+#endif
/* Tell it not to use SSLv2 ciphers, so that it can select an SSLv3 version
* of any cipher we say. */
"!SSLv2"
diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h
index 73f6e6ecca..34abe52ee3 100644
--- a/src/lib/tls/tortls_st.h
+++ b/src/lib/tls/tortls_st.h
@@ -1,11 +1,19 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TORTLS_ST_H
#define TOR_TORTLS_ST_H
+/**
+ * @file tortls_st.h
+ * @brief Structure declarations for internal TLS types.
+ *
+ * These should generally be treated as opaque outside of the
+ * lib/tls module.
+ **/
+
#include "lib/net/socket.h"
#define TOR_TLS_MAGIC 0x71571571
@@ -59,6 +67,8 @@ struct tor_tls_t {
*/
unsigned long last_write_count;
unsigned long last_read_count;
+ /** Most recent error value from ERR_get_error(). */
+ unsigned long last_error;
/** If set, a callback to invoke whenever the client tries to renegotiate
* the handshake. */
void (*negotiated_callback)(tor_tls_t *tls, void *arg);
@@ -69,6 +79,7 @@ struct tor_tls_t {
/** Last values retried from tor_get_prfiledesc_byte_counts(). */
uint64_t last_write_count;
uint64_t last_read_count;
+ long last_error;
#endif
};
diff --git a/src/lib/tls/tortls_sys.h b/src/lib/tls/tortls_sys.h
index 4b04f85f0c..177c198f71 100644
--- a/src/lib/tls/tortls_sys.h
+++ b/src/lib/tls/tortls_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/x509.c b/src/lib/tls/x509.c
index b4a0f8dabf..2515499298 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h
index 0390a5464d..5919b9089d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 f858baae98..145be7e71c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e04afaf07b..341bb57104 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 7724288279..2abf02851d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,7 +19,7 @@
/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
* srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/opensslv.h>
@@ -36,7 +36,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/rsa.h>
#include <openssl/x509.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
diff --git a/src/lib/trace/debug.h b/src/lib/trace/debug.h
index 92bb95c883..87b3074e0b 100644
--- a/src/lib/trace/debug.h
+++ b/src/lib/trace/debug.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/trace/events.h b/src/lib/trace/events.h
index 9de86d63f2..368f85dd02 100644
--- a/src/lib/trace/events.h
+++ b/src/lib/trace/events.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/trace/lib_trace.md b/src/lib/trace/lib_trace.md
new file mode 100644
index 0000000000..a7a32529b0
--- /dev/null
+++ b/src/lib/trace/lib_trace.md
@@ -0,0 +1,6 @@
+@dir /lib/trace
+@brief lib/trace: Function-tracing functionality API.
+
+This module is used for adding "trace" support (low-granularity function
+logging) to Tor. Right now it doesn't have many users.
+
diff --git a/src/lib/trace/trace.c b/src/lib/trace/trace.c
index 18be63c5a8..4e5c66b4c6 100644
--- a/src/lib/trace/trace.c
+++ b/src/lib/trace/trace.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/trace/trace.h b/src/lib/trace/trace.h
index 5001b28a1d..5e24678c3c 100644
--- a/src/lib/trace/trace.h
+++ b/src/lib/trace/trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, 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 900a1e12a0..09f11aa316 100644
--- a/src/lib/version/git_revision.c
+++ b/src/lib/version/git_revision.c
@@ -1,24 +1,39 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "lib/version/git_revision.h"
+/**
+ * @file git_revision.c
+ * @brief Strings to describe the current Git commit.
+ **/
+
/** String describing which Tor Git repository version the source was
* built from. This string is generated by a bit of shell kludging in
* src/core/include.am, and is usually right.
*/
const char tor_git_revision[] =
+#ifndef COCCI
#ifndef _MSC_VER
#include "micro-revision.i"
#endif
+#endif
"";
+/**
+ * String appended to Tor bug messages describing the Tor version.
+ *
+ * It has the form "(on Tor 0.4.3.1-alpha)" or
+ * "(on Tor 0.4.3.1-alpha git-b994397f1af193f8)"
+ **/
const char tor_bug_suffix[] = " (on Tor " VERSION
+#ifndef COCCI
#ifndef _MSC_VER
" "
#include "micro-revision.i"
#endif
+#endif /* !defined(COCCI) */
")";
diff --git a/src/lib/version/git_revision.h b/src/lib/version/git_revision.h
index 79e3c6684b..80b6c4734e 100644
--- a/src/lib/version/git_revision.h
+++ b/src/lib/version/git_revision.h
@@ -1,11 +1,16 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_GIT_REVISION_H
#define TOR_GIT_REVISION_H
+/**
+ * @file git_revision.h
+ * @brief Header for git_revision.c
+ **/
+
extern const char tor_git_revision[];
extern const char tor_bug_suffix[];
diff --git a/src/lib/version/lib_version.md b/src/lib/version/lib_version.md
new file mode 100644
index 0000000000..ccc45920f9
--- /dev/null
+++ b/src/lib/version/lib_version.md
@@ -0,0 +1,2 @@
+@dir /lib/version
+@brief lib/version: holds the current version of Tor.
diff --git a/src/lib/version/torversion.h b/src/lib/version/torversion.h
index 7b0fb66ec0..679df74381 100644
--- a/src/lib/version/torversion.h
+++ b/src/lib/version/torversion.h
@@ -1,11 +1,16 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_VERSION_H
#define TOR_VERSION_H
+/**
+ * @file torversion.h
+ * @brief Header for version.c.
+ **/
+
const char *get_version(void);
const char *get_short_version(void);
diff --git a/src/lib/version/version.c b/src/lib/version/version.c
index 434e6fb424..ec1d0bea2f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -10,6 +10,11 @@
#include <stdio.h>
#include <string.h>
+/**
+ * @file version.c
+ * @brief Functions to get the version of Tor.
+ **/
+
/** A shorter version of this Tor process's version, for export in our router
* descriptor. (Does not include the git version, if any.) */
static const char the_short_tor_version[] =
@@ -19,6 +24,10 @@ static const char the_short_tor_version[] =
#endif
"";
+/**
+ * Longest possible version length. We make this a constant so that we
+ * can statically allocate the_tor_version.
+ **/
#define MAX_VERSION_LEN 128
/** The version of this Tor process, possibly including git version */
diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c
index 77eeddaf56..c815f20e51 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -44,6 +44,9 @@ update_approx_time(time_t now)
}
#endif /* !defined(TIME_IS_FAST) */
+/**
+ * Initialize the "wallclock" subsystem by setting the current cached time.
+ **/
static int
subsys_wallclock_initialize(void)
{
@@ -51,8 +54,12 @@ subsys_wallclock_initialize(void)
return 0;
}
+/**
+ * Subsystem function table describing the "wallclock" subsystem.
+ **/
const subsys_fns_t sys_wallclock = {
.name = "wallclock",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
/* Approximate time is a diagnostic feature, we want it to init right after
* low-level error handling. */
diff --git a/src/lib/wallclock/approx_time.h b/src/lib/wallclock/approx_time.h
index e7da160122..42040a1f52 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/lib_wallclock.md b/src/lib/wallclock/lib_wallclock.md
new file mode 100644
index 0000000000..f21721f6f6
--- /dev/null
+++ b/src/lib/wallclock/lib_wallclock.md
@@ -0,0 +1,11 @@
+@dir /lib/wallclock
+@brief lib/wallclock: Inspect and manipulate the current time.
+
+This module handles our concept of "what time is it" or "what time does the
+world agree it is?" Generally, if you want something derived from UTC, this
+is the module for you.
+
+For versions of the time that are more local, more monotonic, or more
+accurate, see \refdir{lib/time}. For parsing and encoding times and dates,
+see \refdir{lib/encoding}.
+
diff --git a/src/lib/wallclock/time_to_tm.c b/src/lib/wallclock/time_to_tm.c
index f7cb21827b..8c747b4c7b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -198,3 +198,4 @@ tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out)
return correct_tm(0, timep, result, r, err_out);
}
#endif /* defined(HAVE_GMTIME_R) || ... */
+/**@}*/
diff --git a/src/lib/wallclock/time_to_tm.h b/src/lib/wallclock/time_to_tm.h
index da27fcaba1..bfa8fa3689 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h
index e632d04a04..d7d5bda99f 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -69,6 +69,7 @@
} while (0)
#endif /* !defined(timersub) */
+#ifndef COCCI
#ifndef timercmp
/** Replacement for timercmp on platforms that do not have it: returns true
* iff the relational operator "op" makes the expression tv1 op tv2 true.
@@ -82,5 +83,6 @@
((tv1)->tv_usec op (tv2)->tv_usec) : \
((tv1)->tv_sec op (tv2)->tv_sec))
#endif /* !defined(timercmp) */
+#endif /* !defined(COCCI) */
#endif /* !defined(TOR_TIMEVAL_H) */
diff --git a/src/lib/wallclock/tor_gettimeofday.c b/src/lib/wallclock/tor_gettimeofday.c
index 63538f3b81..a07f83220d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 6fec2fc893..c1a8afca3a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 a30912b8fb..3997d11e7a 100644
--- a/src/lib/wallclock/wallclock_sys.h
+++ b/src/lib/wallclock/wallclock_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/mainpage.md b/src/mainpage.md
new file mode 100644
index 0000000000..2c4c494354
--- /dev/null
+++ b/src/mainpage.md
@@ -0,0 +1,150 @@
+@mainpage Tor source reference
+
+@tableofcontents
+
+@section welcome Welcome to Tor
+
+(For an up-to-date rendered copy of this documentation, see
+https://src-ref.docs.torproject.org/tor/index.html .)
+
+This documentation describes the general structure of the Tor codebase, how
+it fits together, what functionality is available for extending Tor, and
+gives some notes on how Tor got that way. It also includes a reference for
+nearly every function, type, file, and module in the Tor source code. The
+high-level documentation is a work in progress.
+
+Tor itself remains a work in progress too: We've been working on it for
+nearly two decades, and we've learned a lot about good coding since we first
+started. This means, however, that some of the older pieces of Tor will have
+some "code smell" in them that could stand a brisk refactoring. So when we
+describe a piece of code, we'll sometimes give a note on how it got that way,
+and whether we still think that's a good idea.
+
+This document is not an overview of the Tor protocol. For that, see the
+design paper and the specifications at https://spec.torproject.org/ .
+
+For more information about Tor's coding standards and some helpful
+development tools, see
+[doc/HACKING](https://gitweb.torproject.org/tor.git/tree/doc/HACKING) in the
+Tor repository.
+
+@section topics Topic-related documentation
+
+@subpage intro
+
+@subpage arch_goals
+
+@subpage initialization
+
+@subpage dataflow
+
+@subpage certificates
+
+@subpage threading
+
+@subpage strings
+
+@subpage time_periodic
+
+@subpage configuration
+
+@subpage publish_subscribe
+
+@page intro A high-level overview
+
+@tableofcontents
+
+@section highlevel The very high level
+
+Ultimately, Tor runs as an event-driven network daemon: it responds to
+network events, signals, and timers by sending and receiving things over
+the network. Clients, relays, and directory authorities all use the
+same codebase: the Tor process will run as a client, relay, or authority
+depending on its configuration.
+
+Tor has a few major dependencies, including Libevent (used to tell which
+sockets are readable and writable), OpenSSL or NSS (used for many encryption
+functions, and to implement the TLS protocol), and zlib (used to
+compress and uncompress directory information).
+
+Most of Tor's work today is done in a single event-driven main thread.
+Tor also spawns one or more worker threads to handle CPU-intensive
+tasks. (Right now, this only includes circuit encryption and the more
+expensive compression algorithms.)
+
+On startup, Tor initializes its libraries, reads and responds to its
+configuration files, and launches a main event loop. At first, the only
+events that Tor listens for are a few signals (like TERM and HUP), and
+one or more listener sockets (for different kinds of incoming
+connections). Tor also configures several timers to handle periodic
+events. As Tor runs over time, other events will open, and new events
+will be scheduled.
+
+The codebase is divided into a few top-level subdirectories, each of
+which contains several sub-modules.
+
+ - `ext` -- Code maintained elsewhere that we include in the Tor
+ source distribution.
+
+ - \refdir{lib} -- Lower-level utility code, not necessarily
+ tor-specific.
+
+ - `trunnel` -- Automatically generated code (from the Trunnel
+ tool): used to parse and encode binary formats.
+
+ - \refdir{core} -- Networking code that is implements the central
+ parts of the Tor protocol and main loop.
+
+ - \refdir{feature} -- Aspects of Tor (like directory management,
+ running a relay, running a directory authorities, managing a list of
+ nodes, running and using onion services) that are built on top of the
+ mainloop code.
+
+ - \refdir{app} -- Highest-level functionality; responsible for setting
+ up and configuring the Tor daemon, making sure all the lower-level
+ modules start up when required, and so on.
+
+ - \refdir{tools} -- Binaries other than Tor that we produce.
+ Currently this is tor-resolve, tor-gencert, and the tor_runner.o helper
+ module.
+
+ - `test` -- unit tests, regression tests, and a few integration
+ tests.
+
+In theory, the above parts of the codebase are sorted from highest-level to
+lowest-level, where high-level code is only allowed to invoke lower-level
+code, and lower-level code never includes or depends on code of a higher
+level. In practice, this refactoring is incomplete: The modules in
+\refdir{lib} are well-factored, but there are many layer violations ("upward
+dependencies") in \refdir{core} and \refdir{feature}.
+We aim to eliminate those over time.
+
+@section keyabstractions Some key high-level abstractions
+
+The most important abstractions at Tor's high-level are Connections,
+Channels, Circuits, and Nodes.
+
+A 'Connection' (connection_t) represents a stream-based information flow.
+Most connections are TCP connections to remote Tor servers and clients. (But
+as a shortcut, a relay will sometimes make a connection to itself without
+actually using a TCP connection. More details later on.) Connections exist
+in different varieties, depending on what functionality they provide. The
+principle types of connection are edge_connection_t (eg a socks connection or
+a connection from an exit relay to a destination), or_connection_t (a TLS
+stream connecting to a relay), dir_connection_t (an HTTP connection to learn
+about the network), and control_connection_t (a connection from a
+controller).
+
+A 'Circuit' (circuit_t) is persistent tunnel through the Tor network,
+established with public-key cryptography, and used to send cells one or more
+hops. Clients keep track of multi-hop circuits (origin_circuit_t), and the
+cryptography associated with each hop. Relays, on the other hand, keep track
+only of their hop of each circuit (or_circuit_t).
+
+A 'Channel' (channel_t) is an abstract view of sending cells to and from a
+Tor relay. Currently, all channels are implemented using OR connections
+(channel_tls_t). If we switch to other strategies in the future, we'll have
+more connection types.
+
+A 'Node' (node_t) is a view of a Tor instance's current knowledge and opinions
+about a Tor relay or bridge.
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
index 0ca960bd69..6d2ef33eec 100644
--- a/src/rust/protover/protover.rs
+++ b/src/rust/protover/protover.rs
@@ -161,30 +161,30 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
"Cons=1-2 \
Desc=1-2 \
DirCache=1-2 \
+ FlowCtrl=1 \
HSDir=1-2 \
HSIntro=3-4 \
HSRend=1-2 \
Link=1-5 \
LinkAuth=3 \
Microdesc=1-2 \
- Relay=1-2 \
Padding=2 \
- FlowCtrl=1"
+ Relay=1-2"
)
} else {
cstr!(
"Cons=1-2 \
Desc=1-2 \
DirCache=1-2 \
+ FlowCtrl=1 \
HSDir=1-2 \
HSIntro=3-4 \
HSRend=1-2 \
Link=1-5 \
LinkAuth=1,3 \
Microdesc=1-2 \
- Relay=1-2 \
Padding=2 \
- FlowCtrl=1"
+ Relay=1-2"
)
}
}
diff --git a/src/test/.may_include b/src/test/.may_include
new file mode 100644
index 0000000000..11c5ffbb14
--- /dev/null
+++ b/src/test/.may_include
@@ -0,0 +1,2 @@
+*.h
+*.inc
diff --git a/src/test/bench.c b/src/test/bench.c
index cf732df593..7a8c04e802 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/bt_test.py b/src/test/bt_test.py
index f9ca79efde..d728f13596 100755
--- a/src/test/bt_test.py
+++ b/src/test/bt_test.py
@@ -15,7 +15,11 @@ OK
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
diff --git a/src/test/conf_examples/badnick_1/expected_log_no_dirauth_relay b/src/test/conf_examples/badnick_1/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..9190a3326b
--- /dev/null
+++ b/src/test/conf_examples/badnick_1/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*badnick_1[./]*torrc
diff --git a/src/test/conf_examples/badnick_1/expected_no_dirauth_relay b/src/test/conf_examples/badnick_1/expected_no_dirauth_relay
new file mode 100644
index 0000000000..b00be15c2e
--- /dev/null
+++ b/src/test/conf_examples/badnick_1/expected_no_dirauth_relay
@@ -0,0 +1 @@
+Nickname TooManyCharactersInThisNickname
diff --git a/src/test/conf_examples/badnick_1/torrc b/src/test/conf_examples/badnick_1/torrc
index 41ee4894f1..087e3f2ff1 100644
--- a/src/test/conf_examples/badnick_1/torrc
+++ b/src/test/conf_examples/badnick_1/torrc
@@ -1,2 +1,4 @@
# This nickname is too long; we won't accept it.
+# (Unless the relay module is disabled, because Nickname is a
+# relay-only option. We'll ignore all relay-only options in #32395.)
Nickname TooManyCharactersInThisNickname
diff --git a/src/test/conf_examples/badnick_2/expected_log_no_dirauth_relay b/src/test/conf_examples/badnick_2/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..a15c7b02cb
--- /dev/null
+++ b/src/test/conf_examples/badnick_2/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*badnick_2[./]*torrc
diff --git a/src/test/conf_examples/badnick_2/expected_no_dirauth_relay b/src/test/conf_examples/badnick_2/expected_no_dirauth_relay
new file mode 100644
index 0000000000..08dcdc33a9
--- /dev/null
+++ b/src/test/conf_examples/badnick_2/expected_no_dirauth_relay
@@ -0,0 +1 @@
+Nickname has a space
diff --git a/src/test/conf_examples/badnick_2/torrc b/src/test/conf_examples/badnick_2/torrc
index 07acc61698..51a5f96c00 100644
--- a/src/test/conf_examples/badnick_2/torrc
+++ b/src/test/conf_examples/badnick_2/torrc
@@ -1,2 +1,4 @@
# this nickname has spaces in it and won't work.
+# (Unless the relay module is disabled, because Nickname is a
+# relay-only option. We'll ignore all relay-only options in #32395.)
Nickname has a space
diff --git a/src/test/conf_examples/bridgeauth_1/error_no_dirauth b/src/test/conf_examples/bridgeauth_1/error_no_dirauth
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/error_no_dirauth
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/bridgeauth_1/error_no_dirauth_relay b/src/test/conf_examples/bridgeauth_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/bridgeauth_1/expected b/src/test/conf_examples/bridgeauth_1/expected
new file mode 100644
index 0000000000..d43aaf2c8b
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/expected
@@ -0,0 +1,7 @@
+Address 198.51.100.123
+AuthoritativeDirectory 1
+BridgeAuthoritativeDir 1
+ContactInfo tor_parse_test@example.com
+DirPort 80
+Nickname Unnamed
+ORPort 443
diff --git a/src/test/conf_examples/bridgeauth_1/expected_log b/src/test/conf_examples/bridgeauth_1/expected_log
new file mode 100644
index 0000000000..cabe9d3f89
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*bridgeauth_1[./]*torrc
diff --git a/src/test/conf_examples/bridgeauth_1/torrc b/src/test/conf_examples/bridgeauth_1/torrc
new file mode 100644
index 0000000000..740bc6c2eb
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/torrc
@@ -0,0 +1,8 @@
+AuthoritativeDirectory 1
+BridgeAuthoritativeDir 1
+
+ContactInfo tor_parse_test@example.com
+
+Address 198.51.100.123
+ORPort 443
+DirPort 80
diff --git a/src/test/conf_examples/contactinfo_notutf8/expected_log_no_dirauth_relay b/src/test/conf_examples/contactinfo_notutf8/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..caa07aca40
--- /dev/null
+++ b/src/test/conf_examples/contactinfo_notutf8/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*contactinfo_notutf8[./]*torrc
diff --git a/src/test/conf_examples/contactinfo_notutf8/expected_no_dirauth_relay b/src/test/conf_examples/contactinfo_notutf8/expected_no_dirauth_relay
new file mode 100644
index 0000000000..cc8bd7b8e3
--- /dev/null
+++ b/src/test/conf_examples/contactinfo_notutf8/expected_no_dirauth_relay
@@ -0,0 +1 @@
+ContactInfo "\304\353\304\353\304\353@example.com"
diff --git a/src/test/conf_examples/contactinfo_notutf8/torrc b/src/test/conf_examples/contactinfo_notutf8/torrc
index 2ee4d093c5..0176a56a97 100644
--- a/src/test/conf_examples/contactinfo_notutf8/torrc
+++ b/src/test/conf_examples/contactinfo_notutf8/torrc
@@ -1 +1,5 @@
+# We only accept ContactInfo in UTF-8 (or 7-bit ASCII)
+# (Unless the relay module is disabled, because ContactInfo is a
+# relay-only option. We'll ignore all relay-only options in #32395.
+# But at the moment, tor canonicalises and quotes the string.)
ContactInfo ÄëÄëÄë@example.com
diff --git a/src/test/conf_examples/controlsock/error b/src/test/conf_examples/controlsock/error
new file mode 100644
index 0000000000..8fbea37894
--- /dev/null
+++ b/src/test/conf_examples/controlsock/error
@@ -0,0 +1 @@
+not supported on this OS\|without setting a ControlSocket
diff --git a/src/test/conf_examples/controlsock/torrc b/src/test/conf_examples/controlsock/torrc
new file mode 100644
index 0000000000..dd3cb7ede5
--- /dev/null
+++ b/src/test/conf_examples/controlsock/torrc
@@ -0,0 +1 @@
+ControlSocketsGroupWritable 1
diff --git a/src/test/conf_examples/crypto_accel/expected b/src/test/conf_examples/crypto_accel/expected
new file mode 100644
index 0000000000..ea80ca19dc
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/expected
@@ -0,0 +1,2 @@
+AccelName nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/crypto_accel/expected_log b/src/test/conf_examples/crypto_accel/expected_log
new file mode 100644
index 0000000000..7fab0c8dad
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/expected_log
@@ -0,0 +1 @@
+Unable to load dynamic OpenSSL engine "nonexistent_chartreuse_accelerator"
diff --git a/src/test/conf_examples/crypto_accel/expected_log_nss b/src/test/conf_examples/crypto_accel/expected_log_nss
new file mode 100644
index 0000000000..c0fe7b003c
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/expected_log_nss
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .*
diff --git a/src/test/conf_examples/crypto_accel/expected_nss b/src/test/conf_examples/crypto_accel/expected_nss
new file mode 100644
index 0000000000..ea80ca19dc
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/expected_nss
@@ -0,0 +1,2 @@
+AccelName nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/crypto_accel/torrc b/src/test/conf_examples/crypto_accel/torrc
new file mode 100644
index 0000000000..9ca18903b7
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/torrc
@@ -0,0 +1,3 @@
+
+AccelName nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/crypto_accel_req/error b/src/test/conf_examples/crypto_accel_req/error
new file mode 100644
index 0000000000..e12e002915
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel_req/error
@@ -0,0 +1 @@
+Unable to load required dynamic OpenSSL engine "nonexistent_chartreuse_accelerator"
diff --git a/src/test/conf_examples/crypto_accel_req/expected_log_nss b/src/test/conf_examples/crypto_accel_req/expected_log_nss
new file mode 100644
index 0000000000..c0fe7b003c
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel_req/expected_log_nss
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .*
diff --git a/src/test/conf_examples/crypto_accel_req/expected_nss b/src/test/conf_examples/crypto_accel_req/expected_nss
new file mode 100644
index 0000000000..f3e172f640
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel_req/expected_nss
@@ -0,0 +1,2 @@
+AccelName !nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/crypto_accel_req/torrc b/src/test/conf_examples/crypto_accel_req/torrc
new file mode 100644
index 0000000000..981d9116fc
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel_req/torrc
@@ -0,0 +1,3 @@
+
+AccelName !nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/dirauth_1/error_no_dirauth b/src/test/conf_examples/dirauth_1/error_no_dirauth
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/error_no_dirauth
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_1/error_no_dirauth_relay b/src/test/conf_examples/dirauth_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_1/expected b/src/test/conf_examples/dirauth_1/expected
new file mode 100644
index 0000000000..901f7d947f
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/expected
@@ -0,0 +1,8 @@
+Address 192.0.2.1
+AuthoritativeDirectory 1
+ContactInfo tor_parse_test@example.net
+DirPort 9030
+DownloadExtraInfo 1
+Nickname Unnamed
+ORPort 9001
+V3AuthoritativeDirectory 1
diff --git a/src/test/conf_examples/dirauth_1/expected_log b/src/test/conf_examples/dirauth_1/expected_log
new file mode 100644
index 0000000000..b788be2e33
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*dirauth_1[./]*torrc
diff --git a/src/test/conf_examples/dirauth_1/torrc b/src/test/conf_examples/dirauth_1/torrc
new file mode 100644
index 0000000000..b870e6e8e0
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/torrc
@@ -0,0 +1,8 @@
+AuthoritativeDirectory 1
+V3AuthoritativeDirectory 1
+
+ContactInfo tor_parse_test@example.net
+
+Address 192.0.2.1
+ORPort 9001
+DirPort 9030
diff --git a/src/test/conf_examples/dirauth_2/expected b/src/test/conf_examples/dirauth_2/expected
new file mode 100644
index 0000000000..19ab024ed3
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected
@@ -0,0 +1 @@
+AuthDirMaxServersPerAddr 8
diff --git a/src/test/conf_examples/dirauth_2/expected_log b/src/test/conf_examples/dirauth_2/expected_log
new file mode 100644
index 0000000000..88611fee9d
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_log
@@ -0,0 +1 @@
+Read configuration file
diff --git a/src/test/conf_examples/dirauth_2/expected_log_no_dirauth b/src/test/conf_examples/dirauth_2/expected_log_no_dirauth
new file mode 100644
index 0000000000..01110c5d8c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_log_no_dirauth
@@ -0,0 +1 @@
+This copy of Tor was built without support for the option "AuthDirMaxServersPerAddr". Skipping. \ No newline at end of file
diff --git a/src/test/conf_examples/dirauth_2/expected_log_no_dirauth_relay b/src/test/conf_examples/dirauth_2/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..01110c5d8c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+This copy of Tor was built without support for the option "AuthDirMaxServersPerAddr". Skipping. \ No newline at end of file
diff --git a/src/test/conf_examples/dirauth_2/expected_no_dirauth b/src/test/conf_examples/dirauth_2/expected_no_dirauth
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_no_dirauth
diff --git a/src/test/conf_examples/dirauth_2/expected_no_dirauth_relay b/src/test/conf_examples/dirauth_2/expected_no_dirauth_relay
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_no_dirauth_relay
diff --git a/src/test/conf_examples/dirauth_2/torrc b/src/test/conf_examples/dirauth_2/torrc
new file mode 100644
index 0000000000..bd1cdbc8b9
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/torrc
@@ -0,0 +1,5 @@
+#
+# This will get accepted if the module is enabled, and ignored if the module
+# is disabled.
+#
+AuthDirMaxServersPerAddr 8
diff --git a/src/test/conf_examples/empty_1/expected b/src/test/conf_examples/empty_1/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_1/expected
diff --git a/src/test/conf_examples/empty_1/expected_log b/src/test/conf_examples/empty_1/expected_log
new file mode 100644
index 0000000000..4c6b00069f
--- /dev/null
+++ b/src/test/conf_examples/empty_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*empty_1[./]*torrc
diff --git a/src/test/conf_examples/empty_1/torrc b/src/test/conf_examples/empty_1/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_1/torrc
diff --git a/src/test/conf_examples/empty_2/cmdline b/src/test/conf_examples/empty_2/cmdline
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_2/cmdline
diff --git a/src/test/conf_examples/empty_2/expected b/src/test/conf_examples/empty_2/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_2/expected
diff --git a/src/test/conf_examples/empty_2/expected_log b/src/test/conf_examples/empty_2/expected_log
new file mode 100644
index 0000000000..9c846a03f3
--- /dev/null
+++ b/src/test/conf_examples/empty_2/expected_log
@@ -0,0 +1 @@
+Read configuration file .*empty_2[./]*torrc\.defaults
diff --git a/src/test/conf_examples/empty_2/torrc b/src/test/conf_examples/empty_2/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_2/torrc
diff --git a/src/test/conf_examples/empty_2/torrc.defaults b/src/test/conf_examples/empty_2/torrc.defaults
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_2/torrc.defaults
diff --git a/src/test/conf_examples/empty_3/expected b/src/test/conf_examples/empty_3/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_3/expected
diff --git a/src/test/conf_examples/empty_3/expected_log b/src/test/conf_examples/empty_3/expected_log
new file mode 100644
index 0000000000..e3f2365893
--- /dev/null
+++ b/src/test/conf_examples/empty_3/expected_log
@@ -0,0 +1 @@
+Processing configuration path \".*included\" at recursion level 1\.
diff --git a/src/test/conf_examples/empty_3/included/empty b/src/test/conf_examples/empty_3/included/empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_3/included/empty
diff --git a/src/test/conf_examples/empty_3/torrc b/src/test/conf_examples/empty_3/torrc
new file mode 100644
index 0000000000..049b438903
--- /dev/null
+++ b/src/test/conf_examples/empty_3/torrc
@@ -0,0 +1 @@
+%include "included"
diff --git a/src/test/conf_examples/empty_4/error b/src/test/conf_examples/empty_4/error
new file mode 100644
index 0000000000..e6c2f7d885
--- /dev/null
+++ b/src/test/conf_examples/empty_4/error
@@ -0,0 +1 @@
+Unable to open configuration file \ No newline at end of file
diff --git a/src/test/conf_examples/example_1/expected_log b/src/test/conf_examples/example_1/expected_log
new file mode 100644
index 0000000000..8f83eec988
--- /dev/null
+++ b/src/test/conf_examples/example_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*example_1[./]*torrc
diff --git a/src/test/conf_examples/example_3/expected_log b/src/test/conf_examples/example_3/expected_log
new file mode 100644
index 0000000000..807f9c2fc8
--- /dev/null
+++ b/src/test/conf_examples/example_3/expected_log
@@ -0,0 +1 @@
+Read configuration file .*example_3[./]*torrc
diff --git a/src/test/conf_examples/include_1/error_no_dirauth_relay b/src/test/conf_examples/include_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/include_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/include_1/expected_log b/src/test/conf_examples/include_1/expected_log
new file mode 100644
index 0000000000..0791a494d2
--- /dev/null
+++ b/src/test/conf_examples/include_1/expected_log
@@ -0,0 +1 @@
+Processing configuration path \".*nested\.inc\" at recursion level 2\.
diff --git a/src/test/conf_examples/include_bug_31408/error_no_dirauth_relay b/src/test/conf_examples/include_bug_31408/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/include_bug_31408/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/include_bug_31408/expected_log b/src/test/conf_examples/include_bug_31408/expected_log
new file mode 100644
index 0000000000..e3f2365893
--- /dev/null
+++ b/src/test/conf_examples/include_bug_31408/expected_log
@@ -0,0 +1 @@
+Processing configuration path \".*included\" at recursion level 1\.
diff --git a/src/test/conf_examples/large_1/error_no_dirauth_relay b/src/test/conf_examples/large_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/large_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/large_1/expected b/src/test/conf_examples/large_1/expected
index 5866f5823e..99a12ffc84 100644
--- a/src/test/conf_examples/large_1/expected
+++ b/src/test/conf_examples/large_1/expected
@@ -15,7 +15,6 @@ CellStatistics 1
CircuitBuildTimeout 200
CircuitsAvailableTimeout 10
CircuitStreamTimeout 20
-ClientAutoIPv6ORPort 1
ClientOnly 1
ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
diff --git a/src/test/conf_examples/large_1/expected_log b/src/test/conf_examples/large_1/expected_log
new file mode 100644
index 0000000000..21248bb5e4
--- /dev/null
+++ b/src/test/conf_examples/large_1/expected_log
@@ -0,0 +1 @@
+Your log may contain sensitive information
diff --git a/src/test/conf_examples/large_1/expected_log_no_dirauth b/src/test/conf_examples/large_1/expected_log_no_dirauth
new file mode 100644
index 0000000000..0b74de4e40
--- /dev/null
+++ b/src/test/conf_examples/large_1/expected_log_no_dirauth
@@ -0,0 +1 @@
+This copy of Tor was built without support for the option "ConsensusParams". Skipping.
diff --git a/src/test/conf_examples/large_1/expected_no_dirauth b/src/test/conf_examples/large_1/expected_no_dirauth
new file mode 100644
index 0000000000..26a33bdc7c
--- /dev/null
+++ b/src/test/conf_examples/large_1/expected_no_dirauth
@@ -0,0 +1,157 @@
+AccountingMax 10737418240
+AccountingRule sum
+AccountingStart day 05:15
+Address 128.66.8.8
+AllowNonRFC953Hostnames 1
+AndroidIdentityTag droidy
+AutomapHostsOnResolve 1
+AutomapHostsSuffixes .onions
+AvoidDiskWrites 1
+BandwidthBurst 2147483647
+BandwidthRate 1610612736
+Bridge 128.66.1.10:80
+CacheDirectory /this-is-a-cache
+CellStatistics 1
+CircuitBuildTimeout 200
+CircuitsAvailableTimeout 10
+CircuitStreamTimeout 20
+ClientOnly 1
+ClientPreferIPv6DirPort 1
+ClientPreferIPv6ORPort 1
+ClientRejectInternalAddresses 0
+ClientUseIPv4 0
+ClientUseIPv6 1
+ConnDirectionStatistics 1
+ConnectionPadding 1
+ConnLimit 64
+ConstrainedSockets 1
+ConstrainedSockSize 10240
+ContactInfo long_config@example.com
+ControlPortFileGroupReadable 1
+ControlPort 9058
+CookieAuthentication 1
+CookieAuthFile /control/cookie
+CookieAuthFileGroupReadable 1
+CountPrivateBandwidth 1
+DataDirectory /data/dir
+DirAllowPrivateAddresses 1
+DirPolicy reject 128.66.1.1/32, accept *:*
+DirPortFrontPage /dirport/frontpage
+DirPort 99
+DirReqStatistics 0
+DisableDebuggerAttachment 0
+DisableNetwork 1
+DisableOOSCheck 0
+DNSPort 53535
+DormantCanceledByStartup 1
+DormantClientTimeout 1260
+DormantOnFirstStartup 1
+DormantTimeoutDisabledByIdleStreams 0
+DoSCircuitCreationBurst 1000
+DoSCircuitCreationDefenseTimePeriod 300
+DoSCircuitCreationDefenseType 2
+DoSCircuitCreationEnabled 1
+DoSCircuitCreationMinConnections 10
+DoSCircuitCreationRate 100
+DoSConnectionDefenseType 2
+DoSConnectionEnabled 1
+DoSConnectionMaxConcurrentCount 6
+DoSRefuseSingleHopClientRendezvous 0
+DownloadExtraInfo 1
+EnforceDistinctSubnets 0
+EntryNodes potrzebie,triffid,cromulent
+EntryStatistics 1
+ExcludeExitNodes blaznort,kriffid,zeppelin
+ExcludeNodes 128.66.7.6
+ExitNodes 128.66.7.7,128.66.128.0/17,exitexit
+ExitPolicy accept *:80,reject *:*
+ExitPolicyRejectLocalInterfaces 1
+ExitPolicyRejectPrivate 0
+ExitPortStatistics 1
+ExitRelay 1
+ExtendAllowPrivateAddresses 1
+ExtendByEd25519ID 1
+ExtORPortCookieAuthFile /foobar
+ExtORPort 99
+FascistFirewall 1
+FetchDirInfoEarly 1
+FetchDirInfoExtraEarly 1
+FetchUselessDescriptors 1
+FirewallPorts 80,443,999
+GeoIPExcludeUnknown 1
+GeoIPFile /geoip
+GuardfractionFile /gff
+GuardLifetime 691200
+HeartbeatPeriod 2700
+IPv6Exit 1
+KeepalivePeriod 540
+KeyDirectory /keyz
+KISTSchedRunInterval 1
+Log notice file /logfile
+Log info file /logfile-verbose
+LogTimeGranularity 60000
+LongLivedPorts 9090
+MainloopStats 1
+MapAddress www.example.com:10.0.0.6
+MaxAdvertisedBandwidth 100
+MaxCircuitDirtiness 3600
+MaxClientCircuitsPending 127
+MaxConsensusAgeForDiffs 2629728
+MaxMemInQueues 314572800
+MaxOnionQueueDelay 60000
+MaxUnparseableDescSizeToLog 1048576
+MiddleNodes grommit,truffle,parcheesi
+MyFamily $ffffffffffffffffffffffffffffffffffffffff
+NewCircuitPeriod 7200
+Nickname nickname
+NodeFamily $ffffffffffffffffffffffffffffffffffffffff,$dddddddddddddddddddddddddddddddddddddddd
+NumCPUs 3
+NumDirectoryGuards 4
+NumEntryGuards 5
+NumPrimaryGuards 8
+OfflineMasterKey 1
+OptimisticData 1
+ORPort 2222
+OutboundBindAddress 10.0.0.7
+OutboundBindAddressExit 10.0.0.8
+OutboundBindAddressOR 10.0.0.9
+PerConnBWBurst 10485760
+PerConnBWRate 102400
+PidFile /piddy
+ProtocolWarnings 1
+PublishHidServDescriptors 0
+PublishServerDescriptor 0
+ReachableAddresses 0.0.0.0, *:*
+ReachableDirAddresses 128.0.0.0/1
+ReachableORAddresses 128.0.0.0/8
+RejectPlaintextPorts 23
+RelayBandwidthBurst 10000
+RelayBandwidthRate 1000
+RendPostPeriod 600
+RephistTrackTime 600
+SafeLogging 0
+Schedulers Vanilla,KISTLite,Kist
+ShutdownWaitLength 10
+SigningKeyLifetime 4838400
+Socks5Proxy 128.66.99.99:99
+Socks5ProxyPassword flynn
+Socks5ProxyUsername spaceparanoids
+SocksPolicy accept 127.0.0.0/24, reject *:*
+SocksPort 9099
+SocksTimeout 600
+SSLKeyLifetime 86400
+StrictNodes 1
+SyslogIdentityTag tortor
+TestSocks 1
+TokenBucketRefillInterval 1000
+TrackHostExits www.example.com
+TrackHostExitsExpire 3600
+TruncateLogFile 1
+UnixSocksGroupWritable 1
+UpdateBridgesFromAuthority 1
+UseDefaultFallbackDirs 0
+UseGuardFraction 1
+UseMicrodescriptors 0
+VirtualAddrNetworkIPv4 18.66.0.0/16
+VirtualAddrNetworkIPv6 [ff00::]/16
+WarnPlaintextPorts 7,11,23,1001
diff --git a/src/test/conf_examples/large_1/torrc b/src/test/conf_examples/large_1/torrc
index e99acd9fb7..20ddf00e16 100644
--- a/src/test/conf_examples/large_1/torrc
+++ b/src/test/conf_examples/large_1/torrc
@@ -16,7 +16,6 @@ CircuitBuildTimeout 200
CircuitPadding 1
CircuitsAvailableTimeout 10
CircuitStreamTimeout 20
-ClientAutoIPv6ORPort 1
ClientOnly 1
ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
diff --git a/src/test/conf_examples/lzma_zstd_1/expected b/src/test/conf_examples/lzma_zstd_1/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log b/src/test/conf_examples/lzma_zstd_1/expected_log
new file mode 100644
index 0000000000..a5531ca21e
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, and Libzstd N/A
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma
new file mode 100644
index 0000000000..2947e5991b
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, and Libzstd N/A
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd
new file mode 100644
index 0000000000..e76e4357f8
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, and Libzstd .* \ No newline at end of file
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_zstd b/src/test/conf_examples/lzma_zstd_1/expected_log_zstd
new file mode 100644
index 0000000000..c8b174423b
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_zstd
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, and Libzstd .* \ No newline at end of file
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_lzma b/src/test/conf_examples/lzma_zstd_1/expected_lzma
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_lzma
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_lzma_zstd b/src/test/conf_examples/lzma_zstd_1/expected_lzma_zstd
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_lzma_zstd
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_zstd b/src/test/conf_examples/lzma_zstd_1/expected_zstd
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_zstd
diff --git a/src/test/conf_examples/lzma_zstd_1/torrc b/src/test/conf_examples/lzma_zstd_1/torrc
new file mode 100644
index 0000000000..f873d79028
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/torrc
@@ -0,0 +1 @@
+# This test checks for the optional library list in tor's logs
diff --git a/src/test/conf_examples/missing_cl_arg/cmdline b/src/test/conf_examples/missing_cl_arg/cmdline
new file mode 100644
index 0000000000..7fc4d0a54d
--- /dev/null
+++ b/src/test/conf_examples/missing_cl_arg/cmdline
@@ -0,0 +1 @@
+--hash-password
diff --git a/src/test/conf_examples/missing_cl_arg/error b/src/test/conf_examples/missing_cl_arg/error
new file mode 100644
index 0000000000..61dbeac8aa
--- /dev/null
+++ b/src/test/conf_examples/missing_cl_arg/error
@@ -0,0 +1 @@
+Command-line option '--hash-password' with no value.
diff --git a/src/test/conf_examples/missing_cl_arg/torrc b/src/test/conf_examples/missing_cl_arg/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/missing_cl_arg/torrc
diff --git a/src/test/conf_examples/nss_1/expected b/src/test/conf_examples/nss_1/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/nss_1/expected
diff --git a/src/test/conf_examples/nss_1/expected_log b/src/test/conf_examples/nss_1/expected_log
new file mode 100644
index 0000000000..32e8cfc2f8
--- /dev/null
+++ b/src/test/conf_examples/nss_1/expected_log
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, OpenSSL .*, Zlib .*, Liblzma .*, and Libzstd .*
diff --git a/src/test/conf_examples/nss_1/expected_log_nss b/src/test/conf_examples/nss_1/expected_log_nss
new file mode 100644
index 0000000000..c0fe7b003c
--- /dev/null
+++ b/src/test/conf_examples/nss_1/expected_log_nss
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .*
diff --git a/src/test/conf_examples/nss_1/expected_nss b/src/test/conf_examples/nss_1/expected_nss
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/nss_1/expected_nss
diff --git a/src/test/conf_examples/nss_1/torrc b/src/test/conf_examples/nss_1/torrc
new file mode 100644
index 0000000000..f873d79028
--- /dev/null
+++ b/src/test/conf_examples/nss_1/torrc
@@ -0,0 +1 @@
+# This test checks for the optional library list in tor's logs
diff --git a/src/test/conf_examples/obsolete_1/expected_log b/src/test/conf_examples/obsolete_1/expected_log
new file mode 100644
index 0000000000..52f6f70a2e
--- /dev/null
+++ b/src/test/conf_examples/obsolete_1/expected_log
@@ -0,0 +1 @@
+Skipping obsolete configuration option
diff --git a/src/test/conf_examples/obsolete_1/torrc b/src/test/conf_examples/obsolete_1/torrc
index 3cd9a6d777..e711fe4065 100644
--- a/src/test/conf_examples/obsolete_1/torrc
+++ b/src/test/conf_examples/obsolete_1/torrc
@@ -1,68 +1,70 @@
# These options are obsolete as of 0.4.2
-AllowDotExit
-AllowInvalidNodes
-AllowSingleHopCircuits
-AllowSingleHopExits
-AlternateHSAuthority
-AuthDirBadDir
-AuthDirBadDirCCs
-AuthDirRejectUnlisted
-AuthDirListBadDirs
-AuthDirMaxServersPerAuthAddr
-CircuitIdleTimeout
-ControlListenAddress
-DirListenAddress
-DisableIOCP
-DisableV2DirectoryInfo_
-DynamicDHGroups
-DNSListenAddress
-TestingEnableTbEmptyEvent
-ExcludeSingleHopRelays
-FallbackNetworkstatusFile
-FastFirstHopPK
-FetchV2Networkstatus
-Group
-HidServDirectoryV2
-CloseHSClientCircuitsImmediatelyOnTimeout
-CloseHSServiceRendCircuitsImmediatelyOnTimeout
-MaxOnionsPending
-NamingAuthoritativeDirectory
-NATDListenAddress
-PredictedPortsRelevanceTime
-WarnUnsafeSocks
-ORListenAddress
-PathBiasDisableRate
-PathBiasScaleFactor
-PathBiasMultFactor
-PathBiasUseCloseCounts
-PortForwarding
-PortForwardingHelper
-PreferTunneledDirConns
-RecommendedPackages
-RunTesting
-SchedulerLowWaterMark__
-SchedulerHighWaterMark__
-SchedulerMaxFlushCells__
-SocksListenAddress
-StrictEntryNodes
-StrictExitNodes
-Support022HiddenServices
-Tor2webMode
-Tor2webRendezvousPoints
-TLSECGroup
-TransListenAddress
-TunnelDirConns
-UseEntryGuardsAsDirGuards
-UseNTorHandshake
-UserspaceIOCPBuffers
-V1AuthoritativeDirectory
-V2AuthoritativeDirectory
-VoteOnHidServDirectoriesV2
-UseFilteringSSLBufferevents
-__UseFilteringSSLBufferevents
-TestingConsensusMaxDownloadTries
-ClientBootstrapConsensusMaxDownloadTries
-ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries
-TestingDescriptorMaxDownloadTries
-TestingMicrodescMaxDownloadTries
-TestingCertMaxDownloadTries
+# Obsolete options without arguments, or with an empty argument,
+# are silently ignored. So we give each one of these options an argument.
+AllowDotExit 1
+AllowInvalidNodes 1
+AllowSingleHopCircuits 1
+AllowSingleHopExits 1
+AlternateHSAuthority 1
+AuthDirBadDir 1
+AuthDirBadDirCCs 1
+AuthDirRejectUnlisted 1
+AuthDirListBadDirs 1
+AuthDirMaxServersPerAuthAddr 1
+CircuitIdleTimeout 1
+ControlListenAddress 1
+DirListenAddress 1
+DisableIOCP 1
+DisableV2DirectoryInfo_ 1
+DynamicDHGroups 1
+DNSListenAddress 1
+TestingEnableTbEmptyEvent 1
+ExcludeSingleHopRelays 1
+FallbackNetworkstatusFile 1
+FastFirstHopPK 1
+FetchV2Networkstatus 1
+Group 1
+HidServDirectoryV2 1
+CloseHSClientCircuitsImmediatelyOnTimeout 1
+CloseHSServiceRendCircuitsImmediatelyOnTimeout 1
+MaxOnionsPending 1
+NamingAuthoritativeDirectory 1
+NATDListenAddress 1
+PredictedPortsRelevanceTime 1
+WarnUnsafeSocks 1
+ORListenAddress 1
+PathBiasDisableRate 1
+PathBiasScaleFactor 1
+PathBiasMultFactor 1
+PathBiasUseCloseCounts 1
+PortForwarding 1
+PortForwardingHelper 1
+PreferTunneledDirConns 1
+RecommendedPackages 1
+RunTesting 1
+SchedulerLowWaterMark__ 1
+SchedulerHighWaterMark__ 1
+SchedulerMaxFlushCells__ 1
+SocksListenAddress 1
+StrictEntryNodes 1
+StrictExitNodes 1
+Support022HiddenServices 1
+Tor2webMode 1
+Tor2webRendezvousPoints 1
+TLSECGroup 1
+TransListenAddress 1
+TunnelDirConns 1
+UseEntryGuardsAsDirGuards 1
+UseNTorHandshake 1
+UserspaceIOCPBuffers 1
+V1AuthoritativeDirectory 1
+V2AuthoritativeDirectory 1
+VoteOnHidServDirectoriesV2 1
+UseFilteringSSLBufferevents 1
+__UseFilteringSSLBufferevents 1
+TestingConsensusMaxDownloadTries 1
+ClientBootstrapConsensusMaxDownloadTries 1
+ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries 1
+TestingDescriptorMaxDownloadTries 1
+TestingMicrodescMaxDownloadTries 1
+TestingCertMaxDownloadTries 1
diff --git a/src/test/conf_examples/obsolete_2/expected_log b/src/test/conf_examples/obsolete_2/expected_log
new file mode 100644
index 0000000000..2160355ee9
--- /dev/null
+++ b/src/test/conf_examples/obsolete_2/expected_log
@@ -0,0 +1 @@
+Read configuration file .*obsolete_2[./]*torrc
diff --git a/src/test/conf_examples/obsolete_2/torrc b/src/test/conf_examples/obsolete_2/torrc
index 4f78d47625..b83e7a7369 100644
--- a/src/test/conf_examples/obsolete_2/torrc
+++ b/src/test/conf_examples/obsolete_2/torrc
@@ -1,2 +1,5 @@
# This option has been obsolete for some time
+# Obsolete options without arguments, or with an empty argument,
+# are silently ignored.
AllowDotExit
+AllowInvalidNodes ""
diff --git a/src/test/conf_examples/obsolete_3/expected b/src/test/conf_examples/obsolete_3/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/obsolete_3/expected
diff --git a/src/test/conf_examples/obsolete_3/expected_log b/src/test/conf_examples/obsolete_3/expected_log
new file mode 100644
index 0000000000..82d76ec818
--- /dev/null
+++ b/src/test/conf_examples/obsolete_3/expected_log
@@ -0,0 +1 @@
+Skipping obsolete configuration option "AllowDotExit"
diff --git a/src/test/conf_examples/obsolete_3/torrc b/src/test/conf_examples/obsolete_3/torrc
new file mode 100644
index 0000000000..e0efe752bf
--- /dev/null
+++ b/src/test/conf_examples/obsolete_3/torrc
@@ -0,0 +1,4 @@
+# This option has been obsolete for some time
+# Obsolete options without arguments, or with an empty argument,
+# are silently ignored. So we give this option an argument.
+AllowDotExit 1
diff --git a/src/test/conf_examples/ops_1/error_no_dirauth_relay b/src/test/conf_examples/ops_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/ops_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/ops_1/expected_log b/src/test/conf_examples/ops_1/expected_log
new file mode 100644
index 0000000000..b785d7fb52
--- /dev/null
+++ b/src/test/conf_examples/ops_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_1[./]*torrc
diff --git a/src/test/conf_examples/ops_2/expected_log b/src/test/conf_examples/ops_2/expected_log
new file mode 100644
index 0000000000..17fbc3ffbf
--- /dev/null
+++ b/src/test/conf_examples/ops_2/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_2[./]*torrc
diff --git a/src/test/conf_examples/ops_3/error_no_dirauth_relay b/src/test/conf_examples/ops_3/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/ops_3/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/ops_3/expected_log b/src/test/conf_examples/ops_3/expected_log
new file mode 100644
index 0000000000..151498f0df
--- /dev/null
+++ b/src/test/conf_examples/ops_3/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_3[./]*torrc
diff --git a/src/test/conf_examples/ops_4/error_no_dirauth_relay b/src/test/conf_examples/ops_4/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/ops_4/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/ops_4/expected_log b/src/test/conf_examples/ops_4/expected_log
new file mode 100644
index 0000000000..7632b2290c
--- /dev/null
+++ b/src/test/conf_examples/ops_4/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_4[./]*torrc\.defaults
diff --git a/src/test/conf_examples/ops_5/error_no_dirauth_relay b/src/test/conf_examples/ops_5/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/ops_5/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/ops_5/expected_log b/src/test/conf_examples/ops_5/expected_log
new file mode 100644
index 0000000000..ec63cb0638
--- /dev/null
+++ b/src/test/conf_examples/ops_5/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_5[./]*torrc\.defaults
diff --git a/src/test/conf_examples/ops_6/expected_log b/src/test/conf_examples/ops_6/expected_log
new file mode 100644
index 0000000000..f9b1ca0412
--- /dev/null
+++ b/src/test/conf_examples/ops_6/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_6[./]*torrc\.defaults
diff --git a/src/test/conf_examples/pt_01/expected b/src/test/conf_examples/pt_01/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/pt_01/expected
diff --git a/src/test/conf_examples/pt_01/expected_log b/src/test/conf_examples/pt_01/expected_log
new file mode 100644
index 0000000000..65bfa7a7b7
--- /dev/null
+++ b/src/test/conf_examples/pt_01/expected_log
@@ -0,0 +1 @@
+Linelist option 'ExtORPort' has no value\. Skipping
diff --git a/src/test/conf_examples/pt_01/torrc b/src/test/conf_examples/pt_01/torrc
new file mode 100644
index 0000000000..574bb32a0d
--- /dev/null
+++ b/src/test/conf_examples/pt_01/torrc
@@ -0,0 +1,7 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Empty linelist values are ignored with a warning
+ExtORPort
+ServerTransportPlugin
+ServerTransportListenAddr
+ServerTransportOptions
diff --git a/src/test/conf_examples/pt_02/error b/src/test/conf_examples/pt_02/error
new file mode 100644
index 0000000000..ce28eab729
--- /dev/null
+++ b/src/test/conf_examples/pt_02/error
@@ -0,0 +1 @@
+Invalid ExtORPort configuration
diff --git a/src/test/conf_examples/pt_02/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_02/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..0e48dca7fd
--- /dev/null
+++ b/src/test/conf_examples/pt_02/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_02[./]*torrc
diff --git a/src/test/conf_examples/pt_02/expected_no_dirauth_relay b/src/test/conf_examples/pt_02/expected_no_dirauth_relay
new file mode 100644
index 0000000000..f5cd26e6b7
--- /dev/null
+++ b/src/test/conf_examples/pt_02/expected_no_dirauth_relay
@@ -0,0 +1,8 @@
+ExtORPort illegal_hostname_chars$()^*%(%
+ServerTransportListenAddr bad
+ServerTransportListenAddr bad2 illegal_hostname_chars$()^*%(%
+ServerTransportOptions bad
+ServerTransportOptions bad2 not_kv
+ServerTransportPlugin bad
+ServerTransportPlugin bad2 exec
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_02/torrc b/src/test/conf_examples/pt_02/torrc
new file mode 100644
index 0000000000..825f2c4be4
--- /dev/null
+++ b/src/test/conf_examples/pt_02/torrc
@@ -0,0 +1,13 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Bad options are also ignored
+# (Unless the relay module is disabled, because they are relay-only
+# options. We'll ignore all relay-only options in #32395.)
+ExtORPort illegal_hostname_chars$()^*%(%#%)#(%*
+ServerTransportPlugin bad
+ServerTransportPlugin bad2 exec
+ServerTransportPlugin bad3 exec /
+ServerTransportListenAddr bad
+ServerTransportListenAddr bad2 illegal_hostname_chars$()^*%(%#%)#(%*
+ServerTransportOptions bad
+ServerTransportOptions bad2 not_kv
diff --git a/src/test/conf_examples/pt_03/expected b/src/test/conf_examples/pt_03/expected
new file mode 100644
index 0000000000..f849f2a78f
--- /dev/null
+++ b/src/test/conf_examples/pt_03/expected
@@ -0,0 +1 @@
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_03/expected_log b/src/test/conf_examples/pt_03/expected_log
new file mode 100644
index 0000000000..285a189c28
--- /dev/null
+++ b/src/test/conf_examples/pt_03/expected_log
@@ -0,0 +1 @@
+We use pluggable transports but the Extended ORPort is disabled
diff --git a/src/test/conf_examples/pt_03/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_03/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..88f4e5bdfb
--- /dev/null
+++ b/src/test/conf_examples/pt_03/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_03[./]*torrc
diff --git a/src/test/conf_examples/pt_03/expected_no_dirauth_relay b/src/test/conf_examples/pt_03/expected_no_dirauth_relay
new file mode 100644
index 0000000000..f849f2a78f
--- /dev/null
+++ b/src/test/conf_examples/pt_03/expected_no_dirauth_relay
@@ -0,0 +1 @@
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_03/torrc b/src/test/conf_examples/pt_03/torrc
new file mode 100644
index 0000000000..9868c39b26
--- /dev/null
+++ b/src/test/conf_examples/pt_03/torrc
@@ -0,0 +1,4 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Plugin, but no ExtORPort
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_04/expected b/src/test/conf_examples/pt_04/expected
new file mode 100644
index 0000000000..9087f600e0
--- /dev/null
+++ b/src/test/conf_examples/pt_04/expected
@@ -0,0 +1,3 @@
+ExtORPortCookieAuthFile /
+ExtORPort 1
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_04/expected_log b/src/test/conf_examples/pt_04/expected_log
new file mode 100644
index 0000000000..5b3ab51d25
--- /dev/null
+++ b/src/test/conf_examples/pt_04/expected_log
@@ -0,0 +1 @@
+Tor is not configured as a relay but you specified a ServerTransportPlugin line.*The ServerTransportPlugin line will be ignored
diff --git a/src/test/conf_examples/pt_04/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_04/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..2b989bf320
--- /dev/null
+++ b/src/test/conf_examples/pt_04/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_04[./]*torrc
diff --git a/src/test/conf_examples/pt_04/expected_no_dirauth_relay b/src/test/conf_examples/pt_04/expected_no_dirauth_relay
new file mode 100644
index 0000000000..9087f600e0
--- /dev/null
+++ b/src/test/conf_examples/pt_04/expected_no_dirauth_relay
@@ -0,0 +1,3 @@
+ExtORPortCookieAuthFile /
+ExtORPort 1
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_04/torrc b/src/test/conf_examples/pt_04/torrc
new file mode 100644
index 0000000000..18bb28f9cf
--- /dev/null
+++ b/src/test/conf_examples/pt_04/torrc
@@ -0,0 +1,6 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a bad cookie auth file
+ExtORPort 1
+ExtORPortCookieAuthFile /
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_05/error_no_dirauth_relay b/src/test/conf_examples/pt_05/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/pt_05/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/pt_05/expected b/src/test/conf_examples/pt_05/expected
new file mode 100644
index 0000000000..61568bb9ac
--- /dev/null
+++ b/src/test/conf_examples/pt_05/expected
@@ -0,0 +1,4 @@
+ExtORPort 1
+Nickname Unnamed
+ORPort 2
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_05/expected_log b/src/test/conf_examples/pt_05/expected_log
new file mode 100644
index 0000000000..c05a0931d6
--- /dev/null
+++ b/src/test/conf_examples/pt_05/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set
diff --git a/src/test/conf_examples/pt_05/torrc b/src/test/conf_examples/pt_05/torrc
new file mode 100644
index 0000000000..55c569bb1b
--- /dev/null
+++ b/src/test/conf_examples/pt_05/torrc
@@ -0,0 +1,6 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a valid minimal config
+ORPort 2
+ExtORPort 1
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_06/expected b/src/test/conf_examples/pt_06/expected
new file mode 100644
index 0000000000..d5788b92c9
--- /dev/null
+++ b/src/test/conf_examples/pt_06/expected
@@ -0,0 +1,6 @@
+ExtORPortCookieAuthFile /
+ExtORPortCookieAuthFileGroupReadable 1
+ExtORPort 1
+ServerTransportListenAddr bad3 127.0.0.1:2
+ServerTransportOptions bad3 a=b
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_06/expected_log b/src/test/conf_examples/pt_06/expected_log
new file mode 100644
index 0000000000..5b3ab51d25
--- /dev/null
+++ b/src/test/conf_examples/pt_06/expected_log
@@ -0,0 +1 @@
+Tor is not configured as a relay but you specified a ServerTransportPlugin line.*The ServerTransportPlugin line will be ignored
diff --git a/src/test/conf_examples/pt_06/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_06/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..f35a380c9f
--- /dev/null
+++ b/src/test/conf_examples/pt_06/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_06[./]*torrc
diff --git a/src/test/conf_examples/pt_06/expected_no_dirauth_relay b/src/test/conf_examples/pt_06/expected_no_dirauth_relay
new file mode 100644
index 0000000000..d5788b92c9
--- /dev/null
+++ b/src/test/conf_examples/pt_06/expected_no_dirauth_relay
@@ -0,0 +1,6 @@
+ExtORPortCookieAuthFile /
+ExtORPortCookieAuthFileGroupReadable 1
+ExtORPort 1
+ServerTransportListenAddr bad3 127.0.0.1:2
+ServerTransportOptions bad3 a=b
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_06/torrc b/src/test/conf_examples/pt_06/torrc
new file mode 100644
index 0000000000..20cfc329a7
--- /dev/null
+++ b/src/test/conf_examples/pt_06/torrc
@@ -0,0 +1,9 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a config with all the options
+ExtORPort 1
+ExtORPortCookieAuthFile /
+ExtORPortCookieAuthFileGroupReadable 1
+ServerTransportPlugin bad3 exec /
+ServerTransportListenAddr bad3 127.0.0.1:2
+ServerTransportOptions bad3 a=b
diff --git a/src/test/conf_examples/pt_07/error_no_dirauth_relay b/src/test/conf_examples/pt_07/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/pt_07/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/pt_07/expected b/src/test/conf_examples/pt_07/expected
new file mode 100644
index 0000000000..c3a75dc407
--- /dev/null
+++ b/src/test/conf_examples/pt_07/expected
@@ -0,0 +1,4 @@
+ExtORPort 2.2.2.2:1
+Nickname Unnamed
+ORPort 2
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_07/expected_log b/src/test/conf_examples/pt_07/expected_log
new file mode 100644
index 0000000000..5afaf02ba9
--- /dev/null
+++ b/src/test/conf_examples/pt_07/expected_log
@@ -0,0 +1 @@
+You specified a public address .* for ExtORPort
diff --git a/src/test/conf_examples/pt_07/torrc b/src/test/conf_examples/pt_07/torrc
new file mode 100644
index 0000000000..40eaf50e64
--- /dev/null
+++ b/src/test/conf_examples/pt_07/torrc
@@ -0,0 +1,6 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a valid config with a risky ExtORPort address
+ORPort 2
+ExtORPort 2.2.2.2:1
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_08/error b/src/test/conf_examples/pt_08/error
new file mode 100644
index 0000000000..7931bbb4b9
--- /dev/null
+++ b/src/test/conf_examples/pt_08/error
@@ -0,0 +1 @@
+ExtORPort does not support unix sockets \ No newline at end of file
diff --git a/src/test/conf_examples/pt_08/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_08/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..79dcbc10ca
--- /dev/null
+++ b/src/test/conf_examples/pt_08/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_08[./]*torrc
diff --git a/src/test/conf_examples/pt_08/expected_no_dirauth_relay b/src/test/conf_examples/pt_08/expected_no_dirauth_relay
new file mode 100644
index 0000000000..9a1a9bd1e4
--- /dev/null
+++ b/src/test/conf_examples/pt_08/expected_no_dirauth_relay
@@ -0,0 +1,2 @@
+ExtORPort unix:/
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_08/torrc b/src/test/conf_examples/pt_08/torrc
new file mode 100644
index 0000000000..6f1d79d706
--- /dev/null
+++ b/src/test/conf_examples/pt_08/torrc
@@ -0,0 +1,7 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try an invalid config with a unix socket for ExtORPort
+# (Unless the relay module is disabled, because they are relay-only
+# options. We'll ignore all relay-only options in #32395.)
+ExtORPort unix:/
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_09/error b/src/test/conf_examples/pt_09/error
new file mode 100644
index 0000000000..882b50a7bc
--- /dev/null
+++ b/src/test/conf_examples/pt_09/error
@@ -0,0 +1 @@
+Error parsing ServerTransportListenAddr address \ No newline at end of file
diff --git a/src/test/conf_examples/pt_09/error_no_dirauth_relay b/src/test/conf_examples/pt_09/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/pt_09/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/pt_09/torrc b/src/test/conf_examples/pt_09/torrc
new file mode 100644
index 0000000000..50a8e95b95
--- /dev/null
+++ b/src/test/conf_examples/pt_09/torrc
@@ -0,0 +1,7 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a valid minimal config, with a bad ServerTransportListenAddr
+ORPort 2
+ExtORPort 1
+ServerTransportPlugin bad3 exec /
+ServerTransportListenAddr bad3 [aaaa::bbbb:ccccc]
diff --git a/src/test/conf_examples/relay_01/expected b/src/test/conf_examples/relay_01/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/relay_01/expected
diff --git a/src/test/conf_examples/relay_01/expected_log b/src/test/conf_examples/relay_01/expected_log
new file mode 100644
index 0000000000..32e8c99d27
--- /dev/null
+++ b/src/test/conf_examples/relay_01/expected_log
@@ -0,0 +1 @@
+Linelist option 'ORPort' has no value\. Skipping
diff --git a/src/test/conf_examples/relay_01/torrc b/src/test/conf_examples/relay_01/torrc
new file mode 100644
index 0000000000..da3e85b427
--- /dev/null
+++ b/src/test/conf_examples/relay_01/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Empty linelist values are ignored with a warning
+ORPort
+DirPort
diff --git a/src/test/conf_examples/relay_02/error b/src/test/conf_examples/relay_02/error
new file mode 100644
index 0000000000..dd87d9f7e2
--- /dev/null
+++ b/src/test/conf_examples/relay_02/error
@@ -0,0 +1 @@
+Unrecognized value bad
diff --git a/src/test/conf_examples/relay_02/error_no_dirauth_relay b/src/test/conf_examples/relay_02/error_no_dirauth_relay
new file mode 100644
index 0000000000..dd87d9f7e2
--- /dev/null
+++ b/src/test/conf_examples/relay_02/error_no_dirauth_relay
@@ -0,0 +1 @@
+Unrecognized value bad
diff --git a/src/test/conf_examples/relay_02/torrc b/src/test/conf_examples/relay_02/torrc
new file mode 100644
index 0000000000..3eaa4403a9
--- /dev/null
+++ b/src/test/conf_examples/relay_02/torrc
@@ -0,0 +1,7 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Bad options are also ignored
+ORPort illegal_hostname_chars$()^*%(%#%)#(%*
+DirPort illegal_hostname_chars$()^*%(%#%)#(%*
+DirCache bad
+BridgeRelay bad
diff --git a/src/test/conf_examples/relay_03/error_no_dirauth_relay b/src/test/conf_examples/relay_03/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_03/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_03/expected b/src/test/conf_examples/relay_03/expected
new file mode 100644
index 0000000000..15056a8d1f
--- /dev/null
+++ b/src/test/conf_examples/relay_03/expected
@@ -0,0 +1,2 @@
+DirPort 1
+ORPort 0
diff --git a/src/test/conf_examples/relay_03/expected_log b/src/test/conf_examples/relay_03/expected_log
new file mode 100644
index 0000000000..46ab723e4a
--- /dev/null
+++ b/src/test/conf_examples/relay_03/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_03[./]*torrc
diff --git a/src/test/conf_examples/relay_03/torrc b/src/test/conf_examples/relay_03/torrc
new file mode 100644
index 0000000000..fd7da7bb95
--- /dev/null
+++ b/src/test/conf_examples/relay_03/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# DirPort, but no ORPort
+ORPort 0
+DirPort 1
diff --git a/src/test/conf_examples/relay_04/error_no_dirauth_relay b/src/test/conf_examples/relay_04/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_04/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_04/expected b/src/test/conf_examples/relay_04/expected
new file mode 100644
index 0000000000..1d25374ed1
--- /dev/null
+++ b/src/test/conf_examples/relay_04/expected
@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_04/expected_log b/src/test/conf_examples/relay_04/expected_log
new file mode 100644
index 0000000000..c05a0931d6
--- /dev/null
+++ b/src/test/conf_examples/relay_04/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set
diff --git a/src/test/conf_examples/relay_04/torrc b/src/test/conf_examples/relay_04/torrc
new file mode 100644
index 0000000000..ff08b2376b
--- /dev/null
+++ b/src/test/conf_examples/relay_04/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid minimal config
+ORPort 1
diff --git a/src/test/conf_examples/relay_05/error_no_dirauth_relay b/src/test/conf_examples/relay_05/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_05/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_05/expected b/src/test/conf_examples/relay_05/expected
new file mode 100644
index 0000000000..ae58cee1af
--- /dev/null
+++ b/src/test/conf_examples/relay_05/expected
@@ -0,0 +1,3 @@
+DirPort 2
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_05/expected_log b/src/test/conf_examples/relay_05/expected_log
new file mode 100644
index 0000000000..483c2e2aae
--- /dev/null
+++ b/src/test/conf_examples/relay_05/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_05[./]*torrc
diff --git a/src/test/conf_examples/relay_05/torrc b/src/test/conf_examples/relay_05/torrc
new file mode 100644
index 0000000000..faeaad32a0
--- /dev/null
+++ b/src/test/conf_examples/relay_05/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid minimal directory mirror config
+ORPort 1
+DirPort 2
diff --git a/src/test/conf_examples/relay_06/error_no_dirauth_relay b/src/test/conf_examples/relay_06/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_06/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_06/expected b/src/test/conf_examples/relay_06/expected
new file mode 100644
index 0000000000..904c7339e0
--- /dev/null
+++ b/src/test/conf_examples/relay_06/expected
@@ -0,0 +1,3 @@
+BridgeRelay 1
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_06/expected_log b/src/test/conf_examples/relay_06/expected_log
new file mode 100644
index 0000000000..70eb18df19
--- /dev/null
+++ b/src/test/conf_examples/relay_06/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_06[./]*torrc
diff --git a/src/test/conf_examples/relay_06/torrc b/src/test/conf_examples/relay_06/torrc
new file mode 100644
index 0000000000..baeae8df5d
--- /dev/null
+++ b/src/test/conf_examples/relay_06/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid minimal bridge config
+ORPort 1
+BridgeRelay 1
diff --git a/src/test/conf_examples/relay_07/error_no_dirauth_relay b/src/test/conf_examples/relay_07/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_07/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_07/expected b/src/test/conf_examples/relay_07/expected
new file mode 100644
index 0000000000..79fa3e5a47
--- /dev/null
+++ b/src/test/conf_examples/relay_07/expected
@@ -0,0 +1,3 @@
+DirCache 0
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_07/expected_log b/src/test/conf_examples/relay_07/expected_log
new file mode 100644
index 0000000000..14729a7ab1
--- /dev/null
+++ b/src/test/conf_examples/relay_07/expected_log
@@ -0,0 +1 @@
+DirCache is disabled and we are configured as a relay
diff --git a/src/test/conf_examples/relay_07/torrc b/src/test/conf_examples/relay_07/torrc
new file mode 100644
index 0000000000..01ac138597
--- /dev/null
+++ b/src/test/conf_examples/relay_07/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid minimal non-directory cache config
+ORPort 1
+DirCache 0
diff --git a/src/test/conf_examples/relay_08/error_no_dirauth_relay b/src/test/conf_examples/relay_08/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_08/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_08/expected b/src/test/conf_examples/relay_08/expected
new file mode 100644
index 0000000000..904c7339e0
--- /dev/null
+++ b/src/test/conf_examples/relay_08/expected
@@ -0,0 +1,3 @@
+BridgeRelay 1
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_08/expected_log b/src/test/conf_examples/relay_08/expected_log
new file mode 100644
index 0000000000..b0168c803d
--- /dev/null
+++ b/src/test/conf_examples/relay_08/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_08[./]*torrc
diff --git a/src/test/conf_examples/relay_08/torrc b/src/test/conf_examples/relay_08/torrc
new file mode 100644
index 0000000000..9e2ff9465c
--- /dev/null
+++ b/src/test/conf_examples/relay_08/torrc
@@ -0,0 +1,6 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid config with all the bridge options
+ORPort 1
+BridgeRelay 1
+DirCache 1
diff --git a/src/test/conf_examples/relay_09/error_no_dirauth_relay b/src/test/conf_examples/relay_09/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_09/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_09/expected b/src/test/conf_examples/relay_09/expected
new file mode 100644
index 0000000000..ae58cee1af
--- /dev/null
+++ b/src/test/conf_examples/relay_09/expected
@@ -0,0 +1,3 @@
+DirPort 2
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_09/expected_log b/src/test/conf_examples/relay_09/expected_log
new file mode 100644
index 0000000000..d3ab4f6593
--- /dev/null
+++ b/src/test/conf_examples/relay_09/expected_log
@@ -0,0 +1 @@
+By default, Tor does not run as an exit relay
diff --git a/src/test/conf_examples/relay_09/torrc b/src/test/conf_examples/relay_09/torrc
new file mode 100644
index 0000000000..014eeca34b
--- /dev/null
+++ b/src/test/conf_examples/relay_09/torrc
@@ -0,0 +1,6 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid config with all the non-bridge options
+ORPort 1
+DirPort 2
+DirCache 1
diff --git a/src/test/conf_examples/relay_10/error_no_dirauth_relay b/src/test/conf_examples/relay_10/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_10/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_10/expected b/src/test/conf_examples/relay_10/expected
new file mode 100644
index 0000000000..904c7339e0
--- /dev/null
+++ b/src/test/conf_examples/relay_10/expected
@@ -0,0 +1,3 @@
+BridgeRelay 1
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_10/expected_log b/src/test/conf_examples/relay_10/expected_log
new file mode 100644
index 0000000000..5b81a904e5
--- /dev/null
+++ b/src/test/conf_examples/relay_10/expected_log
@@ -0,0 +1 @@
+Can't set a DirPort on a bridge relay
diff --git a/src/test/conf_examples/relay_10/torrc b/src/test/conf_examples/relay_10/torrc
new file mode 100644
index 0000000000..4318ebb45b
--- /dev/null
+++ b/src/test/conf_examples/relay_10/torrc
@@ -0,0 +1,7 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid config, that has a warning: Bridge, warn and disable DirPort
+ORPort 1
+DirPort 2
+DirCache 1
+BridgeRelay 1
diff --git a/src/test/conf_examples/relay_11/error b/src/test/conf_examples/relay_11/error
new file mode 100644
index 0000000000..8ed5c31bc7
--- /dev/null
+++ b/src/test/conf_examples/relay_11/error
@@ -0,0 +1 @@
+We are advertising an ORPort, but not actually listening on one
diff --git a/src/test/conf_examples/relay_11/error_no_dirauth_relay b/src/test/conf_examples/relay_11/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_11/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_11/torrc b/src/test/conf_examples/relay_11/torrc
new file mode 100644
index 0000000000..a1e13eb3ce
--- /dev/null
+++ b/src/test/conf_examples/relay_11/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Advertising but not listening: ORPort
+ORPort 1 NoListen
diff --git a/src/test/conf_examples/relay_12/error b/src/test/conf_examples/relay_12/error
new file mode 100644
index 0000000000..57706d6a7a
--- /dev/null
+++ b/src/test/conf_examples/relay_12/error
@@ -0,0 +1 @@
+We are advertising a DirPort, but not actually listening on one
diff --git a/src/test/conf_examples/relay_12/error_no_dirauth_relay b/src/test/conf_examples/relay_12/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_12/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_12/torrc b/src/test/conf_examples/relay_12/torrc
new file mode 100644
index 0000000000..4a7d398112
--- /dev/null
+++ b/src/test/conf_examples/relay_12/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Advertising but not listening: DirPort
+DirPort 1 NoListen
diff --git a/src/test/conf_examples/relay_13/error b/src/test/conf_examples/relay_13/error
new file mode 100644
index 0000000000..cd74247ea8
--- /dev/null
+++ b/src/test/conf_examples/relay_13/error
@@ -0,0 +1 @@
+We are listening on an ORPort, but not advertising any ORPorts
diff --git a/src/test/conf_examples/relay_13/error_no_dirauth_relay b/src/test/conf_examples/relay_13/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_13/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_13/torrc b/src/test/conf_examples/relay_13/torrc
new file mode 100644
index 0000000000..b76b72c0cc
--- /dev/null
+++ b/src/test/conf_examples/relay_13/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Listening but not advertising: ORPort
+ORPort 1 NoAdvertise
diff --git a/src/test/conf_examples/relay_14/error_no_dirauth_relay b/src/test/conf_examples/relay_14/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_14/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_14/expected b/src/test/conf_examples/relay_14/expected
new file mode 100644
index 0000000000..31bb1c2507
--- /dev/null
+++ b/src/test/conf_examples/relay_14/expected
@@ -0,0 +1 @@
+DirPort 1 NoAdvertise
diff --git a/src/test/conf_examples/relay_14/expected_log b/src/test/conf_examples/relay_14/expected_log
new file mode 100644
index 0000000000..9b0c820211
--- /dev/null
+++ b/src/test/conf_examples/relay_14/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_14[./]*torrc
diff --git a/src/test/conf_examples/relay_14/torrc b/src/test/conf_examples/relay_14/torrc
new file mode 100644
index 0000000000..15c6496c7e
--- /dev/null
+++ b/src/test/conf_examples/relay_14/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Listening but not advertising: DirPort
+DirPort 1 NoAdvertise
diff --git a/src/test/conf_examples/relay_15/error b/src/test/conf_examples/relay_15/error
new file mode 100644
index 0000000000..da30f0cd14
--- /dev/null
+++ b/src/test/conf_examples/relay_15/error
@@ -0,0 +1 @@
+Can't advertise more than one DirPort
diff --git a/src/test/conf_examples/relay_15/error_no_dirauth_relay b/src/test/conf_examples/relay_15/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_15/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_15/torrc b/src/test/conf_examples/relay_15/torrc
new file mode 100644
index 0000000000..e1f78ee6a0
--- /dev/null
+++ b/src/test/conf_examples/relay_15/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Advertising more than one DirPort
+DirPort 1
+DirPort 2
diff --git a/src/test/conf_examples/relay_16/error b/src/test/conf_examples/relay_16/error
new file mode 100644
index 0000000000..37b89ee572
--- /dev/null
+++ b/src/test/conf_examples/relay_16/error
@@ -0,0 +1 @@
+Configured public relay to listen only on an IPv6 address. Tor needs to listen on an IPv4 address
diff --git a/src/test/conf_examples/relay_16/error_no_dirauth_relay b/src/test/conf_examples/relay_16/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_16/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_16/torrc b/src/test/conf_examples/relay_16/torrc
new file mode 100644
index 0000000000..e544cd87a4
--- /dev/null
+++ b/src/test/conf_examples/relay_16/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# IPv6 ORPort only
+ORPort [::1]:2
diff --git a/src/test/conf_examples/relay_17/error_no_dirauth_relay b/src/test/conf_examples/relay_17/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_17/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_17/expected b/src/test/conf_examples/relay_17/expected
new file mode 100644
index 0000000000..3fb0c9db92
--- /dev/null
+++ b/src/test/conf_examples/relay_17/expected
@@ -0,0 +1,4 @@
+AccountingMax 1
+KeepBindCapabilities 0
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_17/expected_log b/src/test/conf_examples/relay_17/expected_log
new file mode 100644
index 0000000000..7711f90178
--- /dev/null
+++ b/src/test/conf_examples/relay_17/expected_log
@@ -0,0 +1 @@
+You have set AccountingMax to use hibernation
diff --git a/src/test/conf_examples/relay_17/torrc b/src/test/conf_examples/relay_17/torrc
new file mode 100644
index 0000000000..f63f36815e
--- /dev/null
+++ b/src/test/conf_examples/relay_17/torrc
@@ -0,0 +1,6 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Rebind warning
+ORPort 1
+AccountingMax 1
+KeepBindCapabilities 0
diff --git a/src/test/conf_examples/relay_18/error b/src/test/conf_examples/relay_18/error
new file mode 100644
index 0000000000..5b28d311b0
--- /dev/null
+++ b/src/test/conf_examples/relay_18/error
@@ -0,0 +1 @@
+Invalid DirPort configuration
diff --git a/src/test/conf_examples/relay_18/error_no_dirauth_relay b/src/test/conf_examples/relay_18/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_18/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_18/torrc b/src/test/conf_examples/relay_18/torrc
new file mode 100644
index 0000000000..67a0fd0dfb
--- /dev/null
+++ b/src/test/conf_examples/relay_18/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Bad DirPort
+DirPort illegal_hostname_chars$()^*%(%#%)#(%*
diff --git a/src/test/conf_examples/relay_19/error_no_dirauth_relay b/src/test/conf_examples/relay_19/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_19/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_19/expected b/src/test/conf_examples/relay_19/expected
new file mode 100644
index 0000000000..f077169c88
--- /dev/null
+++ b/src/test/conf_examples/relay_19/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 1
+PublishServerDescriptor
diff --git a/src/test/conf_examples/relay_19/expected_log b/src/test/conf_examples/relay_19/expected_log
new file mode 100644
index 0000000000..17656ba2cf
--- /dev/null
+++ b/src/test/conf_examples/relay_19/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_19[./]*torrc
diff --git a/src/test/conf_examples/relay_19/torrc b/src/test/conf_examples/relay_19/torrc
new file mode 100644
index 0000000000..fd2cd91fa5
--- /dev/null
+++ b/src/test/conf_examples/relay_19/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Minimal PublishServerDescriptor
+ORPort 1
+PublishServerDescriptor
diff --git a/src/test/conf_examples/relay_20/error b/src/test/conf_examples/relay_20/error
new file mode 100644
index 0000000000..e5a81637f8
--- /dev/null
+++ b/src/test/conf_examples/relay_20/error
@@ -0,0 +1 @@
+Unrecognized value in PublishServerDescriptor
diff --git a/src/test/conf_examples/relay_20/error_no_dirauth_relay b/src/test/conf_examples/relay_20/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_20/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_20/torrc b/src/test/conf_examples/relay_20/torrc
new file mode 100644
index 0000000000..87dd74fdc1
--- /dev/null
+++ b/src/test/conf_examples/relay_20/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Invalid PublishServerDescriptor
+ORPort 1
+PublishServerDescriptor bad
diff --git a/src/test/conf_examples/relay_21/error_no_dirauth_relay b/src/test/conf_examples/relay_21/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_21/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_21/expected b/src/test/conf_examples/relay_21/expected
new file mode 100644
index 0000000000..9bcead1402
--- /dev/null
+++ b/src/test/conf_examples/relay_21/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 1
+PublishServerDescriptor v1,v2,hidserv
diff --git a/src/test/conf_examples/relay_21/expected_log b/src/test/conf_examples/relay_21/expected_log
new file mode 100644
index 0000000000..ba0d56fb1c
--- /dev/null
+++ b/src/test/conf_examples/relay_21/expected_log
@@ -0,0 +1 @@
+PublishServerDescriptor v1 has no effect
diff --git a/src/test/conf_examples/relay_21/torrc b/src/test/conf_examples/relay_21/torrc
new file mode 100644
index 0000000000..97f032f626
--- /dev/null
+++ b/src/test/conf_examples/relay_21/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Ignored PublishServerDescriptor values
+ORPort 1
+PublishServerDescriptor v1,v2,hidserv
diff --git a/src/test/conf_examples/relay_22/error b/src/test/conf_examples/relay_22/error
new file mode 100644
index 0000000000..c47dd8c4c6
--- /dev/null
+++ b/src/test/conf_examples/relay_22/error
@@ -0,0 +1 @@
+Invalid BridgeDistribution value
diff --git a/src/test/conf_examples/relay_22/error_no_dirauth_relay b/src/test/conf_examples/relay_22/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_22/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_22/torrc b/src/test/conf_examples/relay_22/torrc
new file mode 100644
index 0000000000..e83c83260e
--- /dev/null
+++ b/src/test/conf_examples/relay_22/torrc
@@ -0,0 +1,6 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Bad BridgeDistribution characters
+ORPort 1
+BridgeRelay 1
+BridgeDistribution *$%()@!
diff --git a/src/test/conf_examples/relay_23/error b/src/test/conf_examples/relay_23/error
new file mode 100644
index 0000000000..f76bbe77c4
--- /dev/null
+++ b/src/test/conf_examples/relay_23/error
@@ -0,0 +1 @@
+Relays must use 'auto' for the ConnectionPadding setting
diff --git a/src/test/conf_examples/relay_23/error_no_dirauth_relay b/src/test/conf_examples/relay_23/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_23/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_23/torrc b/src/test/conf_examples/relay_23/torrc
new file mode 100644
index 0000000000..3d28a1e27c
--- /dev/null
+++ b/src/test/conf_examples/relay_23/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set ConnectionPadding
+ORPort 1
+ConnectionPadding 1
diff --git a/src/test/conf_examples/relay_24/error b/src/test/conf_examples/relay_24/error
new file mode 100644
index 0000000000..f76bbe77c4
--- /dev/null
+++ b/src/test/conf_examples/relay_24/error
@@ -0,0 +1 @@
+Relays must use 'auto' for the ConnectionPadding setting
diff --git a/src/test/conf_examples/relay_24/error_no_dirauth_relay b/src/test/conf_examples/relay_24/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_24/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_24/torrc b/src/test/conf_examples/relay_24/torrc
new file mode 100644
index 0000000000..1206e59e09
--- /dev/null
+++ b/src/test/conf_examples/relay_24/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set ConnectionPadding
+ORPort 1
+ConnectionPadding 0
diff --git a/src/test/conf_examples/relay_25/error b/src/test/conf_examples/relay_25/error
new file mode 100644
index 0000000000..bac681e6cc
--- /dev/null
+++ b/src/test/conf_examples/relay_25/error
@@ -0,0 +1 @@
+Relays cannot set ReducedConnectionPadding
diff --git a/src/test/conf_examples/relay_25/error_no_dirauth_relay b/src/test/conf_examples/relay_25/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_25/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_25/torrc b/src/test/conf_examples/relay_25/torrc
new file mode 100644
index 0000000000..ab862a16f3
--- /dev/null
+++ b/src/test/conf_examples/relay_25/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set ReducedConnectionPadding 1
+ORPort 1
+ReducedConnectionPadding 1
diff --git a/src/test/conf_examples/relay_26/error b/src/test/conf_examples/relay_26/error
new file mode 100644
index 0000000000..94334935e3
--- /dev/null
+++ b/src/test/conf_examples/relay_26/error
@@ -0,0 +1 @@
+Relays cannot set CircuitPadding to 0
diff --git a/src/test/conf_examples/relay_26/error_no_dirauth_relay b/src/test/conf_examples/relay_26/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_26/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_26/torrc b/src/test/conf_examples/relay_26/torrc
new file mode 100644
index 0000000000..5dd6d68dc4
--- /dev/null
+++ b/src/test/conf_examples/relay_26/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set CircuitPadding to 0
+ORPort 1
+CircuitPadding 0
diff --git a/src/test/conf_examples/relay_27/error b/src/test/conf_examples/relay_27/error
new file mode 100644
index 0000000000..e26ce46914
--- /dev/null
+++ b/src/test/conf_examples/relay_27/error
@@ -0,0 +1 @@
+Relays cannot set ReducedCircuitPadding
diff --git a/src/test/conf_examples/relay_27/error_no_dirauth_relay b/src/test/conf_examples/relay_27/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_27/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_27/torrc b/src/test/conf_examples/relay_27/torrc
new file mode 100644
index 0000000000..8556b2f351
--- /dev/null
+++ b/src/test/conf_examples/relay_27/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set ReducedCircuitPadding 1
+ORPort 1
+ReducedCircuitPadding 1
diff --git a/src/test/conf_examples/relay_28/error b/src/test/conf_examples/relay_28/error
new file mode 100644
index 0000000000..3f14df975b
--- /dev/null
+++ b/src/test/conf_examples/relay_28/error
@@ -0,0 +1 @@
+SigningKeyLifetime is too short
diff --git a/src/test/conf_examples/relay_28/error_no_dirauth_relay b/src/test/conf_examples/relay_28/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_28/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_28/torrc b/src/test/conf_examples/relay_28/torrc
new file mode 100644
index 0000000000..3e2c895bb7
--- /dev/null
+++ b/src/test/conf_examples/relay_28/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Short key lifetimes
+ORPort 1
+SigningKeyLifetime 1
diff --git a/src/test/conf_examples/relay_29/error_no_dirauth_relay b/src/test/conf_examples/relay_29/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_29/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_29/expected b/src/test/conf_examples/relay_29/expected
new file mode 100644
index 0000000000..1d25374ed1
--- /dev/null
+++ b/src/test/conf_examples/relay_29/expected
@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_29/expected_log b/src/test/conf_examples/relay_29/expected_log
new file mode 100644
index 0000000000..f46c609c0c
--- /dev/null
+++ b/src/test/conf_examples/relay_29/expected_log
@@ -0,0 +1 @@
+Linelist option 'MyFamily' has no value\. Skipping
diff --git a/src/test/conf_examples/relay_29/torrc b/src/test/conf_examples/relay_29/torrc
new file mode 100644
index 0000000000..4181d5acc2
--- /dev/null
+++ b/src/test/conf_examples/relay_29/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# MyFamily normalisation: empty MyFamily
+ORPort 1
+MyFamily
diff --git a/src/test/conf_examples/relay_30/error_no_dirauth_relay b/src/test/conf_examples/relay_30/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_30/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_30/expected b/src/test/conf_examples/relay_30/expected
new file mode 100644
index 0000000000..3a4e9feb3f
--- /dev/null
+++ b/src/test/conf_examples/relay_30/expected
@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort auto
diff --git a/src/test/conf_examples/relay_30/expected_log b/src/test/conf_examples/relay_30/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_30/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_30/torrc b/src/test/conf_examples/relay_30/torrc
new file mode 100644
index 0000000000..bf8487fe16
--- /dev/null
+++ b/src/test/conf_examples/relay_30/torrc
@@ -0,0 +1,3 @@
+# Relay tests
+# default (IPv4) ORPort auto
+ORPort auto
diff --git a/src/test/conf_examples/relay_31/error_no_dirauth_relay b/src/test/conf_examples/relay_31/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_31/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_31/expected b/src/test/conf_examples/relay_31/expected
new file mode 100644
index 0000000000..9a40cdd588
--- /dev/null
+++ b/src/test/conf_examples/relay_31/expected
@@ -0,0 +1,3 @@
+DirPort auto
+Nickname Unnamed
+ORPort auto
diff --git a/src/test/conf_examples/relay_31/expected_log b/src/test/conf_examples/relay_31/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_31/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_31/torrc b/src/test/conf_examples/relay_31/torrc
new file mode 100644
index 0000000000..e662bb71b3
--- /dev/null
+++ b/src/test/conf_examples/relay_31/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# default (IPv4) ORPort and DirPort auto
+ORPort auto
+DirPort auto
diff --git a/src/test/conf_examples/relay_32/error_no_dirauth_relay b/src/test/conf_examples/relay_32/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_32/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_32/expected b/src/test/conf_examples/relay_32/expected
new file mode 100644
index 0000000000..14b36c8259
--- /dev/null
+++ b/src/test/conf_examples/relay_32/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_32/expected_log b/src/test/conf_examples/relay_32/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_32/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_32/torrc b/src/test/conf_examples/relay_32/torrc
new file mode 100644
index 0000000000..95a66c4852
--- /dev/null
+++ b/src/test/conf_examples/relay_32/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# default (IPv4) ORPort auto and IPv6 ORPort auto
+ORPort auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_33/error_no_dirauth_relay b/src/test/conf_examples/relay_33/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_33/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_33/expected b/src/test/conf_examples/relay_33/expected
new file mode 100644
index 0000000000..22567cbe2e
--- /dev/null
+++ b/src/test/conf_examples/relay_33/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 127.0.0.1:auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_33/expected_log b/src/test/conf_examples/relay_33/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_33/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_33/torrc b/src/test/conf_examples/relay_33/torrc
new file mode 100644
index 0000000000..44d16ad31a
--- /dev/null
+++ b/src/test/conf_examples/relay_33/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# explicit IPv4 ORPort auto and IPv6 ORPort auto
+ORPort 127.0.0.1:auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_34/error_no_dirauth_relay b/src/test/conf_examples/relay_34/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_34/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_34/expected b/src/test/conf_examples/relay_34/expected
new file mode 100644
index 0000000000..bccde684f3
--- /dev/null
+++ b/src/test/conf_examples/relay_34/expected
@@ -0,0 +1,4 @@
+DirPort 127.0.0.1:auto
+Nickname Unnamed
+ORPort 127.0.0.1:auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_34/expected_log b/src/test/conf_examples/relay_34/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_34/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_34/torrc b/src/test/conf_examples/relay_34/torrc
new file mode 100644
index 0000000000..01010a5c38
--- /dev/null
+++ b/src/test/conf_examples/relay_34/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# explicit IPv4 ORPort and DirPort auto and IPv6 ORPort auto
+ORPort 127.0.0.1:auto
+ORPort [::1]:auto
+DirPort 127.0.0.1:auto
diff --git a/src/test/conf_failures/README b/src/test/conf_failures/README
new file mode 100644
index 0000000000..0da470eeb4
--- /dev/null
+++ b/src/test/conf_failures/README
@@ -0,0 +1,5 @@
+This directory contains typical test_parseconf.sh failure cases.
+
+If these directories are copied into conf_examples, test_parseconf.sh will
+fail. Use these failure cases to make sure test_parseconf.sh handles failures
+correctly, and produces useful output.
diff --git a/src/test/conf_failures/fail-error-success/error b/src/test/conf_failures/fail-error-success/error
new file mode 100644
index 0000000000..569a631e86
--- /dev/null
+++ b/src/test/conf_failures/fail-error-success/error
@@ -0,0 +1 @@
+Tor
diff --git a/src/test/conf_failures/fail-error-success/torrc b/src/test/conf_failures/fail-error-success/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-error-success/torrc
diff --git a/src/test/conf_failures/fail-error/error b/src/test/conf_failures/fail-error/error
new file mode 100644
index 0000000000..4c0be97832
--- /dev/null
+++ b/src/test/conf_failures/fail-error/error
@@ -0,0 +1 @@
+no match
diff --git a/src/test/conf_failures/fail-error/torrc b/src/test/conf_failures/fail-error/torrc
new file mode 100644
index 0000000000..bb6fe186a4
--- /dev/null
+++ b/src/test/conf_failures/fail-error/torrc
@@ -0,0 +1 @@
+bad bad bad
diff --git a/src/test/conf_failures/fail-expected-error/expected b/src/test/conf_failures/fail-expected-error/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-error/expected
diff --git a/src/test/conf_failures/fail-expected-error/torrc b/src/test/conf_failures/fail-expected-error/torrc
new file mode 100644
index 0000000000..bb6fe186a4
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-error/torrc
@@ -0,0 +1 @@
+bad bad bad
diff --git a/src/test/conf_failures/fail-expected-log/expected b/src/test/conf_failures/fail-expected-log/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-log/expected
diff --git a/src/test/conf_failures/fail-expected-log/expected_log b/src/test/conf_failures/fail-expected-log/expected_log
new file mode 100644
index 0000000000..bb6fe186a4
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-log/expected_log
@@ -0,0 +1 @@
+bad bad bad
diff --git a/src/test/conf_failures/fail-expected-log/torrc b/src/test/conf_failures/fail-expected-log/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-log/torrc
diff --git a/src/test/conf_failures/fail-expected/expected b/src/test/conf_failures/fail-expected/expected
new file mode 100644
index 0000000000..67be85f127
--- /dev/null
+++ b/src/test/conf_failures/fail-expected/expected
@@ -0,0 +1 @@
+bad
diff --git a/src/test/conf_failures/fail-expected/torrc b/src/test/conf_failures/fail-expected/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-expected/torrc
diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py
index 75562184b5..ae537ff15b 100644
--- a/src/test/ed25519_exts_ref.py
+++ b/src/test/ed25519_exts_ref.py
@@ -8,6 +8,11 @@
Includes self-tester and test vector generator.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import slow_ed25519
from slow_ed25519 import *
@@ -147,7 +152,7 @@ class SelfTest(unittest.TestCase):
# Check that identities match
assert(identity == identity2)
# Check that identity is the point (0,1)
- assert(identity == [0L,1L])
+ assert(identity == [0,1])
# Check identity element: a*E = E, where a is a random scalar
scalar = random_scalar(os.urandom)
@@ -181,22 +186,22 @@ BLINDING_PARAMS = [
PREFIX = "ED25519_"
def writeArray(name, array):
- print "static const char *{prefix}{name}[] = {{".format(
- prefix=PREFIX,name=name)
+ print("static const char *{prefix}{name}[] = {{".format(
+ prefix=PREFIX,name=name))
for a in array:
h = binascii.b2a_hex(a)
if len(h) > 70:
h1 = h[:70]
h2 = h[70:]
- print ' "{0}"\n "{1}",'.format(h1,h2)
+ print(' "{0}"\n "{1}",'.format(h1,h2))
else:
- print ' "{0}",'.format(h)
- print "};\n"
+ print(' "{0}",'.format(h))
+ print("};\n")
def comment(text, initial="/**"):
- print initial
- print textwrap.fill(text,initial_indent=" * ",subsequent_indent=" * ")
- print " */"
+ print(initial)
+ print(textwrap.fill(text,initial_indent=" * ",subsequent_indent=" * "))
+ print(" */")
def makeTestVectors():
comment("""Test vectors for our ed25519 implementation and related
@@ -252,7 +257,7 @@ def makeTestVectors():
if __name__ == '__main__':
import sys
if len(sys.argv) == 1 or sys.argv[1] not in ("SelfTest", "MakeVectors"):
- print "You should specify one of 'SelfTest' or 'MakeVectors'"
+ print("You should specify one of 'SelfTest' or 'MakeVectors'")
sys.exit(1)
if sys.argv[1] == 'SelfTest':
unittest.main()
diff --git a/src/test/fakechans.h b/src/test/fakechans.h
index 4006e1bec4..c3accb1637 100644
--- a/src/test/fakechans.h
+++ b/src/test/fakechans.h
@@ -1,4 +1,4 @@
- /* Copyright (c) 2014-2019, The Tor Project, Inc. */
+ /* Copyright (c) 2014-2020, 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
new file mode 100644
index 0000000000..4d5b97197e
--- /dev/null
+++ b/src/test/fakecircs.c
@@ -0,0 +1,91 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file fakecircs.c
+ * \brief Fake circuits API for unit test.
+ **/
+
+#define CIRCUITBUILD_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#define CRYPT_PATH_PRIVATE
+
+#include "core/or/or.h"
+
+#include "core/crypto/relay_crypto.h"
+#include "core/or/channel.h"
+#include "core/or/circuitbuild.h"
+#include "core/or/circuitlist.h"
+#include "core/or/circuitpadding.h"
+#include "core/or/crypt_path.h"
+#include "core/or/relay.h"
+#include "core/or/relay_crypto_st.h"
+
+#include "test/fakecircs.h"
+
+/** Return newly allocated OR circuit using the given nchan and pchan. It must
+ * be freed with the free_fake_orcirc(). */
+or_circuit_t *
+new_fake_orcirc(channel_t *nchan, channel_t *pchan)
+{
+ or_circuit_t *orcirc = NULL;
+ circuit_t *circ = NULL;
+ crypt_path_t tmp_cpath;
+ char whatevs_key[CPATH_KEY_MATERIAL_LEN];
+
+ orcirc = tor_malloc_zero(sizeof(*orcirc));
+ circ = &(orcirc->base_);
+ circ->magic = OR_CIRCUIT_MAGIC;
+
+ circuit_set_n_circid_chan(circ, get_unique_circ_id_by_chan(nchan), nchan);
+ cell_queue_init(&(circ->n_chan_cells));
+
+ circ->n_hop = NULL;
+ circ->streams_blocked_on_n_chan = 0;
+ circ->streams_blocked_on_p_chan = 0;
+ circ->n_delete_pending = 0;
+ circ->p_delete_pending = 0;
+ circ->received_destroy = 0;
+ circ->state = CIRCUIT_STATE_OPEN;
+ circ->purpose = CIRCUIT_PURPOSE_OR;
+ circ->package_window = CIRCWINDOW_START_MAX;
+ circ->deliver_window = CIRCWINDOW_START_MAX;
+ circ->n_chan_create_cell = NULL;
+
+ circuit_set_p_circid_chan(orcirc, get_unique_circ_id_by_chan(pchan), pchan);
+ cell_queue_init(&(orcirc->p_chan_cells));
+
+ memset(&tmp_cpath, 0, sizeof(tmp_cpath));
+ if (cpath_init_circuit_crypto(&tmp_cpath, whatevs_key,
+ sizeof(whatevs_key), 0, 0)<0) {
+ log_warn(LD_BUG,"Circuit initialization failed");
+ return NULL;
+ }
+ orcirc->crypto = tmp_cpath.pvt_crypto;
+
+ return orcirc;
+}
+
+/** Free fake OR circuit which MUST be created by new_fake_orcirc(). */
+void
+free_fake_orcirc(or_circuit_t *orcirc)
+{
+ if (!orcirc) {
+ return;
+ }
+
+ circuit_t *circ = TO_CIRCUIT(orcirc);
+
+ relay_crypto_clear(&orcirc->crypto);
+
+ circpad_circuit_free_all_machineinfos(circ);
+
+ if (orcirc->p_chan && orcirc->p_chan->cmux) {
+ circuitmux_detach_circuit(orcirc->p_chan->cmux, circ);
+ }
+ if (circ->n_chan && circ->n_chan->cmux) {
+ circuitmux_detach_circuit(circ->n_chan->cmux, circ);
+ }
+
+ tor_free_(circ);
+}
diff --git a/src/test/fakecircs.h b/src/test/fakecircs.h
new file mode 100644
index 0000000000..ed8a150a3f
--- /dev/null
+++ b/src/test/fakecircs.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file fakecircs.h
+ * \brief Declarations for fake circuits for test suite use.
+ **/
+
+#ifndef TOR_FAKECIRCS_H
+#define TOR_FAKECIRCS_H
+
+#include "core/or/or_circuit_st.h"
+
+or_circuit_t *new_fake_orcirc(channel_t *nchan, channel_t *pchan);
+void free_fake_orcirc(or_circuit_t *orcirc);
+
+#endif /* !defined(TOR_FAKECIRCS_H) */
diff --git a/src/test/fuzz/.may_include b/src/test/fuzz/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/test/fuzz/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c
index 656ef0bdb2..f2bf29ea78 100644
--- a/src/test/fuzz/fuzz_consensus.c
+++ b/src/test/fuzz/fuzz_consensus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 58ee3dbc35..eb4d4d507f 100644
--- a/src/test/fuzz/fuzz_descriptor.c
+++ b/src/test/fuzz/fuzz_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 a31445666c..9cd2116245 100644
--- a/src/test/fuzz/fuzz_diff.c
+++ b/src/test/fuzz/fuzz_diff.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 d8a0f9e590..a819c73338 100644
--- a/src/test/fuzz/fuzz_diff_apply.c
+++ b/src/test/fuzz/fuzz_diff_apply.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 f18bd68d65..ad21254e3e 100644
--- a/src/test/fuzz/fuzz_extrainfo.c
+++ b/src/test/fuzz/fuzz_extrainfo.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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
index 34639b237c..81d9e5f00e 100644
--- a/src/test/fuzz/fuzz_hsdescv2.c
+++ b/src/test/fuzz/fuzz_hsdescv2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
#include "feature/dirparse/unparseable.h"
diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c
index 9d4a6dbb55..8d7eab1a8d 100644
--- a/src/test/fuzz/fuzz_hsdescv3.c
+++ b/src/test/fuzz/fuzz_hsdescv3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define HS_DESCRIPTOR_PRIVATE
@@ -85,12 +85,12 @@ int
fuzz_main(const uint8_t *data, size_t sz)
{
hs_descriptor_t *desc = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *fuzzing_data = tor_memdup_nulterm(data, sz);
- memset(subcredential, 'A', sizeof(subcredential));
+ memset(&subcredential, 'A', sizeof(subcredential));
- hs_desc_decode_descriptor(fuzzing_data, subcredential, NULL, &desc);
+ hs_desc_decode_descriptor(fuzzing_data, &subcredential, NULL, &desc);
if (desc) {
log_debug(LD_GENERAL, "Decoding okay");
hs_descriptor_free(desc);
@@ -101,4 +101,3 @@ fuzz_main(const uint8_t *data, size_t sz)
tor_free(fuzzing_data);
return 0;
}
-
diff --git a/src/test/fuzz/fuzz_http.c b/src/test/fuzz/fuzz_http.c
index 44393b3a10..a4fd182f1e 100644
--- a/src/test/fuzz/fuzz_http.c
+++ b/src/test/fuzz/fuzz_http.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 2a597cae74..9e5a48ba4d 100644
--- a/src/test/fuzz/fuzz_http_connect.c
+++ b/src/test/fuzz/fuzz_http_connect.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 76fa3c164e..bc51ffcdb8 100644
--- a/src/test/fuzz/fuzz_iptsv2.c
+++ b/src/test/fuzz/fuzz_iptsv2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 28fdc5e24d..3fc709183b 100644
--- a/src/test/fuzz/fuzz_microdesc.c
+++ b/src/test/fuzz/fuzz_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 d6c416a0f9..4e7cb4d48d 100644
--- a/src/test/fuzz/fuzz_socks.c
+++ b/src/test/fuzz/fuzz_socks.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 459b4e21aa..05d9101e72 100644
--- a/src/test/fuzz/fuzz_strops.c
+++ b/src/test/fuzz/fuzz_strops.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 7b61b8df2d..d6e88e59e7 100644
--- a/src/test/fuzz/fuzz_vrs.c
+++ b/src/test/fuzz/fuzz_vrs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 2d278825ec..6cbcdc41ad 100644
--- a/src/test/fuzz/fuzzing.h
+++ b/src/test/fuzz/fuzzing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 604aba7a7f..d9719074ad 100644
--- a/src/test/fuzz/fuzzing_common.c
+++ b/src/test/fuzz/fuzzing_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CRYPTO_ED25519_PRIVATE
#define CONFIG_PRIVATE
diff --git a/src/test/hs_build_address.py b/src/test/hs_build_address.py
index 7ff22c3a9a..91864eabcb 100644
--- a/src/test/hs_build_address.py
+++ b/src/test/hs_build_address.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/hs_indexes.py b/src/test/hs_indexes.py
index af0b81f8de..5c6d893a66 100644
--- a/src/test/hs_indexes.py
+++ b/src/test/hs_indexes.py
@@ -7,6 +7,11 @@
# store/fetch the descriptor on the hashring. (hs_build_hs_index()).
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/hs_ntor_ref.py b/src/test/hs_ntor_ref.py
index 1b9772a5d6..f107cc36ca 100644
--- a/src/test/hs_ntor_ref.py
+++ b/src/test/hs_ntor_ref.py
@@ -41,6 +41,11 @@ The whole logic and concept for this test suite was taken from ntor_ref.py.
*** DO NOT USE THIS IN PRODUCTION. ***
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import struct
import os, sys
import binascii
diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c
index 0a21fe576b..5116fc7169 100644
--- a/src/test/hs_test_helpers.c
+++ b/src/test/hs_test_helpers.c
@@ -1,17 +1,34 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define HS_CLIENT_PRIVATE
+
#include "core/or/or.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "test/test.h"
#include "feature/nodelist/torcert.h"
+#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
+#include "feature/hs/hs_service.h"
#include "test/hs_test_helpers.h"
+/**
+ * Create an introduction point taken straight out of an HSv3 descriptor.
+ *
+ * Use 'signing_kp' to sign the introduction point certificates.
+ *
+ * If 'intro_auth_kp' is provided use that as the introduction point
+ * authentication keypair, otherwise generate one on the fly.
+ *
+ * If 'intro_enc_kp' is provided use that as the introduction point encryption
+ * keypair, otherwise generate one on the fly.
+ */
hs_desc_intro_point_t *
hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
- const char *addr, int legacy)
+ const char *addr, int legacy,
+ const ed25519_keypair_t *intro_auth_kp,
+ const curve25519_keypair_t *intro_enc_kp)
{
int ret;
ed25519_keypair_t auth_kp;
@@ -52,8 +69,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
smartlist_add(ip->link_specifiers, ls_ip);
}
- ret = ed25519_keypair_generate(&auth_kp, 0);
- tt_int_op(ret, ==, 0);
+ if (intro_auth_kp) {
+ memcpy(&auth_kp, intro_auth_kp, sizeof(ed25519_keypair_t));
+ } else {
+ ret = ed25519_keypair_generate(&auth_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ }
ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
&auth_kp.pubkey, now,
HS_DESC_CERT_LIFETIME,
@@ -64,7 +85,7 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
ip->legacy.key = crypto_pk_new();
tt_assert(ip->legacy.key);
ret = crypto_pk_generate_key(ip->legacy.key);
- tt_int_op(ret, ==, 0);
+ tt_int_op(ret, OP_EQ, 0);
ssize_t cert_len = tor_make_rsa_ed25519_crosscert(
&signing_kp->pubkey, ip->legacy.key,
now + HS_DESC_CERT_LIFETIME,
@@ -81,8 +102,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
ed25519_keypair_t ed25519_kp;
tor_cert_t *cross_cert;
- ret = curve25519_keypair_generate(&curve25519_kp, 0);
- tt_int_op(ret, ==, 0);
+ if (intro_enc_kp) {
+ memcpy(&curve25519_kp, intro_enc_kp, sizeof(curve25519_keypair_t));
+ } else {
+ ret = curve25519_keypair_generate(&curve25519_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ }
ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit,
&curve25519_kp);
cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS,
@@ -91,6 +116,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(cross_cert);
ip->enc_key_cert = cross_cert;
+ memcpy(ip->enc_key.public_key, curve25519_kp.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN);
}
intro_point = ip;
@@ -136,11 +163,11 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
desc->plaintext_data.lifetime_sec = 3 * 60 * 60;
hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey,
- desc->subcredential);
+ &desc->subcredential);
/* Setup superencrypted data section. */
ret = curve25519_keypair_generate(&auth_ephemeral_kp, 0);
- tt_int_op(ret, ==, 0);
+ tt_int_op(ret, OP_EQ, 0);
memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey,
&auth_ephemeral_kp.pubkey,
sizeof(curve25519_public_key_t));
@@ -161,13 +188,17 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
if (!no_ip) {
/* Add four intro points. */
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0));
+ hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0));
+ hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1));
+ hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1));
+ hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1,
+ NULL, NULL));
}
descp = desc;
@@ -182,7 +213,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
* an HS. Used to decrypt descriptors in unittests. */
void
hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
- uint8_t *subcred_out)
+ hs_subcredential_t *subcred_out)
{
ed25519_keypair_t blinded_kp;
uint64_t current_time_period = hs_get_time_period_num(approx_time());
@@ -207,6 +238,35 @@ hs_helper_build_hs_desc_no_ip(const ed25519_keypair_t *signing_kp)
return hs_helper_build_hs_desc_impl(1, signing_kp);
}
+hs_descriptor_t *
+hs_helper_build_hs_desc_with_client_auth(
+ const uint8_t *descriptor_cookie,
+ const curve25519_public_key_t *client_pk,
+ 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_desc_authorized_client_t *desc_client;
+
+ /* The number of client authorized auth has tobe a multiple of
+ * HS_DESC_AUTH_CLIENT_MULTIPLE so remove one that we'll replace. */
+ desc_client = smartlist_get(desc->superencrypted_data.clients, 0);
+ smartlist_remove(desc->superencrypted_data.clients, desc_client);
+ hs_desc_authorized_client_free(desc_client);
+
+ desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t));
+
+ curve25519_keypair_generate(&auth_ephemeral_kp, 0);
+ memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey,
+ &auth_ephemeral_kp.pubkey, sizeof(curve25519_public_key_t));
+
+ hs_desc_build_authorized_client(&desc->subcredential, client_pk,
+ &auth_ephemeral_kp.seckey,
+ descriptor_cookie, desc_client);
+ smartlist_add(desc->superencrypted_data.clients, desc_client);
+ return desc;
+}
+
void
hs_helper_desc_equal(const hs_descriptor_t *desc1,
const hs_descriptor_t *desc2)
@@ -224,7 +284,7 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
tt_mem_op(desc1->plaintext_data.blinded_pubkey.pubkey, OP_EQ,
desc2->plaintext_data.blinded_pubkey.pubkey,
ED25519_PUBKEY_LEN);
- tt_u64_op(desc1->plaintext_data.revision_counter, ==,
+ tt_u64_op(desc1->plaintext_data.revision_counter, OP_EQ,
desc2->plaintext_data.revision_counter);
/* NOTE: We can't compare the encrypted blob because when encoding the
@@ -241,7 +301,7 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
{
tt_assert(desc1->superencrypted_data.clients);
tt_assert(desc2->superencrypted_data.clients);
- tt_int_op(smartlist_len(desc1->superencrypted_data.clients), ==,
+ tt_int_op(smartlist_len(desc1->superencrypted_data.clients), OP_EQ,
smartlist_len(desc2->superencrypted_data.clients));
for (int i=0;
i < smartlist_len(desc1->superencrypted_data.clients);
@@ -259,15 +319,15 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
}
/* Encrypted data section. */
- tt_uint_op(desc1->encrypted_data.create2_ntor, ==,
+ tt_uint_op(desc1->encrypted_data.create2_ntor, OP_EQ,
desc2->encrypted_data.create2_ntor);
/* Authentication type. */
- tt_int_op(!!desc1->encrypted_data.intro_auth_types, ==,
+ tt_int_op(!!desc1->encrypted_data.intro_auth_types, OP_EQ,
!!desc2->encrypted_data.intro_auth_types);
if (desc1->encrypted_data.intro_auth_types &&
desc2->encrypted_data.intro_auth_types) {
- tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), ==,
+ tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), OP_EQ,
smartlist_len(desc2->encrypted_data.intro_auth_types));
for (int i = 0;
i < smartlist_len(desc1->encrypted_data.intro_auth_types);
@@ -281,7 +341,7 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
{
tt_assert(desc1->encrypted_data.intro_points);
tt_assert(desc2->encrypted_data.intro_points);
- tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), ==,
+ tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), OP_EQ,
smartlist_len(desc2->encrypted_data.intro_points));
for (int i=0; i < smartlist_len(desc1->encrypted_data.intro_points); i++) {
hs_desc_intro_point_t *ip1 = smartlist_get(desc1->encrypted_data
@@ -296,12 +356,12 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
tt_mem_op(&ip1->enc_key, OP_EQ, &ip2->enc_key, CURVE25519_PUBKEY_LEN);
}
- tt_int_op(smartlist_len(ip1->link_specifiers), ==,
+ tt_int_op(smartlist_len(ip1->link_specifiers), OP_EQ,
smartlist_len(ip2->link_specifiers));
for (int j = 0; j < smartlist_len(ip1->link_specifiers); j++) {
link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j),
*ls2 = smartlist_get(ip2->link_specifiers, j);
- tt_int_op(link_specifier_get_ls_type(ls1), ==,
+ tt_int_op(link_specifier_get_ls_type(ls1), OP_EQ,
link_specifier_get_ls_type(ls2));
switch (link_specifier_get_ls_type(ls1)) {
case LS_IPV4:
@@ -311,7 +371,7 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
tt_int_op(addr1, OP_EQ, addr2);
uint16_t port1 = link_specifier_get_un_ipv4_port(ls1);
uint16_t port2 = link_specifier_get_un_ipv4_port(ls2);
- tt_int_op(port1, ==, port2);
+ tt_int_op(port1, OP_EQ, port2);
}
break;
case LS_IPV6:
@@ -326,7 +386,7 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
link_specifier_getlen_un_ipv6_addr(ls1));
uint16_t port1 = link_specifier_get_un_ipv6_port(ls1);
uint16_t port2 = link_specifier_get_un_ipv6_port(ls2);
- tt_int_op(port1, ==, port2);
+ tt_int_op(port1, OP_EQ, port2);
}
break;
case LS_LEGACY_ID:
@@ -353,3 +413,19 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
;
}
+void
+hs_helper_add_client_auth(const ed25519_public_key_t *service_pk,
+ const curve25519_secret_key_t *client_sk)
+{
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ if (client_auths == NULL) {
+ client_auths = digest256map_new();
+ set_hs_client_auths_map(client_auths);
+ }
+
+ hs_client_service_authorization_t *auth =
+ tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+ memcpy(&auth->enc_seckey, client_sk, sizeof(curve25519_secret_key_t));
+ hs_build_address(service_pk, HS_VERSION_THREE, auth->onion_address);
+ digest256map_set(client_auths, service_pk->pubkey, auth);
+}
diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h
index 9662a83ba8..23d11f2a4a 100644
--- a/src/test/hs_test_helpers.h
+++ b/src/test/hs_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_HS_TEST_HELPERS_H
@@ -8,18 +8,26 @@
#include "feature/hs/hs_descriptor.h"
/* Set of functions to help build and test descriptors. */
-hs_desc_intro_point_t *hs_helper_build_intro_point(
- const ed25519_keypair_t *signing_kp, time_t now,
- const char *addr, int legacy);
+hs_desc_intro_point_t *
+hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
+ const char *addr, int legacy,
+ const ed25519_keypair_t *intro_auth_kp,
+ const curve25519_keypair_t *intro_enc_kp);
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_client_auth(
+ const uint8_t *descriptor_cookie,
+ const curve25519_public_key_t *client_pk,
+ const ed25519_keypair_t *signing_kp);
void hs_helper_desc_equal(const hs_descriptor_t *desc1,
const hs_descriptor_t *desc2);
-void
-hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
- uint8_t *subcred_out);
+struct hs_subcredential_t;
+void hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
+ struct hs_subcredential_t *subcred_out);
-#endif /* !defined(TOR_HS_TEST_HELPERS_H) */
+void hs_helper_add_client_auth(const ed25519_public_key_t *service_pk,
+ const curve25519_secret_key_t *client_sk);
+#endif /* !defined(TOR_HS_TEST_HELPERS_H) */
diff --git a/src/test/include.am b/src/test/include.am
index d8e25dea9f..e7647260c5 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -37,7 +37,8 @@ TESTSCRIPTS += \
src/test/test_ntor.sh \
src/test/test_hs_ntor.sh \
src/test/test_bt.sh \
- scripts/maint/practracker/test_practracker.sh
+ scripts/maint/practracker/test_practracker.sh \
+ scripts/maint/run_check_subsystem_order.sh
if COVERAGE_ENABLED
# ...
@@ -48,6 +49,11 @@ TESTSCRIPTS += src/test/test_rebind.sh
endif
endif
+if USE_PERL
+TESTSCRIPTS += \
+ scripts/maint/checkSpaceTest.sh
+endif
+
TESTS += src/test/test src/test/test-slow src/test/test-memwipe \
src/test/test_workqueue \
src/test/test_keygen.sh \
@@ -56,13 +62,25 @@ TESTS += src/test/test src/test/test-slow src/test/test-memwipe \
$(TESTSCRIPTS)
# These flavors are run using automake's test-driver and test-network.sh
-TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v2-min hs-v3-min \
- single-onion-v23
+
+# run a quick test or two
+# this test only uses IPv4
+TEST_CHUTNEY_FLAVOR_QUICK = bridges+hs-v23
# only run if we can ping6 ::1 (localhost)
+TEST_CHUTNEY_FLAVOR_QUICK_IPV6 = single-onion-v23-ipv6-md
+
+# run a basic set of tests, which only use IPv4
+TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v23-min single-onion-v23
+
+# only run if we can ping ::1 (localhost)
TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v23-ipv6-md \
single-onion-v23-ipv6-md
+
# only run if we can find a stable (or simply another) version of tor
-TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v2
+TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v23
+
+# only run if IPv6 and mixed networks are run
+TEST_CHUTNEY_FLAVORS_IPV6_MIXED = mixed+hs-v23-ipv6
### This is a lovely feature, but it requires automake >= 1.12, and Tor
### doesn't require that yet.
@@ -99,8 +117,10 @@ if UNITTESTS_ENABLED
# ADD_C_FILE: INSERT SOURCES HERE.
src_test_test_SOURCES += \
+ src/test/fakecircs.c \
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 \
@@ -122,6 +142,7 @@ src_test_test_SOURCES += \
src/test/test_checkdir.c \
src/test/test_circuitlist.c \
src/test/test_circuitmux.c \
+ src/test/test_circuitmux_ewma.c \
src/test/test_circuitbuild.c \
src/test/test_circuituse.c \
src/test/test_circuitstats.c \
@@ -159,6 +180,7 @@ src_test_test_SOURCES += \
src/test/test_hs_client.c \
src/test/test_hs_intropoint.c \
src/test/test_hs_control.c \
+ src/test/test_hs_ob.c \
src/test/test_handles.c \
src/test/test_hs_cache.c \
src/test/test_hs_descriptor.c \
@@ -175,6 +197,7 @@ src_test_test_SOURCES += \
src/test/test_oom.c \
src/test/test_oos.c \
src/test/test_options.c \
+ src/test/test_options_act.c \
src/test/test_pem.c \
src/test/test_periodic_event.c \
src/test/test_policy.c \
@@ -182,6 +205,7 @@ src_test_test_SOURCES += \
src/test/test_process_descs.c \
src/test/test_prob_distr.c \
src/test/test_procmon.c \
+ src/test/test_proto_haproxy.c \
src/test/test_proto_http.c \
src/test/test_proto_misc.c \
src/test/test_protover.c \
@@ -201,6 +225,7 @@ src_test_test_SOURCES += \
src/test/test_sendme.c \
src/test/test_shared_random.c \
src/test/test_socks.c \
+ src/test/test_stats.c \
src/test/test_status.c \
src/test/test_storagedir.c \
src/test/test_threads.c \
@@ -339,8 +364,10 @@ src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS+= \
src/test/fakechans.h \
+ src/test/fakecircs.h \
src/test/hs_test_helpers.h \
src/test/log_test_helpers.h \
+ src/test/opts_test_helpers.h \
src/test/rend_test_helpers.h \
src/test/resolve_test_helpers.h \
src/test/rng_test_helpers.h \
@@ -404,6 +431,7 @@ EXTRA_DIST += \
src/test/test_rebind.sh \
src/test/test_rebind.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 \
diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c
index 03c52dd6bd..5e60d6b282 100644
--- a/src/test/log_test_helpers.c
+++ b/src/test/log_test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, 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 5d1c3c1914..c2d71c6bcd 100644
--- a/src/test/log_test_helpers.h
+++ b/src/test/log_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -78,7 +78,7 @@ void mock_dump_saved_logs(void);
mock_saved_log_n_entries() == 1, \
("expected log to contain exactly 1 message \"%s\"", \
str)); \
- } while (0);
+ } while (0)
#define expect_single_log_msg_containing(str) \
do { \
@@ -86,30 +86,30 @@ void mock_dump_saved_logs(void);
mock_saved_log_n_entries() == 1 , \
("expected log to contain 1 message, containing \"%s\"",\
str)); \
- } while (0);
+ } while (0)
#define expect_no_log_msg(str) \
assert_log_predicate(!mock_saved_log_has_message(str), \
- ("expected log to not contain \"%s\"",str));
+ ("expected log to not contain \"%s\"",str))
#define expect_no_log_msg_containing(str) \
assert_log_predicate(!mock_saved_log_has_message_containing(str), \
- ("expected log to not contain \"%s\"", str));
+ ("expected log to not contain \"%s\"", str))
#define expect_log_severity(severity) \
assert_log_predicate(mock_saved_log_has_severity(severity), \
- ("expected log to contain severity " # severity));
+ ("expected log to contain severity " # severity))
#define expect_no_log_severity(severity) \
assert_log_predicate(!mock_saved_log_has_severity(severity), \
- ("expected log to not contain severity " # severity));
+ ("expected log to not contain severity " # severity))
#define expect_log_entry() \
assert_log_predicate(mock_saved_log_has_entry(), \
- ("expected log to contain entries"));
+ ("expected log to contain entries"))
#define expect_no_log_entry() \
assert_log_predicate(!mock_saved_log_has_entry(), \
- ("expected log to not contain entries"));
+ ("expected log to not contain entries"))
#endif /* !defined(TOR_LOG_TEST_HELPERS_H) */
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
index 204f05e2ad..e3307430e1 100755
--- a/src/test/ntor_ref.py
+++ b/src/test/ntor_ref.py
@@ -27,6 +27,11 @@ commands:
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import binascii
try:
import curve25519
@@ -99,7 +104,7 @@ else:
def int2byte(i):
return bytes([i])
-def kdf_rfc5869(key, salt, info, n):
+def kdf_rfc5869(key, salt, info, n):
prk = HMAC(key=salt, msg=key)
diff --git a/src/test/ope_ref.py b/src/test/ope_ref.py
index b2f7012563..61a86b57bb 100644
--- a/src/test/ope_ref.py
+++ b/src/test/ope_ref.py
@@ -4,6 +4,11 @@
# Reference implementation for our rudimentary OPE code, used to
# generate test vectors. See crypto_ope.c for more details.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.backends import default_backend
diff --git a/src/test/opts_test_helpers.c b/src/test/opts_test_helpers.c
new file mode 100644
index 0000000000..619ca40733
--- /dev/null
+++ b/src/test/opts_test_helpers.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file opts_testing_helpers.c
+ * @brief Helper functions to access module-specific config options.
+ **/
+
+#include "orconfig.h"
+#include "test/opts_test_helpers.h"
+
+#define CONFIG_PRIVATE
+#include "core/or/or.h"
+#include "lib/confmgt/confmgt.h"
+#include "app/main/subsysmgr.h"
+#include "app/config/config.h"
+
+#include "lib/crypt_ops/crypto_sys.h"
+#include "feature/dirauth/dirauth_sys.h"
+
+struct dirauth_options_t *
+get_dirauth_options(struct or_options_t *opt)
+{
+ int idx = subsystems_get_options_idx(&sys_dirauth);
+ tor_assert(idx >= 0);
+ return config_mgr_get_obj_mutable(get_options_mgr(), opt, idx);
+}
+
+struct crypto_options_t *
+get_crypto_options(struct or_options_t *opt)
+{
+ int idx = subsystems_get_options_idx(&sys_crypto);
+ tor_assert(idx >= 0);
+ return config_mgr_get_obj_mutable(get_options_mgr(), opt, idx);
+}
diff --git a/src/test/opts_test_helpers.h b/src/test/opts_test_helpers.h
new file mode 100644
index 0000000000..f925194e63
--- /dev/null
+++ b/src/test/opts_test_helpers.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file opts_testing_helpers.h
+ * @brief Header for test/opts_test_helpers.c
+ **/
+
+#ifndef TOR_TEST_OPTS_TESTING_HELPERS_H
+#define TOR_TEST_OPTS_TESTING_HELPERS_H
+
+struct crypto_options_t;
+struct dirauth_options_t;
+struct or_options_t;
+
+struct crypto_options_t *get_crypto_options(struct or_options_t *opt);
+struct dirauth_options_t *get_dirauth_options(struct or_options_t *opt);
+
+#endif /* !defined(TOR_TEST_OPTS_TESTING_HELPERS_H) */
diff --git a/src/test/prob_distr_mpfr_ref.c b/src/test/prob_distr_mpfr_ref.c
index 425733dc1b..de4179c4e0 100644
--- a/src/test/prob_distr_mpfr_ref.c
+++ b/src/test/prob_distr_mpfr_ref.c
@@ -1,4 +1,4 @@
-/* Copyright 2012-2019, The Tor Project, Inc
+/* Copyright 2012-2020, 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 a55ab437fa..0e0995df7c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 7349bddd51..0999fdf5d2 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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
index f12d193cc5..61bacb4d2e 100644
--- a/src/test/rend_test_helpers.c
+++ b/src/test/rend_test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h
index c10da52cd7..b1078ce866 100644
--- a/src/test/rend_test_helpers.h
+++ b/src/test/rend_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/resolve_test_helpers.c b/src/test/resolve_test_helpers.c
index 73ea730149..ed5853c359 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e7d2e29373..ca642d6c63 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 7024fb5793..b7d7cb0dfa 100644
--- a/src/test/rng_test_helpers.c
+++ b/src/test/rng_test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 d7925148ae..6fcdaa2653 100644
--- a/src/test/rng_test_helpers.h
+++ b/src/test/rng_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_RNG_TEST_HELPERS_H
diff --git a/src/test/slow_ed25519.py b/src/test/slow_ed25519.py
index f44708b200..be4eeab857 100644
--- a/src/test/slow_ed25519.py
+++ b/src/test/slow_ed25519.py
@@ -1,5 +1,5 @@
# This is the ed25519 implementation from
-# http://ed25519.cr.yp.to/python/ed25519.py .
+# https://ed25519.cr.yp.to/python/ed25519.py .
# It is in the public domain.
#
# It isn't constant-time. Don't use it except for testing. Also, see
@@ -8,6 +8,11 @@
#
# Don't edit this file. Mess with ed25519_ref.py
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import hashlib
b = 256
diff --git a/src/test/slownacl_curve25519.py b/src/test/slownacl_curve25519.py
index 4dabab61b6..0cafe0e71f 100644
--- a/src/test/slownacl_curve25519.py
+++ b/src/test/slownacl_curve25519.py
@@ -6,10 +6,15 @@
# Nick got the slownacl source from:
# https://github.com/mdempsky/dnscurve/tree/master/slownacl
-__all__ = ['smult_curve25519_base', 'smult_curve25519']
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
import sys
+__all__ = ['smult_curve25519_base', 'smult_curve25519']
+
P = 2 ** 255 - 19
A = 486662
diff --git a/src/test/sr_commit_calc_ref.py b/src/test/sr_commit_calc_ref.py
index 45e629cfb0..c4cb72d87f 100644
--- a/src/test/sr_commit_calc_ref.py
+++ b/src/test/sr_commit_calc_ref.py
@@ -12,6 +12,11 @@
# COMMIT = base64-encode( TIMESTAMP || H(REVEAL) )
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/sr_srv_calc_ref.py b/src/test/sr_srv_calc_ref.py
index 492ca62b15..a3752b15cc 100644
--- a/src/test/sr_srv_calc_ref.py
+++ b/src/test/sr_srv_calc_ref.py
@@ -10,6 +10,11 @@
# HASHED_REVEALS | previous_SRV)
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c
index 3f952e484f..4faf7bc5a1 100644
--- a/src/test/test-memwipe.c
+++ b/src/test/test-memwipe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, 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 eb28ad90e9..f5a1f1a54e 100644
--- a/src/test/test-process.c
+++ b/src/test/test-process.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2019, The Tor Project, Inc. */
+/* Copyright (c) 2011-2020, 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 c80fb1e305..18e2191a09 100644
--- a/src/test/test-timers.c
+++ b/src/test/test-timers.c
@@ -1,4 +1,4 @@
-/* Copyright 2016-2019, The Tor Project, Inc. */
+/* Copyright 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -59,7 +59,7 @@ main(int argc, char **argv)
{
(void)argc;
(void)argv;
- tor_libevent_cfg cfg;
+ tor_libevent_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
tor_libevent_initialize(&cfg);
timers_initialize();
diff --git a/src/test/test.c b/src/test/test.c
index 6dbec26fa8..4b6082ce4f 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,6 +1,6 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -55,7 +55,6 @@
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_tap.h"
#include "core/or/policies.h"
-#include "feature/stats/rephist.h"
#include "app/config/statefile.h"
#include "lib/crypt_ops/crypto_curve25519.h"
@@ -639,166 +638,6 @@ test_rend_fns(void *arg)
tor_free(intro_points_encrypted);
}
-/** Run unit tests for stats code. */
-static void
-test_stats(void *arg)
-{
- time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- char *s = NULL;
- int i;
-
- /* Start with testing exit port statistics; we shouldn't collect exit
- * stats without initializing them. */
- (void)arg;
- rep_hist_note_exit_stream_opened(80);
- rep_hist_note_exit_bytes(80, 100, 10000);
- s = rep_hist_format_exit_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats, note some streams and bytes, and generate history
- * string. */
- rep_hist_exit_stats_init(now);
- rep_hist_note_exit_stream_opened(80);
- rep_hist_note_exit_bytes(80, 100, 10000);
- rep_hist_note_exit_stream_opened(443);
- rep_hist_note_exit_bytes(443, 100, 10000);
- rep_hist_note_exit_bytes(443, 100, 10000);
- s = rep_hist_format_exit_stats(now + 86400);
- tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "exit-kibibytes-written 80=1,443=1,other=0\n"
- "exit-kibibytes-read 80=10,443=20,other=0\n"
- "exit-streams-opened 80=4,443=4,other=0\n",OP_EQ, s);
- tor_free(s);
-
- /* Add a few bytes on 10 more ports and ensure that only the top 10
- * ports are contained in the history string. */
- for (i = 50; i < 60; i++) {
- rep_hist_note_exit_bytes(i, i, i);
- rep_hist_note_exit_stream_opened(i);
- }
- s = rep_hist_format_exit_stats(now + 86400);
- tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "exit-kibibytes-written 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
- "59=1,80=1,443=1,other=1\n"
- "exit-kibibytes-read 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
- "59=1,80=10,443=20,other=1\n"
- "exit-streams-opened 52=4,53=4,54=4,55=4,56=4,57=4,58=4,"
- "59=4,80=4,443=4,other=4\n",OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting stats, add some bytes, and ensure we don't generate
- * a history string. */
- rep_hist_exit_stats_term();
- rep_hist_note_exit_bytes(80, 100, 10000);
- s = rep_hist_format_exit_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Re-start stats, add some bytes, reset stats, and see what history we
- * get when observing no streams or bytes at all. */
- rep_hist_exit_stats_init(now);
- rep_hist_note_exit_stream_opened(80);
- rep_hist_note_exit_bytes(80, 100, 10000);
- rep_hist_reset_exit_stats(now);
- s = rep_hist_format_exit_stats(now + 86400);
- tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "exit-kibibytes-written other=0\n"
- "exit-kibibytes-read other=0\n"
- "exit-streams-opened other=0\n",OP_EQ, s);
- tor_free(s);
-
- /* Continue with testing connection statistics; we shouldn't collect
- * conn stats without initializing them. */
- rep_hist_note_or_conn_bytes(1, 20, 400, now);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats, note bytes, and generate history string. */
- rep_hist_conn_stats_init(now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n",OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting stats, add some bytes, and ensure we don't generate
- * a history string. */
- rep_hist_conn_stats_term();
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Re-start stats, add some bytes, reset stats, and see what history we
- * get when observing no bytes at all. */
- rep_hist_conn_stats_init(now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- rep_hist_reset_conn_stats(now);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",OP_EQ, s);
- tor_free(s);
-
- /* Continue with testing buffer statistics; we shouldn't collect buffer
- * stats without initializing them. */
- rep_hist_add_buffer_stats(2.0, 2.0, 20);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats, add statistics for a single circuit, and generate
- * the history string. */
- rep_hist_buffer_stats_init(now);
- rep_hist_add_buffer_stats(2.0, 2.0, 20);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n"
- "cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
- "0.00,0.00\n"
- "cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n"
- "cell-circuits-per-decile 1\n",OP_EQ, s);
- tor_free(s);
-
- /* Add nineteen more circuit statistics to the one that's already in the
- * history to see that the math works correctly. */
- for (i = 21; i < 30; i++)
- rep_hist_add_buffer_stats(2.0, 2.0, i);
- for (i = 20; i < 30; i++)
- rep_hist_add_buffer_stats(3.5, 3.5, i);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n"
- "cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75,"
- "2.75,2.75\n"
- "cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n"
- "cell-circuits-per-decile 2\n",OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting stats, add statistics for one circuit, and ensure we
- * don't generate a history string. */
- rep_hist_buffer_stats_term();
- rep_hist_add_buffer_stats(2.0, 2.0, 20);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Re-start stats, add statistics for one circuit, reset stats, and make
- * sure that the history has all zeros. */
- rep_hist_buffer_stats_init(now);
- rep_hist_add_buffer_stats(2.0, 2.0, 20);
- rep_hist_reset_buffer_stats(now);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n"
- "cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
- "0.00,0.00\n"
- "cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n"
- "cell-circuits-per-decile 0\n",OP_EQ, s);
-
- done:
- tor_free(s);
-}
-
#define ENT(name) \
{ #name, test_ ## name , 0, NULL, NULL }
#define FORK(name) \
@@ -812,7 +651,6 @@ static struct testcase_t test_array[] = {
{ "fast_handshake", test_fast_handshake, 0, NULL, NULL },
FORK(circuit_timeout),
FORK(rend_fns),
- FORK(stats),
END_OF_TESTCASES
};
@@ -836,6 +674,7 @@ struct testgroup_t testgroups[] = {
{ "circuitpadding/", circuitpadding_tests },
{ "circuitlist/", circuitlist_tests },
{ "circuitmux/", circuitmux_tests },
+ { "circuitmux_ewma/", circuitmux_ewma_tests },
{ "circuitstats/", circuitstats_tests },
{ "circuituse/", circuituse_tests },
{ "compat/libevent/", compat_libevent_tests },
@@ -882,6 +721,7 @@ struct testgroup_t testgroups[] = {
{ "hs_dos/", hs_dos_tests },
{ "hs_intropoint/", hs_intropoint_tests },
{ "hs_ntor/", hs_ntor_tests },
+ { "hs_ob/", hs_ob_tests },
{ "hs_service/", hs_service_tests },
{ "introduce/", introduce_tests },
{ "keypin/", keypin_tests },
@@ -893,12 +733,14 @@ struct testgroup_t testgroups[] = {
{ "oom/", oom_tests },
{ "oos/", oos_tests },
{ "options/", options_tests },
+ { "options/act/", options_act_tests },
{ "parsecommon/", parsecommon_tests },
{ "periodic-event/" , periodic_event_tests },
{ "policy/" , policy_tests },
{ "prob_distr/", prob_distr_tests },
{ "procmon/", procmon_tests },
{ "process/", process_tests },
+ { "proto/haproxy/", proto_haproxy_tests },
{ "proto/http/", proto_http_tests },
{ "proto/misc/", proto_misc_tests },
{ "protover/", protover_tests },
@@ -918,6 +760,7 @@ struct testgroup_t testgroups[] = {
{ "sendme/", sendme_tests },
{ "shared-random/", sr_tests },
{ "socks/", socks_tests },
+ { "stats/", stats_tests },
{ "status/" , status_tests },
{ "storagedir/", storagedir_tests },
{ "token_bucket/", token_bucket_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 76c4c0ec75..18987719d0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_H
@@ -37,6 +37,7 @@
#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, OP_EQ, hex)
+#ifndef COCCI
#define tt_double_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%g", \
TT_EXIT_TEST_FUNCTION)
@@ -64,6 +65,7 @@
tt_assert_test_fmt_type(a,b,#a" "#op" "#b,int64_t,(val1_ op val2_), \
int64_t, "%"PRId64, \
{print_ = (int64_t) value_;}, {}, TT_EXIT_TEST_FUNCTION)
+#endif /* !defined(COCCI) */
/**
* Declare that the test is done, even though no tt___op() calls were made.
@@ -79,99 +81,6 @@ struct crypto_pk_t *pk_generate(int idx);
void init_pregenerated_keys(void);
void free_pregenerated_keys(void);
-#define US2_CONCAT_2__(a, b) a ## __ ## b
-#define US_CONCAT_2__(a, b) a ## _ ## b
-#define US_CONCAT_3__(a, b, c) a ## _ ## b ## _ ## c
-#define US_CONCAT_2_(a, b) US_CONCAT_2__(a, b)
-#define US_CONCAT_3_(a, b, c) US_CONCAT_3__(a, b, c)
-
-/*
- * These macros are helpful for streamlining the authorship of several test
- * cases that use mocks.
- *
- * The pattern is as follows.
- * * Declare a top level namespace:
- * #define NS_MODULE foo
- *
- * * For each test case you want to write, create a new submodule in the
- * namespace. All mocks and other information should belong to a single
- * submodule to avoid interference with other test cases.
- * You can simply name the submodule after the function in the module you
- * are testing:
- * #define NS_SUBMODULE some_function
- * or, if you're wanting to write several tests against the same function,
- * ie., you are testing an aspect of that function, you can use:
- * #define NS_SUBMODULE ASPECT(some_function, behavior)
- *
- * * Declare all the mocks you will use. The NS_DECL macro serves to declare
- * the mock in the current namespace (defined by NS_MODULE and NS_SUBMODULE).
- * It behaves like MOCK_DECL:
- * NS_DECL(int, dependent_function, (void *));
- * Here, dependent_function must be declared and implemented with the
- * MOCK_DECL and MOCK_IMPL macros. The NS_DECL macro also defines an integer
- * global for use for tracking how many times a mock was called, and can be
- * accessed by CALLED(mock_name). For example, you might put
- * CALLED(dependent_function)++;
- * in your mock body.
- *
- * * Define a function called NS(main) that will contain the body of the
- * test case. The NS macro can be used to reference a name in the current
- * namespace.
- *
- * * In NS(main), indicate that a mock function in the current namespace,
- * declared with NS_DECL is to override that in the global namespace,
- * with the NS_MOCK macro:
- * NS_MOCK(dependent_function)
- * Unmock with:
- * NS_UNMOCK(dependent_function)
- *
- * * Define the mocks with the NS macro, eg.,
- * int
- * NS(dependent_function)(void *)
- * {
- * CALLED(dependent_function)++;
- * }
- *
- * * In the struct testcase_t array, you can use the TEST_CASE and
- * TEST_CASE_ASPECT macros to define the cases without having to do so
- * explicitly nor without having to reset NS_SUBMODULE, eg.,
- * struct testcase_t foo_tests[] = {
- * TEST_CASE_ASPECT(some_function, behavior),
- * ...
- * END_OF_TESTCASES
- * which will define a test case named "some_function__behavior".
- */
-
-#define NAME_TEST_(name) #name
-#define NAME_TEST(name) NAME_TEST_(name)
-#define ASPECT(test_module, test_name) US2_CONCAT_2__(test_module, test_name)
-#define TEST_CASE(function) \
- { \
- NAME_TEST(function), \
- NS_FULL(NS_MODULE, function, test_main), \
- TT_FORK, \
- NULL, \
- NULL, \
- }
-#define TEST_CASE_ASPECT(function, aspect) \
- { \
- NAME_TEST(ASPECT(function, aspect)), \
- NS_FULL(NS_MODULE, ASPECT(function, aspect), test_main), \
- TT_FORK, \
- NULL, \
- NULL, \
- }
-
-#define NS(name) US_CONCAT_3_(NS_MODULE, NS_SUBMODULE, name)
-#define NS_FULL(module, submodule, name) US_CONCAT_3_(module, submodule, name)
-
-#define CALLED(mock_name) US_CONCAT_2_(NS(mock_name), called)
-#define NS_DECL(retval, mock_fn, args) \
- extern int CALLED(mock_fn); \
- static retval NS(mock_fn) args; int CALLED(mock_fn) = 0
-#define NS_MOCK(name) MOCK(name, NS(name))
-#define NS_UNMOCK(name) UNMOCK(name)
-
extern const struct testcase_setup_t passthrough_setup;
extern const struct testcase_setup_t ed25519_test_setup;
@@ -193,6 +102,7 @@ extern struct testcase_t checkdir_tests[];
extern struct testcase_t circuitbuild_tests[];
extern struct testcase_t circuitlist_tests[];
extern struct testcase_t circuitmux_tests[];
+extern struct testcase_t circuitmux_ewma_tests[];
extern struct testcase_t circuitstats_tests[];
extern struct testcase_t circuituse_tests[];
extern struct testcase_t compat_libevent_tests[];
@@ -231,6 +141,7 @@ extern struct testcase_t hs_descriptor[];
extern struct testcase_t hs_dos_tests[];
extern struct testcase_t hs_intropoint_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[];
@@ -245,6 +156,7 @@ extern struct testcase_t nodelist_tests[];
extern struct testcase_t oom_tests[];
extern struct testcase_t oos_tests[];
extern struct testcase_t options_tests[];
+extern struct testcase_t options_act_tests[];
extern struct testcase_t parsecommon_tests[];
extern struct testcase_t pem_tests[];
extern struct testcase_t periodic_event_tests[];
@@ -254,6 +166,7 @@ extern struct testcase_t slow_stochastic_prob_distr_tests[];
extern struct testcase_t procmon_tests[];
extern struct testcase_t process_tests[];
extern struct testcase_t process_descs_tests[];
+extern struct testcase_t proto_haproxy_tests[];
extern struct testcase_t proto_http_tests[];
extern struct testcase_t proto_misc_tests[];
extern struct testcase_t protover_tests[];
@@ -273,6 +186,7 @@ extern struct testcase_t scheduler_tests[];
extern struct testcase_t sendme_tests[];
extern struct testcase_t socks_tests[];
extern struct testcase_t sr_tests[];
+extern struct testcase_t stats_tests[];
extern struct testcase_t status_tests[];
extern struct testcase_t storagedir_tests[];
extern struct testcase_t thread_tests[];
diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c
index 8ae8fe4343..7933df5e35 100644
--- a/src/test/test_accounting.c
+++ b/src/test/test_accounting.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -11,19 +11,16 @@
#include "app/config/or_state_st.h"
-#define NS_MODULE accounting
-
-#define NS_SUBMODULE limits
-
/*
* Test to make sure accounting triggers hibernation
* correctly with both sum or max rules set
*/
static or_state_t *or_state;
-NS_DECL(or_state_t *, get_or_state, (void));
+static or_state_t * acct_limits_get_or_state(void);
+ATTR_UNUSED static int acct_limits_get_or_state_called = 0;
static or_state_t *
-NS(get_or_state)(void)
+acct_limits_get_or_state(void)
{
return or_state;
}
@@ -35,7 +32,8 @@ test_accounting_limits(void *arg)
time_t fake_time = time(NULL);
(void) arg;
- NS_MOCK(get_or_state);
+ MOCK(get_or_state,
+ acct_limits_get_or_state);
or_state = or_state_new();
options->AccountingMax = 100;
@@ -94,12 +92,10 @@ test_accounting_limits(void *arg)
goto done;
done:
- NS_UNMOCK(get_or_state);
+ UNMOCK(get_or_state);
or_state_free(or_state);
}
-#undef NS_SUBMODULE
-
struct testcase_t accounting_tests[] = {
{ "bwlimits", test_accounting_limits, TT_FORK, NULL, NULL },
END_OF_TESTCASES
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index c89c6e78d4..cf5aad7e71 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESSMAP_PRIVATE
@@ -52,6 +52,7 @@ test_addr_basic(void *arg)
;
}
+#ifndef COCCI
#define test_op_ip6_(a,op,b,e1,e2) \
STMT_BEGIN \
tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \
@@ -69,6 +70,7 @@ test_addr_basic(void *arg)
TT_EXIT_TEST_FUNCTION \
); \
STMT_END
+#endif /* !defined(COCCI) */
/** Helper: Assert that two strings both decode as IPv6 addresses with
* tor_inet_pton(), and both decode to the same address. */
@@ -108,9 +110,10 @@ test_addr_basic(void *arg)
tt_int_op(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), OP_EQ, 1); \
t1.family = AF_INET6; \
if (tor_addr_is_internal(&t1, for_listening)) \
- TT_DIE(("%s was not internal", a)); \
+ TT_DIE(("%s was internal", a)); \
STMT_END
+#ifndef COCCI
/** Helper: Assert that <b>a</b> and <b>b</b>, when parsed by
* tor_inet_pton(), give addresses that compare in the order defined by
* <b>op</b> with tor_addr_compare(). */
@@ -135,6 +138,7 @@ test_addr_basic(void *arg)
TT_DIE(("Failed: tor_addr_compare_masked(%s,%s,%d) %s 0", \
a, b, m, #op)); \
STMT_END
+#endif /* !defined(COCCI) */
/** Helper: assert that <b>xx</b> is parseable as a masked IPv6 address with
* ports by tor_parse_mask_addr_ports(), with family <b>f</b>, IP address
@@ -655,12 +659,7 @@ test_addr_ip6_helpers(void *arg)
tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010202);
r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2);
- tt_int_op(r, OP_EQ, AF_INET);
- tt_int_op(mask,OP_EQ,32);
- tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
- tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x03041020);
- tt_uint_op(port1, OP_EQ, 1);
- tt_uint_op(port2, OP_EQ, 2);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
tt_int_op(r, OP_EQ, AF_INET);
tt_int_op(mask,OP_EQ,17);
@@ -1649,8 +1648,163 @@ test_addr_rfc6598(void *arg)
;
}
+#define TEST_ADDR_ATON(a, rv) STMT_BEGIN \
+ struct in_addr addr; \
+ tt_int_op(tor_inet_aton(a, &addr), OP_EQ, rv); \
+ STMT_END;
+
+static void
+test_addr_octal(void *arg)
+{
+ (void)arg;
+
+ /* Test non-octal IP addresses. */
+ TEST_ADDR_ATON("0.1.2.3", 1);
+ TEST_ADDR_ATON("1.0.2.3", 1);
+ TEST_ADDR_ATON("1.2.3.0", 1);
+
+ /* Test octal IP addresses. */
+ TEST_ADDR_ATON("01.1.2.3", 0);
+ TEST_ADDR_ATON("1.02.3.4", 0);
+ TEST_ADDR_ATON("1.2.3.04", 0);
+ done:
+ ;
+}
+
+#define get_ipv4(test_addr, str, iprv) STMT_BEGIN \
+ test_addr = tor_malloc(sizeof(tor_addr_t)); \
+ test_addr->family = AF_INET; \
+ iprv = tor_inet_aton(str, &test_addr->addr.in_addr); \
+ tor_assert(iprv); \
+ STMT_END;
+
+#define get_ipv6(test_addr, str, iprv) STMT_BEGIN \
+ test_addr = tor_malloc(sizeof(tor_addr_t)); \
+ test_addr->family = AF_INET6; \
+ iprv = tor_inet_pton(AF_INET6, str, &test_addr->addr.in6_addr); \
+ tor_assert(iprv); \
+ STMT_END;
+
+#define get_af_unix(test_addr) STMT_BEGIN \
+ test_addr = tor_malloc_zero(sizeof(tor_addr_t)); \
+ test_addr->family = AF_UNIX; \
+ STMT_END;
+
+#define get_af_unspec(test_addr) STMT_BEGIN \
+ test_addr = tor_malloc_zero(sizeof(tor_addr_t)); \
+ test_addr->family = AF_UNSPEC; \
+ STMT_END;
+
+#define TEST_ADDR_VALIDITY(a, lis, rv) STMT_BEGIN \
+ tor_assert(a); \
+ tt_int_op(tor_addr_is_valid(a, lis), OP_EQ, rv); \
+ STMT_END;
+
+/* Here we can change the addresses we are testing for. */
+#define IP4_TEST_ADDR "123.98.45.1"
+#define IP6_TEST_ADDR "2001:0DB8:AC10:FE01::"
+
+static void
+test_addr_is_valid(void *arg)
+{
+ (void)arg;
+ tor_addr_t *test_addr;
+ int iprv;
+
+ /* Tests for IPv4 addresses. */
+
+ /* Test for null IPv4 address. */
+ get_ipv4(test_addr, "0.0.0.0", iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv4 address. */
+ get_ipv4(test_addr, IP4_TEST_ADDR, iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 1);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Tests for IPv6 addresses. */
+
+ /* Test for null IPv6 address. */
+ get_ipv6(test_addr, "::", iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv6 address. */
+ get_ipv6(test_addr, IP6_TEST_ADDR, iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 1);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for address of type AF_UNIX. */
+
+ get_af_unix(test_addr);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 0);
+ tor_free(test_addr);
+
+ /* Test for address of type AF_UNSPEC. */
+
+ get_af_unspec(test_addr);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 0);
+
+ done:
+ tor_free(test_addr);
+}
+
+#define TEST_ADDR_IS_NULL(a, rv) STMT_BEGIN \
+ tor_assert(a); \
+ tt_int_op(tor_addr_is_null(a), OP_EQ, rv); \
+ STMT_END;
+
+static void
+test_addr_is_null(void *arg)
+{
+ (void)arg;
+ tor_addr_t *test_addr;
+ int iprv;
+
+ /* Test for null IPv4. */
+ get_ipv4(test_addr, "0.0.0.0", iprv);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv4. */
+ get_ipv4(test_addr, IP4_TEST_ADDR, iprv);
+ TEST_ADDR_IS_NULL(test_addr, 0);
+ tor_free(test_addr);
+
+ /* Test for null IPv6. */
+ get_ipv6(test_addr, "::", iprv);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv6. */
+ get_ipv6(test_addr, IP6_TEST_ADDR, iprv);
+ TEST_ADDR_IS_NULL(test_addr, 0);
+ tor_free(test_addr);
+
+ /* Test for address family AF_UNIX. */
+ get_af_unix(test_addr);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for address family AF_UNSPEC. */
+ get_af_unspec(test_addr);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+
+ done:
+ tor_free(test_addr);
+}
+
+#ifndef COCCI
#define ADDR_LEGACY(name) \
{ #name, test_addr_ ## name , 0, NULL, NULL }
+#endif
struct testcase_t addr_tests[] = {
ADDR_LEGACY(basic),
@@ -1665,5 +1819,8 @@ struct testcase_t addr_tests[] = {
{ "is_loopback", test_addr_is_loopback, 0, NULL, NULL },
{ "make_null", test_addr_make_null, 0, NULL, NULL },
{ "rfc6598", test_addr_rfc6598, 0, NULL, NULL },
+ { "octal", test_addr_octal, 0, NULL, NULL },
+ { "address_validity", test_addr_is_valid, 0, NULL, NULL },
+ { "address_is_null", test_addr_is_null, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_address.c b/src/test/test_address.c
index 32fb4aa232..4cedbda347 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESS_PRIVATE
@@ -460,7 +460,7 @@ test_address_ifreq_to_smartlist(void *arg)
ifc->ifc_len = sizeof(struct ifreq);
ifc->ifc_ifcu.ifcu_req = ifr;
- results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
+ results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len);
tt_int_op(smartlist_len(results),OP_EQ,1);
tor_addr = smartlist_get(results, 0);
@@ -483,7 +483,7 @@ test_address_ifreq_to_smartlist(void *arg)
SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
smartlist_free(results);
- results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
+ results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len);
tt_int_op(smartlist_len(results),OP_EQ,2);
tor_addr = smartlist_get(results, 0);
diff --git a/src/test/test_address_set.c b/src/test/test_address_set.c
index 6e299d779e..829ecd79e8 100644
--- a/src/test/test_address_set.c
+++ b/src/test/test_address_set.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, 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 879ae6636b..f1624a529d 100644
--- a/src/test/test_bridges.c
+++ b/src/test/test_bridges.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -550,8 +550,6 @@ test_bridges_get_transport_by_bridge_addrport_no_ptlist(void *arg)
sweep_bridge_list();
}
-#define PT_PRIVATE
-
/**
* Calling get_transport_by_bridge_addrport() with the address and port of a
* configured bridge which uses a pluggable transport should return 0 and set
diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c
index b29c2c6cbc..5f9a88705c 100644
--- a/src/test/test_bt_cl.c
+++ b/src/test/test_bt_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -33,7 +33,7 @@ int a_tangled_web(int x) NOINLINE;
int we_weave(int x) NOINLINE;
#ifdef HAVE_CFLAG_WNULL_DEREFERENCE
-DISABLE_GCC_WARNING(null-dereference)
+DISABLE_GCC_WARNING("-Wnull-dereference")
#endif
int
crash(int x)
@@ -55,7 +55,7 @@ crash(int x)
return crashtype;
}
#ifdef HAVE_CFLAG_WNULL_DEREFERENCE
-ENABLE_GCC_WARNING(null-dereference)
+ENABLE_GCC_WARNING("-Wnull-dereference")
#endif
int
diff --git a/src/test/test_btrack.c b/src/test/test_btrack.c
index 80da7829ae..2b2f34fc23 100644
--- a/src/test/test_btrack.c
+++ b/src/test/test_btrack.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, 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 3084c19d74..fbaa628fd7 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 e6f028ed74..117783cafc 100644
--- a/src/test/test_bwmgt.c
+++ b/src/test/test_bwmgt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,12 +8,14 @@
#define CONFIG_PRIVATE
#define CONNECTION_PRIVATE
+#define DIRAUTH_SYS_PRIVATE
#define TOKEN_BUCKET_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
+#include "feature/dirauth/dirauth_sys.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
@@ -26,6 +28,7 @@
#include "app/config/or_options_st.h"
#include "core/or/connection_st.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/routerinfo_st.h"
@@ -277,6 +280,7 @@ test_bwmgt_dir_conn_global_write_low(void *arg)
connection_t *conn = NULL;
routerstatus_t *rs = NULL; microdesc_t *md = NULL; routerinfo_t *ri = NULL;
tor_addr_t relay_addr;
+ dirauth_options_t *dirauth_opts = NULL;
(void) arg;
@@ -329,6 +333,10 @@ test_bwmgt_dir_conn_global_write_low(void *arg)
nodelist_set_consensus(dummy_ns);
+ dirauth_opts = tor_malloc_zero(sizeof(dirauth_options_t));
+ dirauth_opts->AuthDirRejectRequestsUnderLoad = 0;
+ dirauth_set_options(dirauth_opts);
+
/* Ok, now time to control which options we use. */
MOCK(get_options, mock_get_options);
@@ -365,7 +373,7 @@ test_bwmgt_dir_conn_global_write_low(void *arg)
/* Now, we will reject requests under load so try again a non authority non
* relay IP thus a client. We should get a warning that our limit is too
* low. */
- mock_options.AuthDirRejectRequestsUnderLoad = 1;
+ dirauth_opts->AuthDirRejectRequestsUnderLoad = 1;
addr_family = tor_addr_parse(&conn->addr, "1.1.1.1");
tt_int_op(addr_family, OP_EQ, AF_INET);
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index fc5367557d..f9ff101c98 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -713,16 +713,20 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op(cc->onionskin,OP_EQ, b, 99+20);
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
- /* We'll generate it minus the IPv6 address and minus the konami code */
- tt_int_op(p2_len, OP_EQ, 89+99-34-20);
+ /* We'll generate it minus the konami code */
+ tt_int_op(p2_len, OP_EQ, 89+99-34);
test_memeq_hex(p2,
- /* Two items: one that same darn IP address. */
- "02000612F40001F0F1"
- /* The next is a digest : anthropomorphization */
- "0214616e7468726f706f6d6f727068697a6174696f6e"
+ /* Three items */
+ "03"
+ /* IPv4 address */
+ "0006" "12F40001" "F0F1"
+ /* The next is an RSA digest: anthropomorphization */
+ "0214" "616e7468726f706f6d6f727068697a6174696f6e"
+ /*IPv6 address */
+ "0112" "20020000000000000000000000f0c51e" "1112"
/* Now the handshake prologue */
"01050063");
- tt_mem_op(p2+1+8+22+4,OP_EQ, b, 99+20);
+ tt_mem_op(p2+1+8+22+20+4, OP_EQ, b, 99+20);
tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
/* Now let's add an ed25519 key to that extend2 cell. */
@@ -732,22 +736,31 @@ test_cfmt_extend_cells(void *arg)
/* As before, since we aren't extending by ed25519. */
get_options_mutable()->ExtendByEd25519ID = 0;
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(p2_len, OP_EQ, 89+99-34-20);
+ tt_int_op(p2_len, OP_EQ, 89+99-34);
test_memeq_hex(p2,
- "02000612F40001F0F1"
+ "03"
+ "000612F40001F0F1"
"0214616e7468726f706f6d6f727068697a6174696f6e"
+ "011220020000000000000000000000f0c51e1112"
"01050063");
/* Now try with the ed25519 ID. */
get_options_mutable()->ExtendByEd25519ID = 1;
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(p2_len, OP_EQ, 89+99-34-20 + 34);
+ tt_int_op(p2_len, OP_EQ, 89+99);
test_memeq_hex(p2,
- "03000612F40001F0F1"
+ /* Four items */
+ "04"
+ /* IPv4 address */
+ "0006" "12F40001" "F0F1"
+ /* The next is an RSA digest: anthropomorphization */
"0214616e7468726f706f6d6f727068697a6174696f6e"
- // ed digest follows:
+ /* Then an ed public key: brownshoesdontmakeit/brownshoesd */
"0320" "62726f776e73686f6573646f6e746d616b656"
"9742f62726f776e73686f657364"
+ /*IPv6 address */
+ "0112" "20020000000000000000000000f0c51e" "1112"
+ /* Now the handshake prologue */
"01050063");
/* Can we parse that? Did the key come through right? */
memset(&ec, 0, sizeof(ec));
@@ -756,6 +769,40 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op("brownshoesdontmakeit/brownshoesd", OP_EQ,
ec.ed_pubkey.pubkey, 32);
+ /* Now try IPv6 without IPv4 */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02", 1);
+ memcpy(p+1, "\x02\x14" "anthropomorphization", 22);
+ memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 20);
+ memcpy(p+43, "\xff\xff\x00\x20", 4);
+ tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ tt_int_op(RELAY_COMMAND_EXTEND2, OP_EQ, ec.cell_type);
+ tt_assert(fast_mem_is_zero((const char *)&ec.orport_ipv4.addr,
+ sizeof(tor_addr_t)));
+ tt_int_op(0, OP_EQ, ec.orport_ipv4.port);
+ tt_str_op("7878:7878:7878:7878:7878:7878:7878:7878",
+ OP_EQ, fmt_addr(&ec.orport_ipv6.addr));
+ tt_int_op(22873, OP_EQ, ec.orport_ipv6.port);
+ tt_assert(ed25519_public_key_is_zero(&ec.ed_pubkey));
+ tt_mem_op(ec.node_id,OP_EQ, "anthropomorphization", 20);
+ tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, OP_EQ, 0xffff);
+ tt_int_op(cc->handshake_len, OP_EQ, 32);
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
+ tt_int_op(p2_len, OP_EQ, 47+32);
+ test_memeq_hex(p2,
+ /* Two items */
+ "02"
+ /* The next is an RSA digest: anthropomorphization */
+ "0214" "616e7468726f706f6d6f727068697a6174696f6e"
+ /*IPv6 address */
+ "0112" "78787878787878787878787878787878" "5959"
+ /* Now the handshake prologue */
+ "ffff0020");
+ tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
+
/* == Now try parsing some junk */
/* Try a too-long handshake */
@@ -811,13 +858,6 @@ test_cfmt_extend_cells(void *arg)
memcpy(p+48, "\xff\xff\x00\x20", 4);
tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
- memset(p, 0, sizeof(p));
- memcpy(p, "\x02", 1);
- memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
- memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
- memcpy(p+41, "\xff\xff\x00\x20", 4);
- tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
- p, sizeof(p)));
/* Running out of space in specifiers */
memset(p,0,sizeof(p));
diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c
index 8fc1da031e..b778c07802 100644
--- a/src/test/test_cell_queue.c
+++ b/src/test/test_cell_queue.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, 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 6a6bc9d810..83b69cc80b 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -1,8 +1,8 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define TOR_CHANNEL_INTERNAL_
-#define CHANNEL_PRIVATE_
+#define CHANNEL_OBJECT_PRIVATE
+#define CHANNEL_FILE_PRIVATE
#include "core/or/or.h"
#include "core/or/channel.h"
/* For channel_note_destroy_not_pending */
@@ -34,8 +34,6 @@
static int test_chan_accept_cells = 0;
static int test_chan_fixed_cells_recved = 0;
static cell_t * test_chan_last_seen_fixed_cell_ptr = NULL;
-static int test_chan_var_cells_recved = 0;
-static var_cell_t * test_chan_last_seen_var_cell_ptr = NULL;
static int test_cells_written = 0;
static int test_doesnt_want_writes_count = 0;
static int test_dumpstats_calls = 0;
@@ -46,7 +44,6 @@ static int dump_statistics_mock_matches = 0;
static int test_close_called = 0;
static int test_chan_should_be_canonical = 0;
static int test_chan_should_match_target = 0;
-static int test_chan_canonical_should_be_reliable = 0;
static int test_chan_listener_close_fn_called = 0;
static int test_chan_listener_fn_called = 0;
@@ -113,24 +110,6 @@ chan_test_dumpstats(channel_t *ch, int severity)
return;
}
-/*
- * Handle an incoming variable-size cell for unit tests
- */
-
-static void
-chan_test_var_cell_handler(channel_t *ch,
- var_cell_t *var_cell)
-{
- tt_assert(ch);
- tt_assert(var_cell);
-
- test_chan_last_seen_var_cell_ptr = var_cell;
- ++test_chan_var_cells_recved;
-
- done:
- return;
-}
-
static void
chan_test_close(channel_t *ch)
{
@@ -357,14 +336,10 @@ scheduler_release_channel_mock(channel_t *ch)
}
static int
-test_chan_is_canonical(channel_t *chan, int req)
+test_chan_is_canonical(channel_t *chan)
{
tor_assert(chan);
- if (req && test_chan_canonical_should_be_reliable) {
- return 1;
- }
-
if (test_chan_should_be_canonical) {
return 1;
}
@@ -492,11 +467,8 @@ test_channel_dumpstats(void *arg)
/* Receive path */
channel_set_cell_handlers(ch,
- chan_test_cell_handler,
- chan_test_var_cell_handler);
+ chan_test_cell_handler);
tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler);
- tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ,
- chan_test_var_cell_handler);
cell = tor_malloc_zero(sizeof(*cell));
old_count = test_chan_fixed_cells_recved;
channel_process_cell(ch, cell);
@@ -722,7 +694,7 @@ test_channel_inbound_cell(void *arg)
/* Setup incoming cell handlers. We don't care about var cell, the channel
* layers is not handling those. */
- channel_set_cell_handlers(chan, chan_test_cell_handler, NULL);
+ channel_set_cell_handlers(chan, chan_test_cell_handler);
tt_ptr_op(chan->cell_handler, OP_EQ, chan_test_cell_handler);
/* Now process the cell, we should see it. */
old_count = test_chan_fixed_cells_recved;
@@ -1349,7 +1321,7 @@ test_channel_for_extend(void *arg)
channel_t *ret_chan = NULL;
char digest[DIGEST_LEN];
ed25519_public_key_t ed_id;
- tor_addr_t addr;
+ tor_addr_t ipv4_addr, ipv6_addr;
const char *msg;
int launch;
time_t now = time(NULL);
@@ -1359,6 +1331,9 @@ test_channel_for_extend(void *arg)
memset(digest, 'A', sizeof(digest));
memset(&ed_id, 'B', sizeof(ed_id));
+ tor_addr_make_null(&ipv4_addr, AF_INET);
+ tor_addr_make_null(&ipv6_addr, AF_INET6);
+
chan1 = new_fake_channel();
tt_assert(chan1);
/* Need to be registered to get added to the id map. */
@@ -1380,6 +1355,9 @@ test_channel_for_extend(void *arg)
/* Make it older than chan1. */
chan2->timestamp_created = chan1->timestamp_created - 1;
+ /* Say it's all canonical. */
+ test_chan_should_be_canonical = 1;
+
/* Set channel identities and add it to the channel map. The last one to be
* added is made the first one in the list so the lookup will always return
* that one first. */
@@ -1389,7 +1367,8 @@ test_channel_for_extend(void *arg)
tt_ptr_op(channel_find_by_remote_identity(digest, &ed_id), OP_EQ, chan1);
/* The expected result is chan2 because it is older than chan1. */
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1397,16 +1376,18 @@ test_channel_for_extend(void *arg)
/* Switch that around from previous test. */
chan2->timestamp_created = chan1->timestamp_created + 1;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
/* Same creation time, num circuits will be used and they both have 0 so the
- * channel 2 should be picked due to how channel_is_better() work. */
+ * channel 2 should be picked due to how channel_is_better() works. */
chan2->timestamp_created = chan1->timestamp_created;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
@@ -1417,7 +1398,8 @@ test_channel_for_extend(void *arg)
/* Condemned the older channel. */
chan1->state = CHANNEL_STATE_CLOSING;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1426,7 +1408,8 @@ test_channel_for_extend(void *arg)
/* Make the older channel a client one. */
channel_mark_client(chan1);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1436,8 +1419,9 @@ test_channel_for_extend(void *arg)
/* Non matching ed identity with valid digest. */
ed25519_public_key_t dumb_ed_id;
memset(&dumb_ed_id, 0, sizeof(dumb_ed_id));
- ret_chan = channel_get_for_extend(digest, &dumb_ed_id, &addr, &msg,
- &launch);
+ ret_chan = channel_get_for_extend(digest, &dumb_ed_id,
+ &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Not connected. Connecting.");
tt_int_op(launch, OP_EQ, 1);
@@ -1446,7 +1430,8 @@ test_channel_for_extend(void *arg)
test_chan_should_match_target = 1;
chan1->state = CHANNEL_STATE_OPENING;
chan2->state = CHANNEL_STATE_OPENING;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connection in progress; waiting.");
tt_int_op(launch, OP_EQ, 0);
@@ -1455,7 +1440,8 @@ test_channel_for_extend(void *arg)
/* Mark channel 1 as bad for circuits. */
channel_mark_bad_for_new_circs(chan1);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1465,7 +1451,8 @@ test_channel_for_extend(void *arg)
/* Mark both channels as unusable. */
channel_mark_bad_for_new_circs(chan1);
channel_mark_bad_for_new_circs(chan2);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
@@ -1474,9 +1461,10 @@ test_channel_for_extend(void *arg)
chan2->is_bad_for_new_circs = 0;
/* Non canonical channels. */
+ test_chan_should_be_canonical = 0;
test_chan_should_match_target = 0;
- test_chan_canonical_should_be_reliable = 1;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c
index 885246628e..63a591583d 100644
--- a/src/test/test_channelpadding.c
+++ b/src/test/test_channelpadding.c
@@ -1,7 +1,7 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define MAINLOOP_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define TOR_TIMERS_PRIVATE
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index 054d3910e4..f4f5cb447e 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -1,11 +1,11 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include <math.h>
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#include "core/or/or.h"
#include "lib/net/address.h"
#include "lib/buf/buffers.h"
@@ -14,6 +14,7 @@
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
/* For init/free stuff */
#include "core/or/scheduler.h"
#include "lib/tls/tortls.h"
diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c
index 1df74c390a..186a55cc8c 100644
--- a/src/test/test_checkdir.c
+++ b/src/test/test_checkdir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, 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 7291e04d6a..03fd176ead 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
@@ -8,18 +8,32 @@
#define ENTRYNODES_PRIVATE
#include "core/or/or.h"
+
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
+
+#define CONFIG_PRIVATE
#include "app/config/config.h"
+
+#include "core/or/channel.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/onion.h"
+#include "core/or/cell_st.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
+#include "core/or/or_circuit_st.h"
#include "feature/client/entrynodes.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/relay/circuitbuild_relay.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+
+#include "feature/nodelist/node_st.h"
/* Dummy nodes smartlist for testing */
static smartlist_t dummy_nodes;
@@ -114,6 +128,14 @@ test_new_route_len_unhandled_exit(void *arg)
int r;
(void)arg;
+#ifdef ALL_BUGS_ARE_FATAL
+ /* Coverity (and maybe clang analyser) complain that the code following
+ * tt_skip() is unconditionally unreachable. */
+#if !defined(__COVERITY__) && !defined(__clang_analyzer__)
+ tt_skip();
+#endif
+#endif /* defined(ALL_BUGS_ARE_FATAL) */
+
MOCK(count_acceptable_nodes, mock_count_acceptable_nodes);
tor_capture_bugs_(1);
@@ -125,10 +147,10 @@ test_new_route_len_unhandled_exit(void *arg)
"!(exit_ei && !known_purpose)");
expect_single_log_msg_containing("Unhandled purpose");
expect_single_log_msg_containing("with a chosen exit; assuming routelen");
- teardown_capture_of_logs();
- tor_end_capture_bugs_();
done:
+ teardown_capture_of_logs();
+ tor_end_capture_bugs_();
UNMOCK(count_acceptable_nodes);
}
@@ -172,12 +194,1361 @@ test_upgrade_from_guard_wait(void *arg)
entry_guard_free_(guard);
}
+static int server = 0;
+static int
+mock_server_mode(const or_options_t *options)
+{
+ (void)options;
+ return server;
+}
+
+/* Test the different cases in circuit_extend_state_valid_helper(). */
+static void
+test_circuit_extend_state_valid(void *arg)
+{
+ (void)arg;
+ circuit_t *circ = tor_malloc_zero(sizeof(circuit_t));
+
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+ /* Clients can't extend */
+ server = 0;
+ tt_int_op(circuit_extend_state_valid_helper(NULL), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* n_chan and n_hop are NULL, this should succeed */
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ /* But clients still can't extend */
+ server = 0;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+ /* n_chan must be NULL */
+ circ->n_chan = tor_malloc_zero(sizeof(channel_t));
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("n_chan already set. Bug/attack. Closing.\n");
+ mock_clean_saved_logs();
+ tor_free(circ->n_chan);
+
+ /* n_hop must be NULL */
+ circ->n_hop = tor_malloc_zero(sizeof(extend_info_t));
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("conn to next hop already launched. Bug/attack. Closing.\n");
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(server_mode);
+ server = 0;
+
+ tor_free(circ->n_chan);
+ tor_free(circ->n_hop);
+ tor_free(circ);
+}
+
+static node_t *mocked_node = NULL;
+static const node_t *
+mock_node_get_by_id(const char *identity_digest)
+{
+ (void)identity_digest;
+ return mocked_node;
+}
+
+static int mocked_supports_ed25519_link_authentication = 0;
+static int
+mock_node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us)
+{
+ (void)node;
+ (void)compatible_with_us;
+ return mocked_supports_ed25519_link_authentication;
+}
+
+static ed25519_public_key_t * mocked_ed25519_id = NULL;
+static const ed25519_public_key_t *
+mock_node_get_ed25519_id(const node_t *node)
+{
+ (void)node;
+ return mocked_ed25519_id;
+}
+
+/* Test the different cases in circuit_extend_add_ed25519_helper(). */
+static void
+test_circuit_extend_add_ed25519(void *arg)
+{
+ (void)arg;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *old_ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *zero_ec = tor_malloc_zero(sizeof(extend_cell_t));
+
+ node_t *fake_node = tor_malloc_zero(sizeof(node_t));
+ ed25519_public_key_t *fake_ed25519_id = NULL;
+ fake_ed25519_id = tor_malloc_zero(sizeof(ed25519_public_key_t));
+
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(node_supports_ed25519_link_authentication,
+ mock_node_supports_ed25519_link_authentication);
+ MOCK(node_get_ed25519_id, mock_node_get_ed25519_id);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* The extend cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_add_ed25519_helper(NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* The node id must be non-zero */
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, -1);
+ expect_log_msg(
+ "Client asked me to extend without specifying an id_digest.\n");
+ /* And nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ mock_clean_saved_logs();
+
+ /* Fill in fake node_id, and try again */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* There's no node with that id, so the ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ mock_clean_saved_logs();
+
+ /* Provide 2 out of 3 of node, supports link auth, and ed_id.
+ * The ed_id should remain zeroed. */
+
+ /* Provide node and supports link auth */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Provide supports link auth and ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Provide node and ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Now do the real lookup */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should match */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, fake_ed25519_id, sizeof(ec->ed_pubkey));
+ /* Nothing else should have changed */
+ memcpy(&ec->ed_pubkey, &old_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Now do the real lookup, but with a zeroed ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should match */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, fake_ed25519_id, sizeof(ec->ed_pubkey));
+ /* Nothing else should have changed */
+ memcpy(&ec->ed_pubkey, &old_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ done:
+ UNMOCK(node_get_by_id);
+ UNMOCK(node_supports_ed25519_link_authentication);
+ UNMOCK(node_get_ed25519_id);
+
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ tor_free(ec);
+ tor_free(old_ec);
+ tor_free(zero_ec);
+
+ tor_free(fake_ed25519_id);
+ tor_free(fake_node);
+}
+
+static or_options_t *mocked_options = NULL;
+static const or_options_t *
+mock_get_options(void)
+{
+ return mocked_options;
+}
+
+#define PUBLIC_IPV4 "1.2.3.4"
+#define INTERNAL_IPV4 "0.0.0.1"
+
+#define PUBLIC_IPV6 "1234::cdef"
+#define INTERNAL_IPV6 "::1"
+
+#define VALID_PORT 0x1234
+
+/* Test the different cases in circuit_extend_lspec_valid_helper(). */
+static void
+test_circuit_extend_lspec_valid(void *arg)
+{
+ (void)arg;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ channel_t *p_chan = tor_malloc_zero(sizeof(channel_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ circuit_t *circ = TO_CIRCUIT(or_circ);
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Extend cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(NULL, circ), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(NULL, NULL), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* IPv4 and IPv6 addr and port are all zero, this should fail */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or unspecified address '[scrubbed]'.\n");
+ mock_clean_saved_logs();
+
+ /* Now ask for the actual address in the logs */
+ fake_options->SafeLogging_ = SAFELOG_SCRUB_NONE;
+
+ /* IPv4 port is 0, IPv6 addr and port are both zero, this should fail */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv4 address '1.2.3.4:0'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv4 addr is 0, IPv6 addr and port are both zero, this should fail */
+ ec->orport_ipv4.port = VALID_PORT;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv4 address '0.0.0.0:4660'.\n");
+ mock_clean_saved_logs();
+ ec->orport_ipv4.port = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv4 addr is internal, and port is valid.
+ * (IPv6 addr and port are both zero.)
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now do the same tests, but for IPv6 */
+
+ /* IPv6 port is 0, IPv4 addr and port are both zero, this should fail */
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv6 address '[1234::cdef]:0'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv6 addr is 0, IPv4 addr and port are both zero, this should fail */
+ ec->orport_ipv6.port = VALID_PORT;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv6 address '[::]:4660'.\n");
+ mock_clean_saved_logs();
+ ec->orport_ipv4.port = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv6 addr is internal, and port is valid.
+ * (IPv4 addr and port are both zero.)
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Both addresses are internal.
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* If we pass the private address check, but don't have the right
+ * OR circuit magic number, we trigger another bug */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 1;
+
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(circ->magic != 0x98ABC04Fu))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Fail again, but this time only set an IPv4 address. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 1;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now set the right magic */
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* If we pass the OR circuit magic check, but don't have p_chan,
+ * we trigger another bug */
+ fake_options->ExtendAllowPrivateAddresses = 1;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!p_chan))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ /* We can also pass the OR circuit magic check with a public address */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tor_addr_make_null(&ec->orport_ipv4.addr, AF_INET);
+ ec->orport_ipv4.port = 0x0000;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now let's fake a p_chan and the addresses */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ or_circ->p_chan = p_chan;
+
+ /* This is a trivial failure: node_id and p_chan->identity_digest are both
+ * zeroed */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop.\n");
+ mock_clean_saved_logs();
+
+ /* Let's check with non-zero identities as well */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0xAA, sizeof(p_chan->identity_digest));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop.\n");
+ mock_clean_saved_logs();
+
+ memset(ec->node_id, 0, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0, sizeof(p_chan->identity_digest));
+
+ /* Let's pass the node_id test */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0xBB, sizeof(p_chan->identity_digest));
+
+ /* ed_pubkey is zero, and that's allowed, so we should succeed */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ /* Now let's check that we warn, but succeed, when only one address is
+ * private */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now with private IPv6 */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now reset to public IPv4 and IPv6 */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ /* Fail on matching non-zero identities */
+ memset(&ec->ed_pubkey, 0xEE, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop "
+ "(by Ed25519 ID).\n");
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed on different, non-zero identities */
+ memset(&ec->ed_pubkey, 0xDD, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed if the client knows the identity, but we don't */
+ memset(&ec->ed_pubkey, 0xDD, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0x00, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed if we know the identity, but the client doesn't */
+ memset(&ec->ed_pubkey, 0x00, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Cleanup the node ids */
+ memset(ec->node_id, 0, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0, sizeof(p_chan->identity_digest));
+
+ /* Cleanup the p_chan and the addresses */
+ tor_addr_make_null(&ec->orport_ipv4.addr, AF_UNSPEC);
+ ec->orport_ipv4.port = 0;
+ or_circ->p_chan = NULL;
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ tor_free(ec);
+ tor_free(or_circ);
+ tor_free(p_chan);
+}
+
+static bool can_extend_over_ipv6_result = false;
+static int mock_router_can_extend_over_ipv6_calls = 0;
+static bool
+mock_router_can_extend_over_ipv6(const or_options_t *options)
+{
+ (void)options;
+ mock_router_can_extend_over_ipv6_calls++;
+ return can_extend_over_ipv6_result;
+}
+
+/* Test the different cases in circuit_choose_ip_ap_for_extend(). */
+static void
+test_circuit_choose_ip_ap_for_extend(void *arg)
+{
+ (void)arg;
+ tor_addr_port_t ipv4_ap;
+ tor_addr_port_t ipv6_ap;
+
+ /* Set up valid addresses */
+ tor_addr_parse(&ipv4_ap.addr, PUBLIC_IPV4);
+ ipv4_ap.port = VALID_PORT;
+ tor_addr_parse(&ipv6_ap.addr, PUBLIC_IPV6);
+ ipv6_ap.port = VALID_PORT;
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ MOCK(router_can_extend_over_ipv6,
+ mock_router_can_extend_over_ipv6);
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+
+ /* No valid addresses */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* One valid address: IPv4 */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* One valid address: IPv6 */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, &ipv6_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* Two valid addresses */
+ const tor_addr_port_t *chosen_addr = NULL;
+
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ chosen_addr = circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap);
+ tt_assert(chosen_addr == &ipv4_ap || chosen_addr == &ipv6_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap),
+ OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ done:
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ UNMOCK(router_can_extend_over_ipv6);
+
+ tor_free(fake_options);
+}
+
+static int mock_circuit_close_calls = 0;
+static void
+mock_circuit_mark_for_close_(circuit_t *circ, int reason,
+ int line, const char *cfile)
+{
+ (void)circ;
+ (void)reason;
+ (void)line;
+ (void)cfile;
+ mock_circuit_close_calls++;
+}
+
+static int mock_channel_connect_calls = 0;
+static channel_t *mock_channel_connect_nchan = NULL;
+static channel_t *
+mock_channel_connect_for_circuit(const tor_addr_t *addr,
+ uint16_t port,
+ const char *id_digest,
+ const struct ed25519_public_key_t *ed_id)
+{
+ (void)addr;
+ (void)port;
+ (void)id_digest;
+ (void)ed_id;
+ mock_channel_connect_calls++;
+ return mock_channel_connect_nchan;
+}
+
+/* Test the different cases in circuit_open_connection_for_extend().
+ * Chooses different IP addresses depending on the first character in arg:
+ * - 4: IPv4
+ * - 6: IPv6
+ * - d: IPv4 and IPv6 (dual-stack)
+ */
+static void
+test_circuit_open_connection_for_extend(void *arg)
+{
+ const char ip_version = ((const char *)arg)[0];
+ const bool use_ipv4 = (ip_version == '4' || ip_version == 'd');
+ const bool use_ipv6 = (ip_version == '6' || ip_version == 'd');
+ tor_assert(use_ipv4 || use_ipv6);
+
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ circuit_t *circ = tor_malloc_zero(sizeof(circuit_t));
+ channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t));
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close_);
+ mock_circuit_close_calls = 0;
+ MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+ mock_channel_connect_nchan = NULL;
+
+ MOCK(router_can_extend_over_ipv6,
+ mock_router_can_extend_over_ipv6);
+ can_extend_over_ipv6_result = true;
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(ec, NULL, 0);
+ /* We can't close a NULL circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(NULL, circ, 0);
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(NULL, NULL, 0);
+ /* We can't close a NULL circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Fail, because neither address is valid */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(ec, circ, 0);
+ /* Close the circuit, don't connect */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_EQ, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_EQ, NULL);
+ tt_int_op(circ->state, OP_EQ, 0);
+ /* Cleanup */
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Set up valid addresses */
+ if (use_ipv4) {
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ }
+ if (use_ipv6) {
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ }
+
+ /* Succeed, but don't try to open a connection */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 0);
+ /* If we haven't closed the circuit, that's success */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+
+ /* Try to open a connection, but fail with a NULL n_chan */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 1);
+ /* Try to connect, but fail, and close the circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+ expect_log_msg("Launching n_chan failed. Closing circuit.\n");
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+
+ /* Try to open a connection, and succeed, because n_chan is not NULL */
+ mock_channel_connect_nchan = fake_n_chan;
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 1);
+ /* Connection attempt succeeded, leaving the circuit open */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+ mock_channel_connect_nchan = NULL;
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(circuit_mark_for_close_);
+ mock_circuit_close_calls = 0;
+ UNMOCK(channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ UNMOCK(router_can_extend_over_ipv6);
+
+ tor_free(ec);
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ tor_free(circ);
+ tor_free(fake_n_chan);
+}
+
+/* Guaranteed to be initialised to zero. */
+static extend_cell_t mock_extend_cell_parse_cell_out;
+static int mock_extend_cell_parse_result = 0;
+static int mock_extend_cell_parse_calls = 0;
+
+static int
+mock_extend_cell_parse(extend_cell_t *cell_out,
+ const uint8_t command,
+ const uint8_t *payload_in,
+ size_t payload_len)
+{
+ (void)command;
+ (void)payload_in;
+ (void)payload_len;
+
+ mock_extend_cell_parse_calls++;
+ memcpy(cell_out, &mock_extend_cell_parse_cell_out,
+ sizeof(extend_cell_t));
+ return mock_extend_cell_parse_result;
+}
+
+static int mock_channel_get_for_extend_calls = 0;
+static int mock_channel_get_for_extend_launch_out = 0;
+static channel_t *mock_channel_get_for_extend_nchan = NULL;
+static channel_t *
+mock_channel_get_for_extend(const char *rsa_id_digest,
+ const ed25519_public_key_t *ed_id,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr,
+ const char **msg_out,
+ int *launch_out)
+{
+ (void)rsa_id_digest;
+ (void)ed_id;
+ (void)target_ipv4_addr;
+ (void)target_ipv6_addr;
+
+ /* channel_get_for_extend() requires non-NULL arguments */
+ tt_ptr_op(msg_out, OP_NE, NULL);
+ tt_ptr_op(launch_out, OP_NE, NULL);
+
+ mock_channel_get_for_extend_calls++;
+ *msg_out = NULL;
+ *launch_out = mock_channel_get_for_extend_launch_out;
+ return mock_channel_get_for_extend_nchan;
+
+ done:
+ return NULL;
+}
+
+static const char *
+mock_channel_get_canonical_remote_descr(channel_t *chan)
+{
+ (void)chan;
+ return "mock_channel_get_canonical_remote_descr()";
+}
+
+static int mock_circuit_deliver_create_cell_calls = 0;
+static int mock_circuit_deliver_create_cell_result = 0;
+static int
+mock_circuit_deliver_create_cell(circuit_t *circ,
+ const struct create_cell_t *create_cell,
+ int relayed)
+{
+ (void)create_cell;
+
+ /* circuit_deliver_create_cell() requires non-NULL arguments,
+ * but we only check circ and circ->n_chan here. */
+ tt_ptr_op(circ, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan, OP_NE, NULL);
+
+ /* We should only ever get relayed cells from extends */
+ tt_int_op(relayed, OP_EQ, 1);
+
+ mock_circuit_deliver_create_cell_calls++;
+ return mock_circuit_deliver_create_cell_result;
+
+ done:
+ return -1;
+}
+
+/* Test the different cases in circuit_extend(). */
+static void
+test_circuit_extend(void *arg)
+{
+ (void)arg;
+ cell_t *cell = tor_malloc_zero(sizeof(cell_t));
+ channel_t *p_chan = tor_malloc_zero(sizeof(channel_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ circuit_t *circ = TO_CIRCUIT(or_circ);
+ channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t));
+
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ /* Mock a debug function, but otherwise ignore it */
+ MOCK(channel_get_canonical_remote_descr,
+ mock_channel_get_canonical_remote_descr);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(cell, NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(NULL, circ), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!cell))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(NULL, NULL), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Clients can't extend */
+ server = 0;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+ /* But servers can. Unpack the cell, but fail parsing. */
+ server = 1;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ expect_log_msg("Can't parse extend cell. Closing circuit.\n");
+ mock_clean_saved_logs();
+
+ /* Now mock parsing */
+ MOCK(extend_cell_parse, mock_extend_cell_parse);
+
+ /* And make parsing succeed, but fail on adding ed25519 */
+ memset(&mock_extend_cell_parse_cell_out, 0,
+ sizeof(mock_extend_cell_parse_cell_out));
+ mock_extend_cell_parse_result = 0;
+ mock_extend_cell_parse_calls = 0;
+
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ expect_log_msg(
+ "Client asked me to extend without specifying an id_digest.\n");
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+
+ /* Now add a node_id. Fail the lspec check because IPv4 and port are zero. */
+ memset(&mock_extend_cell_parse_cell_out.node_id, 0xAA,
+ sizeof(mock_extend_cell_parse_cell_out.node_id));
+
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or unspecified address '[scrubbed]'.\n");
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+
+ /* Now add a valid IPv4 and port. Fail the OR circuit magic check. */
+ tor_addr_parse(&mock_extend_cell_parse_cell_out.orport_ipv4.addr,
+ PUBLIC_IPV4);
+ mock_extend_cell_parse_cell_out.orport_ipv4.port = VALID_PORT;
+
+#ifndef ALL_BUGS_ARE_FATAL
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(circ->magic != 0x98ABC04Fu))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now add the right magic and a p_chan. */
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->p_chan = p_chan;
+
+ /* Mock channel_get_for_extend(), so it doesn't crash. */
+ mock_channel_get_for_extend_calls = 0;
+ MOCK(channel_get_for_extend, mock_channel_get_for_extend);
+
+ /* Test circuit not established, but don't launch another one */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = NULL;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+
+ /* cleanup */
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Mock channel_connect_for_circuit(), so we don't crash */
+ mock_channel_connect_calls = 0;
+ MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit);
+
+ /* Test circuit not established, and successful launch of a channel */
+ mock_channel_get_for_extend_launch_out = 1;
+ mock_channel_get_for_extend_nchan = NULL;
+ mock_channel_connect_nchan = fake_n_chan;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+
+ /* cleanup */
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Mock circuit_deliver_create_cell(), so it doesn't crash */
+ mock_circuit_deliver_create_cell_calls = 0;
+ MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell);
+
+ /* Test circuit established, re-using channel, successful delivery */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = fake_n_chan;
+ mock_channel_connect_nchan = NULL;
+ mock_circuit_deliver_create_cell_result = 0;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(mock_circuit_deliver_create_cell_calls, OP_EQ, 1);
+ tt_ptr_op(circ->n_chan, OP_EQ, fake_n_chan);
+
+ /* cleanup */
+ circ->n_chan = NULL;
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ mock_circuit_deliver_create_cell_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Test circuit established, re-using channel, failed delivery */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = fake_n_chan;
+ mock_channel_connect_nchan = NULL;
+ mock_circuit_deliver_create_cell_result = -1;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(mock_circuit_deliver_create_cell_calls, OP_EQ, 1);
+ tt_ptr_op(circ->n_chan, OP_EQ, fake_n_chan);
+
+ /* cleanup */
+ circ->n_chan = NULL;
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ mock_circuit_deliver_create_cell_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(server_mode);
+ server = 0;
+
+ UNMOCK(channel_get_canonical_remote_descr);
+
+ UNMOCK(extend_cell_parse);
+ memset(&mock_extend_cell_parse_cell_out, 0,
+ sizeof(mock_extend_cell_parse_cell_out));
+ mock_extend_cell_parse_result = 0;
+ mock_extend_cell_parse_calls = 0;
+
+ UNMOCK(channel_get_for_extend);
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = NULL;
+
+ UNMOCK(channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+ mock_channel_connect_nchan = NULL;
+
+ UNMOCK(circuit_deliver_create_cell);
+ mock_circuit_deliver_create_cell_calls = 0;
+ mock_circuit_deliver_create_cell_result = 0;
+
+ tor_free(cell);
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ tor_free(or_circ);
+ tor_free(p_chan);
+ tor_free(fake_n_chan);
+}
+
+/* Test the different cases in onionskin_answer(). */
+static void
+test_onionskin_answer(void *arg)
+{
+ (void)arg;
+ created_cell_t *created_cell = tor_malloc_zero(sizeof(created_cell_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ char keys[CPATH_KEY_MATERIAL_LEN] = {0};
+ uint8_t rend_circ_nonce[DIGEST_LEN] = {0};
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(NULL, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Created cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, NULL,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!created_cell))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Keys must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ NULL, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!keys))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* The rend circuit nonce must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!rend_circ_nonce))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Also, the keys length must be CPATH_KEY_MATERIAL_LEN, but we can't catch
+ * asserts in unit tests. */
+
+ /* Fail when formatting the created cell */
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ expect_log_msg("couldn't format created cell (type=0, len=0).\n");
+ mock_clean_saved_logs();
+
+ /* TODO: test the rest of onionskin_answer(), see #33860 */
+ /* TODO: mock created_cell_format for the next test */
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ tor_free(created_cell);
+ tor_free(or_circ);
+}
+
+#define TEST(name, flags, setup, cleanup) \
+ { #name, test_ ## name, flags, setup, cleanup }
+
+#define TEST_NEW_ROUTE_LEN(name, flags) \
+ { #name, test_new_route_len_ ## name, flags, NULL, NULL }
+
+#define TEST_CIRCUIT(name, flags) \
+ { #name, test_circuit_ ## name, flags, NULL, NULL }
+
+#ifndef COCCI
+#define TEST_CIRCUIT_PASSTHROUGH(name, flags, arg) \
+ { #name "/" arg, test_circuit_ ## name, flags, \
+ &passthrough_setup, (void *)(arg) }
+#endif
+
struct testcase_t circuitbuild_tests[] = {
- { "noexit", test_new_route_len_noexit, 0, NULL, NULL },
- { "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL },
- { "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL },
- { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL },
- { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK,
- &helper_pubsub_setup, NULL },
+ TEST_NEW_ROUTE_LEN(noexit, 0),
+ TEST_NEW_ROUTE_LEN(safe_exit, 0),
+ TEST_NEW_ROUTE_LEN(unsafe_exit, 0),
+ TEST_NEW_ROUTE_LEN(unhandled_exit, 0),
+
+ TEST(upgrade_from_guard_wait, TT_FORK, &helper_pubsub_setup, NULL),
+
+ TEST_CIRCUIT(extend_state_valid, TT_FORK),
+ TEST_CIRCUIT(extend_add_ed25519, TT_FORK),
+ TEST_CIRCUIT(extend_lspec_valid, TT_FORK),
+ TEST_CIRCUIT(choose_ip_ap_for_extend, 0),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "4"),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "6"),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "dual-stack"),
+ TEST_CIRCUIT(extend, TT_FORK),
+
+ TEST(onionskin_answer, TT_FORK, NULL, NULL),
+
END_OF_TESTCASES
};
diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c
index 5cebdbeda0..63c4418f29 100644
--- a/src/test/test_circuitlist.c
+++ b/src/test/test_circuitlist.c
@@ -1,7 +1,7 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CIRCUITBUILD_PRIVATE
#define CIRCUITLIST_PRIVATE
#define HS_CIRCUITMAP_PRIVATE
@@ -136,7 +136,7 @@ test_clist_maps(void *arg)
channel_note_destroy_pending(ch2, 200);
channel_note_destroy_pending(ch2, 205);
channel_note_destroy_pending(ch1, 100);
- tt_assert(circuit_id_in_use_on_channel(205, ch2))
+ tt_assert(circuit_id_in_use_on_channel(205, ch2));
tt_assert(circuit_id_in_use_on_channel(200, ch2));
tt_assert(circuit_id_in_use_on_channel(100, ch1));
diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c
index a2b3e62fe8..2c11d107d0 100644
--- a/src/test/test_circuitmux.c
+++ b/src/test/test_circuitmux.c
@@ -1,33 +1,27 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CIRCUITMUX_PRIVATE
#define CIRCUITMUX_EWMA_PRIVATE
#define RELAY_PRIVATE
+
#include "core/or/or.h"
#include "core/or/channel.h"
#include "core/or/circuitmux.h"
#include "core/or/circuitmux_ewma.h"
+#include "core/or/destroy_cell_queue_st.h"
#include "core/or/relay.h"
#include "core/or/scheduler.h"
-#include "test/test.h"
-#include "core/or/destroy_cell_queue_st.h"
+#include "test/fakechans.h"
+#include "test/fakecircs.h"
+#include "test/test.h"
#include <math.h>
-/* XXXX duplicated function from test_circuitlist.c */
-static channel_t *
-new_fake_channel(void)
-{
- channel_t *chan = tor_malloc_zero(sizeof(channel_t));
- channel_init(chan);
- return chan;
-}
-
static int
-has_queued_writes(channel_t *c)
+mock_has_queued_writes_true(channel_t *c)
{
(void) c;
return 1;
@@ -44,16 +38,14 @@ test_cmux_destroy_cell_queue(void *arg)
packed_cell_t *pc = NULL;
destroy_cell_t *dc = NULL;
- scheduler_init();
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
(void) arg;
- cmux = circuitmux_alloc();
- tt_assert(cmux);
ch = new_fake_channel();
- circuitmux_set_policy(cmux, &ewma_policy);
- ch->has_queued_writes = has_queued_writes;
+ ch->has_queued_writes = mock_has_queued_writes_true;
ch->wide_circ_ids = 1;
+ cmux = ch->cmux;
circ = circuitmux_get_first_active_circuit(cmux, &cq);
tt_ptr_op(circ, OP_EQ, NULL);
@@ -78,10 +70,11 @@ test_cmux_destroy_cell_queue(void *arg)
tt_int_op(circuitmux_num_cells(cmux), OP_EQ, 2);
done:
- circuitmux_free(cmux);
- channel_free(ch);
+ free_fake_channel(ch);
packed_cell_free(pc);
tor_free(dc);
+
+ UNMOCK(scheduler_release_channel);
}
static void
@@ -125,9 +118,363 @@ test_cmux_compute_ticks(void *arg)
;
}
+static void
+test_cmux_allocate(void *arg)
+{
+ circuitmux_t *cmux = NULL;
+
+ (void) arg;
+
+ cmux = circuitmux_alloc();
+ tt_assert(cmux);
+ tt_assert(cmux->chanid_circid_map);
+ tt_int_op(HT_SIZE(cmux->chanid_circid_map), OP_EQ, 0);
+ tt_uint_op(cmux->n_circuits, OP_EQ, 0);
+ tt_uint_op(cmux->n_active_circuits, OP_EQ, 0);
+ tt_uint_op(cmux->n_cells, OP_EQ, 0);
+ tt_uint_op(cmux->last_cell_was_destroy, OP_EQ, 0);
+ tt_i64_op(cmux->destroy_ctr, OP_EQ, 0);
+ tt_ptr_op(cmux->policy, OP_EQ, NULL);
+ tt_ptr_op(cmux->policy_data, OP_EQ, NULL);
+
+ tt_assert(TOR_SIMPLEQ_EMPTY(&cmux->destroy_cell_queue.head));
+
+ done:
+ circuitmux_free(cmux);
+}
+
+static void
+test_cmux_attach_circuit(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+ cell_direction_t cdir;
+ unsigned int n_cells;
+
+ (void) arg;
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* While assigning a new circuit IDs, the circuitmux_attach_circuit() is
+ * called for a new channel on the circuit. This means, we should now have
+ * the created circuit attached on both the pchan and nchan cmux. */
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
+
+ /* There should be _no_ active circuit due to no queued cells. */
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_active_circuits(nchan->cmux), OP_EQ, 0);
+
+ /* Circuit should not be active on the cmux. */
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(nchan->cmux, circ), OP_EQ, 0);
+
+ /* Not active so no cells. */
+ n_cells = circuitmux_num_cells_for_circuit(pchan->cmux, circ);
+ tt_uint_op(n_cells, OP_EQ, 0);
+ n_cells = circuitmux_num_cells(pchan->cmux);
+ tt_uint_op(n_cells, OP_EQ, 0);
+ n_cells = circuitmux_num_cells_for_circuit(nchan->cmux, circ);
+ tt_uint_op(n_cells, OP_EQ, 0);
+ n_cells = circuitmux_num_cells(nchan->cmux);
+ tt_uint_op(n_cells, OP_EQ, 0);
+
+ /* So it should be attached :) */
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
+
+ /* Query the chanid<->circid map in the cmux subsytem with what we just
+ * created and validate the cell direction. */
+ cdir = circuitmux_attached_circuit_direction(pchan->cmux, circ);
+ tt_int_op(cdir, OP_EQ, CELL_DIRECTION_IN);
+ cdir = circuitmux_attached_circuit_direction(nchan->cmux, circ);
+ tt_int_op(cdir, OP_EQ, CELL_DIRECTION_OUT);
+
+ /*
+ * We'll activate->deactivate->activate to test all code paths of
+ * circuitmux_set_num_cells().
+ */
+
+ /* Activate circuit. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+
+ /* Deactivate. */
+ circuitmux_clear_num_cells(pchan->cmux, circ);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 0);
+
+ /* Re-activate. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+
+ /* Once re-attached, it should become inactive because the circuit has no
+ * cells while the chanid<->circid object has some. The attach code will
+ * reset the count on the cmux for that circuit:
+ *
+ * if (chanid_circid_muxinfo_t->muxinfo.cell_count > 0 && cell_count == 0) {
+ */
+ circuitmux_attach_circuit(pchan->cmux, circ, CELL_DIRECTION_IN);
+ n_cells = circuitmux_num_cells_for_circuit(pchan->cmux, circ);
+ tt_uint_op(n_cells, OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
+
+ /* Lets queue a cell on the circuit now so it becomes active when
+ * re-attaching:
+ *
+ * else if (chanid_circid_muxinfo_t->muxinfo.cell_count == 0 &&
+ * cell_count > 0) {
+ */
+ orcirc->p_chan_cells.n = 1;
+ circuitmux_attach_circuit(pchan->cmux, circ, CELL_DIRECTION_IN);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+
+ done:
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void
+test_cmux_detach_circuit(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+
+ (void) arg;
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* While assigning a new circuit IDs, the circuitmux_attach_circuit() is
+ * called for a new channel on the circuit. This means, we should now have
+ * the created circuit attached on both the pchan and nchan cmux. */
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
+
+ /* Now, detach the circuit from pchan and then nchan. */
+ circuitmux_detach_circuit(pchan->cmux, circ);
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 0);
+ circuitmux_detach_circuit(nchan->cmux, circ);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 0);
+
+ done:
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void
+test_cmux_detach_all_circuits(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+ smartlist_t *detached_out = smartlist_new();
+
+ (void) arg;
+
+ /* Channels need to be registered in order for the detach all circuit
+ * function to find them. */
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ channel_register(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+ channel_register(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* Just make sure it is attached. */
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
+
+ /* Queue some cells so we can test if the circuit becomes inactive on the
+ * cmux after the mass detach. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+ circuitmux_set_num_cells(nchan->cmux, circ, 4);
+
+ /* Detach all on pchan and then nchan. */
+ circuitmux_detach_all_circuits(pchan->cmux, detached_out);
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(smartlist_len(detached_out), OP_EQ, 1);
+ circuitmux_detach_all_circuits(nchan->cmux, NULL);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(nchan->cmux, circ), OP_EQ, 0);
+
+ done:
+ smartlist_free(detached_out);
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void
+test_cmux_policy(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+
+ (void) arg;
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ channel_register(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+ channel_register(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* Confirm we have the EWMA policy by default for new channels. */
+ tt_ptr_op(circuitmux_get_policy(pchan->cmux), OP_EQ, &ewma_policy);
+ tt_ptr_op(circuitmux_get_policy(nchan->cmux), OP_EQ, &ewma_policy);
+
+ /* Putting cell on the cmux means will make the notify policy code path to
+ * trigger. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+
+ /* Clear it out. */
+ circuitmux_clear_policy(pchan->cmux);
+
+ /* Set back the EWMA policy. */
+ circuitmux_set_policy(pchan->cmux, &ewma_policy);
+
+ done:
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void
+test_cmux_xmit_cell(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+
+ (void) arg;
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* Queue 4 cells on the circuit. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+ tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 4);
+ tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 4);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 1);
+
+ /* Emit the first cell. Circuit should still be active. */
+ circuitmux_notify_xmit_cells(pchan->cmux, circ, 1);
+ tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 3);
+ tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 3);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 1);
+
+ /* Emit the last 3 cells. Circuit should become inactive. */
+ circuitmux_notify_xmit_cells(pchan->cmux, circ, 3);
+ tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
+
+ /* Queue a DESTROY cell. */
+ pchan->has_queued_writes = mock_has_queued_writes_true;
+ circuitmux_append_destroy_cell(pchan, pchan->cmux, orcirc->p_circ_id, 0);
+ tt_i64_op(pchan->cmux->destroy_ctr, OP_EQ, 1);
+ tt_int_op(pchan->cmux->destroy_cell_queue.n, OP_EQ, 1);
+ tt_i64_op(circuitmux_count_queued_destroy_cells(pchan, pchan->cmux),
+ OP_EQ, 1);
+
+ /* Emit the DESTROY cell. */
+ circuitmux_notify_xmit_destroy(pchan->cmux);
+ tt_i64_op(pchan->cmux->destroy_ctr, OP_EQ, 0);
+
+ done:
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void *
+cmux_setup_test(const struct testcase_t *tc)
+{
+ static int whatever;
+
+ (void) tc;
+
+ cell_ewma_initialize_ticks();
+ return &whatever;
+}
+
+static int
+cmux_cleanup_test(const struct testcase_t *tc, void *ptr)
+{
+ (void) tc;
+ (void) ptr;
+
+ circuitmux_ewma_free_all();
+
+ return 1;
+}
+
+static struct testcase_setup_t cmux_test_setup = {
+ .setup_fn = cmux_setup_test,
+ .cleanup_fn = cmux_cleanup_test,
+};
+
+#define TEST_CMUX(name) \
+ { #name, test_cmux_##name, TT_FORK, &cmux_test_setup, NULL }
+
struct testcase_t circuitmux_tests[] = {
- { "destroy_cell_queue", test_cmux_destroy_cell_queue, TT_FORK, NULL, NULL },
- { "compute_ticks", test_cmux_compute_ticks, TT_FORK, NULL, NULL },
+ /* Test circuitmux_t object */
+ TEST_CMUX(allocate),
+ TEST_CMUX(attach_circuit),
+ TEST_CMUX(detach_circuit),
+ TEST_CMUX(detach_all_circuits),
+ TEST_CMUX(policy),
+ TEST_CMUX(xmit_cell),
+
+ /* Misc. */
+ TEST_CMUX(compute_ticks),
+ TEST_CMUX(destroy_cell_queue),
+
END_OF_TESTCASES
};
-
diff --git a/src/test/test_circuitmux_ewma.c b/src/test/test_circuitmux_ewma.c
new file mode 100644
index 0000000000..27601e0c7d
--- /dev/null
+++ b/src/test/test_circuitmux_ewma.c
@@ -0,0 +1,228 @@
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CIRCUITMUX_PRIVATE
+#define CIRCUITMUX_EWMA_PRIVATE
+
+#include "core/or/or.h"
+#include "core/or/circuitmux.h"
+#include "core/or/circuitmux_ewma.h"
+
+#include "test/fakechans.h"
+#include "test/fakecircs.h"
+#include "test/test.h"
+
+static void
+test_cmux_ewma_active_circuit(void *arg)
+{
+ circuitmux_t cmux; /* garbage */
+ circuitmux_policy_data_t *pol_data = NULL;
+ circuit_t circ; /* garbage */
+ circuitmux_policy_circ_data_t *circ_data = NULL;
+
+ (void) arg;
+
+ pol_data = ewma_policy.alloc_cmux_data(&cmux);
+ tt_assert(pol_data);
+ circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ,
+ CELL_DIRECTION_OUT, 42);
+ tt_assert(circ_data);
+
+ /* Get EWMA specific objects. */
+
+ /* Make circuit active. */
+ ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data);
+
+ circuit_t *entry = ewma_policy.pick_active_circuit(&cmux, pol_data);
+ tt_mem_op(entry, OP_EQ, &circ, sizeof(circ));
+
+ done:
+ ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data);
+ ewma_policy.free_cmux_data(&cmux, pol_data);
+}
+
+static void
+test_cmux_ewma_xmit_cell(void *arg)
+{
+ circuitmux_t cmux; /* garbage */
+ circuitmux_policy_data_t *pol_data = NULL;
+ circuit_t circ; /* garbage */
+ circuitmux_policy_circ_data_t *circ_data = NULL;
+ ewma_policy_data_t *ewma_pol_data;
+ ewma_policy_circ_data_t *ewma_data;
+ double old_cell_count;
+
+ (void) arg;
+
+ pol_data = ewma_policy.alloc_cmux_data(&cmux);
+ tt_assert(pol_data);
+ circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ,
+ CELL_DIRECTION_OUT, 42);
+ tt_assert(circ_data);
+ ewma_pol_data = TO_EWMA_POL_DATA(pol_data);
+ ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data);
+
+ /* Make circuit active. */
+ ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data);
+
+ /* Move back in time the last time we calibrated so we scale the active
+ * circuit when emitting a cell. */
+ ewma_pol_data->active_circuit_pqueue_last_recalibrated -= 100;
+ ewma_data->cell_ewma.last_adjusted_tick =
+ ewma_pol_data->active_circuit_pqueue_last_recalibrated;
+
+ /* Grab old cell count. */
+ old_cell_count = ewma_data->cell_ewma.cell_count;
+
+ ewma_policy.notify_xmit_cells(&cmux, pol_data, &circ, circ_data, 1);
+
+ /* Our old cell count should be lower to what we have since we just emitted
+ * a cell and thus we scale. */
+ tt_double_op(old_cell_count, OP_LT, ewma_data->cell_ewma.cell_count);
+
+ done:
+ ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data);
+ ewma_policy.free_cmux_data(&cmux, pol_data);
+}
+
+static void
+test_cmux_ewma_notify_circ(void *arg)
+{
+ circuitmux_t cmux; /* garbage */
+ circuitmux_policy_data_t *pol_data = NULL;
+ circuit_t circ; /* garbage */
+ circuitmux_policy_circ_data_t *circ_data = NULL;
+ const ewma_policy_data_t *ewma_pol_data;
+
+ (void) arg;
+
+ pol_data = ewma_policy.alloc_cmux_data(&cmux);
+ tt_assert(pol_data);
+ circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ,
+ CELL_DIRECTION_OUT, 42);
+ tt_assert(circ_data);
+
+ /* Currently, notify_circ_active() ignores cmux and circ. They can not be
+ * NULL so it is fine to pass garbage. */
+ ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data);
+
+ /* We should have an active circuit in the queue so its EWMA value can be
+ * tracked. */
+ ewma_pol_data = TO_EWMA_POL_DATA(pol_data);
+ tt_int_op(smartlist_len(ewma_pol_data->active_circuit_pqueue), OP_EQ, 1);
+ tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0);
+
+ ewma_policy.notify_circ_inactive(&cmux, pol_data, &circ, circ_data);
+ /* Should be removed from the active queue. */
+ ewma_pol_data = TO_EWMA_POL_DATA(pol_data);
+ tt_int_op(smartlist_len(ewma_pol_data->active_circuit_pqueue), OP_EQ, 0);
+ tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0);
+
+ done:
+ ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data);
+ ewma_policy.free_cmux_data(&cmux, pol_data);
+}
+
+static void
+test_cmux_ewma_policy_circ_data(void *arg)
+{
+ circuitmux_t cmux; /* garbage */
+ circuitmux_policy_data_t pol_data; /* garbage */
+ circuit_t circ; /* garbage */
+ circuitmux_policy_circ_data_t *circ_data = NULL;
+ const ewma_policy_circ_data_t *ewma_data;
+
+ (void) arg;
+
+ /* Currently, alloc_circ_data() ignores every parameter _except_ the cell
+ * direction so it is OK to pass garbage. They can not be NULL. */
+ circ_data = ewma_policy.alloc_circ_data(&cmux, &pol_data, &circ,
+ CELL_DIRECTION_OUT, 42);
+ tt_assert(circ_data);
+ tt_uint_op(circ_data->magic, OP_EQ, EWMA_POL_CIRC_DATA_MAGIC);
+
+ ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data);
+ tt_mem_op(ewma_data->circ, OP_EQ, &circ, sizeof(circuit_t));
+ tt_double_op(ewma_data->cell_ewma.cell_count, OP_LE, 0.0);
+ tt_int_op(ewma_data->cell_ewma.heap_index, OP_EQ, -1);
+ tt_uint_op(ewma_data->cell_ewma.is_for_p_chan, OP_EQ, 0);
+ ewma_policy.free_circ_data(&cmux, &pol_data, &circ, circ_data);
+
+ circ_data = ewma_policy.alloc_circ_data(&cmux, &pol_data, &circ,
+ CELL_DIRECTION_IN, 42);
+ tt_assert(circ_data);
+ tt_uint_op(circ_data->magic, OP_EQ, EWMA_POL_CIRC_DATA_MAGIC);
+
+ ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data);
+ tt_mem_op(ewma_data->circ, OP_EQ, &circ, sizeof(circuit_t));
+ tt_double_op(ewma_data->cell_ewma.cell_count, OP_LE, 0.0);
+ tt_int_op(ewma_data->cell_ewma.heap_index, OP_EQ, -1);
+ tt_uint_op(ewma_data->cell_ewma.is_for_p_chan, OP_EQ, 1);
+
+ done:
+ ewma_policy.free_circ_data(&cmux, &pol_data, &circ, circ_data);
+}
+
+static void
+test_cmux_ewma_policy_data(void *arg)
+{
+ circuitmux_t cmux; /* garbage. */
+ circuitmux_policy_data_t *pol_data = NULL;
+ const ewma_policy_data_t *ewma_pol_data;
+
+ (void) arg;
+
+ pol_data = ewma_policy.alloc_cmux_data(&cmux);
+ tt_assert(pol_data);
+ tt_uint_op(pol_data->magic, OP_EQ, EWMA_POL_DATA_MAGIC);
+
+ /* Test EWMA object. */
+ ewma_pol_data = TO_EWMA_POL_DATA(pol_data);
+ tt_assert(ewma_pol_data->active_circuit_pqueue);
+ tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0);
+
+ done:
+ ewma_policy.free_cmux_data(&cmux, pol_data);
+}
+
+static void *
+cmux_ewma_setup_test(const struct testcase_t *tc)
+{
+ static int whatever;
+
+ (void) tc;
+
+ cell_ewma_initialize_ticks();
+ cmux_ewma_set_options(NULL, NULL);
+
+ return &whatever;
+}
+
+static int
+cmux_ewma_cleanup_test(const struct testcase_t *tc, void *ptr)
+{
+ (void) tc;
+ (void) ptr;
+
+ circuitmux_ewma_free_all();
+
+ return 1;
+}
+
+static struct testcase_setup_t cmux_ewma_test_setup = {
+ .setup_fn = cmux_ewma_setup_test,
+ .cleanup_fn = cmux_ewma_cleanup_test,
+};
+
+#define TEST_CMUX_EWMA(name) \
+ { #name, test_cmux_ewma_##name, TT_FORK, &cmux_ewma_test_setup, NULL }
+
+struct testcase_t circuitmux_ewma_tests[] = {
+ TEST_CMUX_EWMA(active_circuit),
+ TEST_CMUX_EWMA(policy_data),
+ TEST_CMUX_EWMA(policy_circ_data),
+ TEST_CMUX_EWMA(notify_circ),
+ TEST_CMUX_EWMA(xmit_cell),
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c
index 934ddb0208..cfb24c032c 100644
--- a/src/test/test_circuitpadding.c
+++ b/src/test/test_circuitpadding.c
@@ -1,4 +1,4 @@
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define TOR_TIMERS_PRIVATE
#define CIRCUITPADDING_PRIVATE
#define CIRCUITPADDING_MACHINES_PRIVATE
@@ -27,7 +27,6 @@
#include "core/crypto/relay_crypto.h"
#include "core/or/protover.h"
#include "feature/nodelist/nodelist.h"
-#include "lib/evloop/compat_libevent.h"
#include "app/config/config.h"
#include "feature/nodelist/routerstatus_st.h"
@@ -38,6 +37,7 @@
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
+#include "test/fakecircs.h"
#include "test/rng_test_helpers.h"
/* Start our monotime mocking at 1 second past whatever monotime_init()
@@ -53,7 +53,6 @@ circid_t get_unique_circ_id_by_chan(channel_t *chan);
void helper_create_basic_machine(void);
static void helper_create_conditional_machines(void);
-static or_circuit_t * new_fake_orcirc(channel_t *nchan, channel_t *pchan);
channel_t *new_fake_channel(void);
void test_circuitpadding_negotiation(void *arg);
void test_circuitpadding_wronghop(void *arg);
@@ -67,7 +66,6 @@ void test_circuitpadding_state_length(void *arg);
static void
simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
int padding);
-void free_fake_orcirc(circuit_t *circ);
void free_fake_origin_circuit(origin_circuit_t *circ);
static int deliver_negotiated = 1;
@@ -127,62 +125,6 @@ circuit_get_nth_node_mock(origin_circuit_t *circ, int hop)
return &padding_node;
}
-static or_circuit_t *
-new_fake_orcirc(channel_t *nchan, channel_t *pchan)
-{
- or_circuit_t *orcirc = NULL;
- circuit_t *circ = NULL;
- crypt_path_t tmp_cpath;
- char whatevs_key[CPATH_KEY_MATERIAL_LEN];
-
- orcirc = tor_malloc_zero(sizeof(*orcirc));
- circ = &(orcirc->base_);
- circ->magic = OR_CIRCUIT_MAGIC;
-
- //circ->n_chan = nchan;
- circ->n_circ_id = get_unique_circ_id_by_chan(nchan);
- cell_queue_init(&(circ->n_chan_cells));
- circ->n_hop = NULL;
- circ->streams_blocked_on_n_chan = 0;
- circ->streams_blocked_on_p_chan = 0;
- circ->n_delete_pending = 0;
- circ->p_delete_pending = 0;
- circ->received_destroy = 0;
- circ->state = CIRCUIT_STATE_OPEN;
- circ->purpose = CIRCUIT_PURPOSE_OR;
- circ->package_window = CIRCWINDOW_START_MAX;
- circ->deliver_window = CIRCWINDOW_START_MAX;
- circ->n_chan_create_cell = NULL;
-
- //orcirc->p_chan = pchan;
- orcirc->p_circ_id = get_unique_circ_id_by_chan(pchan);
- cell_queue_init(&(orcirc->p_chan_cells));
-
- circuit_set_p_circid_chan(orcirc, orcirc->p_circ_id, pchan);
- circuit_set_n_circid_chan(circ, circ->n_circ_id, nchan);
-
- memset(&tmp_cpath, 0, sizeof(tmp_cpath));
- if (cpath_init_circuit_crypto(&tmp_cpath, whatevs_key,
- sizeof(whatevs_key), 0, 0)<0) {
- log_warn(LD_BUG,"Circuit initialization failed");
- return NULL;
- }
- orcirc->crypto = tmp_cpath.pvt_crypto;
-
- return orcirc;
-}
-
-void
-free_fake_orcirc(circuit_t *circ)
-{
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
-
- relay_crypto_clear(&orcirc->crypto);
-
- circpad_circuit_free_all_machineinfos(circ);
- tor_free(circ);
-}
-
void
free_fake_origin_circuit(origin_circuit_t *circ)
{
@@ -413,7 +355,7 @@ test_circuitpadding_rtt(void *arg)
circpad_machine_current_state(
client_side->padding_info[0])->histogram_edges[0]);
done:
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
timers_shutdown();
@@ -1439,7 +1381,7 @@ test_circuitpadding_wronghop(void *arg)
/* Test 2: Test no padding */
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
@@ -1484,7 +1426,7 @@ test_circuitpadding_wronghop(void *arg)
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
monotime_disable_test_mocking();
@@ -1553,7 +1495,7 @@ test_circuitpadding_negotiation(void *arg)
/* Test 2: Test no padding */
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
@@ -1591,7 +1533,7 @@ test_circuitpadding_negotiation(void *arg)
/* 3. Test failure to negotiate a machine due to desync */
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
@@ -1619,7 +1561,7 @@ test_circuitpadding_negotiation(void *arg)
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
monotime_disable_test_mocking();
@@ -1939,7 +1881,7 @@ test_circuitpadding_state_length(void *arg)
tor_free(client_machine);
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
@@ -2312,7 +2254,7 @@ test_circuitpadding_circuitsetup_machine(void *arg)
tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
OP_NE, 0);
circuit_mark_for_close(client_side, END_CIRC_REASON_FLAG_REMOTE);
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
timers_advance_and_run(5000);
/* No cells sent */
@@ -2616,7 +2558,7 @@ test_circuitpadding_global_rate_limiting(void *arg)
tt_int_op(retval, OP_EQ, 0);
done:
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
@@ -2769,7 +2711,7 @@ test_circuitpadding_reduce_disable(void *arg)
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
done:
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
testing_disable_reproducible_rng();
@@ -3075,7 +3017,7 @@ helper_test_hs_machines(bool test_intro_circs)
}
done:
- free_fake_orcirc(relay_side);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c
index 9bfaabeb2f..e15dec5a01 100644
--- a/src/test/test_circuitstats.c
+++ b/src/test/test_circuitstats.c
@@ -1,10 +1,10 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
#define CIRCUITSTATS_PRIVATE
#define CIRCUITLIST_PRIVATE
-#define CHANNEL_PRIVATE_
+#define CHANNEL_FILE_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c
index 3acfc12044..49438d9d3b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITLIST_PRIVATE
diff --git a/src/test/test_cmdline.sh b/src/test/test_cmdline.sh
index cf758c3851..ded58af63d 100755
--- a/src/test/test_cmdline.sh
+++ b/src/test/test_cmdline.sh
@@ -3,6 +3,21 @@
umask 077
set -e
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+# find the tor binary
if [ $# -ge 1 ]; then
TOR_BINARY="${1}"
shift
@@ -10,6 +25,8 @@ else
TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
fi
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
echo "TOR BINARY IS ${TOR_BINARY}"
die() { echo "$1" >&2 ; exit 5; }
diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c
index ecd97e3474..5376e08fb3 100644
--- a/src/test/test_compat_libevent.c
+++ b/src/test/test_compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define COMPAT_LIBEVENT_PRIVATE
@@ -13,8 +13,6 @@
#include "test/log_test_helpers.h"
-#define NS_MODULE compat_libevent
-
static void
test_compat_libevent_logging_callback(void *ignored)
{
diff --git a/src/test/test_config.c b/src/test/test_config.c
index ebc0624fb2..cb0d9bba28 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -1,11 +1,13 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CONFIG_PRIVATE
+#define RELAY_CONFIG_PRIVATE
+#define RELAY_TRANSPORT_CONFIG_PRIVATE
#define PT_PRIVATE
#define ROUTERSET_PRIVATE
#include "core/or/or.h"
@@ -16,7 +18,10 @@
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitbuild.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "app/config/resolve_addr.h"
+#include "feature/relay/relay_config.h"
+#include "feature/relay/transport_config.h"
+#include "lib/confmgt/confmgt.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "test/test.h"
@@ -24,6 +29,7 @@
#include "feature/control/control.h"
#include "core/mainloop/cpuworker.h"
#include "feature/dircache/dirserv.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirauth/dirvote.h"
#include "feature/relay/dns.h"
#include "feature/client/entrynodes.h"
@@ -37,6 +43,7 @@
#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"
#include "feature/nodelist/dirlist.h"
@@ -672,6 +679,52 @@ transport_is_needed_mock(const char *transport_name)
return transport_is_needed_mock_return;
}
+static void
+test_config_parse_tcp_proxy_line(void *arg)
+{
+ (void)arg;
+
+ int ret;
+ char *msg = NULL;
+ or_options_t *options = get_options_mutable();
+
+ /* Bad TCPProxy line - too short. */
+ ret = parse_tcp_proxy_line("haproxy", options, &msg);
+ /* Return error. */
+ tt_int_op(ret, OP_EQ, -1);
+ /* Correct error message. */
+ tt_str_op(msg, OP_EQ, "TCPProxy has no address/port. Please fix.");
+ /* Free error message. */
+ tor_free(msg);
+
+ /* Bad TCPProxy line - unsupported protocol. */
+ ret = parse_tcp_proxy_line("unsupported 95.216.163.36:443", options, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ, "TCPProxy protocol is not supported. Currently the "
+ "only supported protocol is 'haproxy'. Please fix.");
+ tor_free(msg);
+
+ /* Bad TCPProxy line - unparsable address/port. */
+ ret = parse_tcp_proxy_line("haproxy 95.216.163.36/443", options, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ, "TCPProxy address/port failed to parse or resolve. "
+ "Please fix.");
+ tor_free(msg);
+
+ /* Good TCPProxy line - ipv4. */
+ ret = parse_tcp_proxy_line("haproxy 95.216.163.36:443", options, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(options->TCPProxyProtocol, OP_EQ, TCP_PROXY_PROTOCOL_HAPROXY);
+ /* Correct the address. */
+ tt_assert(tor_addr_eq_ipv4h(&options->TCPProxyAddr, 0x5fd8a324));
+ tt_int_op(options->TCPProxyPort, OP_EQ, 443);
+ tor_free(msg);
+
+ done:
+ ;
+}
+
/**
* Test parsing for the ClientTransportPlugin and ServerTransportPlugin config
* options.
@@ -689,84 +742,84 @@ test_config_parse_transport_plugin_line(void *arg)
int old_transport_is_needed_mock_call_count;
/* Bad transport lines - too short */
- r = parse_transport_line(options, "bad", 1, 0);
+ r = pt_parse_transport_line(options, "bad", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options, "bad", 1, 1);
+ r = pt_parse_transport_line(options, "bad", 1, 1);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options, "bad bad", 1, 0);
+ r = pt_parse_transport_line(options, "bad bad", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options, "bad bad", 1, 1);
+ r = pt_parse_transport_line(options, "bad bad", 1, 1);
tt_int_op(r, OP_LT, 0);
/* Test transport list parsing */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 0);
tt_int_op(r, OP_EQ, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 1);
tt_int_op(r, OP_EQ, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1,transport_2 exec /usr/bin/fake-transport", 1, 0);
tt_int_op(r, OP_EQ, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1,transport_2 exec /usr/bin/fake-transport", 1, 1);
tt_int_op(r, OP_EQ, 0);
/* Bad transport identifiers */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_* exec /usr/bin/fake-transport", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_* exec /usr/bin/fake-transport", 1, 1);
tt_int_op(r, OP_LT, 0);
/* Check SOCKS cases for client transport */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks4 1.2.3.4:567", 1, 0);
tt_int_op(r, OP_EQ, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks5 1.2.3.4:567", 1, 0);
tt_int_op(r, OP_EQ, 0);
/* Proxy case for server transport */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 proxy 1.2.3.4:567", 1, 1);
tt_int_op(r, OP_EQ, 0);
/* Multiple-transport error exit */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1,transport_2 socks5 1.2.3.4:567", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1,transport_2 proxy 1.2.3.4:567", 1, 1);
tt_int_op(r, OP_LT, 0);
/* No port error exit */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks5 1.2.3.4", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 proxy 1.2.3.4", 1, 1);
tt_int_op(r, OP_LT, 0);
/* Unparsable address error exit */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks5 1.2.3:6x7", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 proxy 1.2.3:6x7", 1, 1);
tt_int_op(r, OP_LT, 0);
/* "Strange {Client|Server}TransportPlugin field" error exit */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 foo bar", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 foo bar", 1, 1);
tt_int_op(r, OP_LT, 0);
/* No sandbox mode error exit */
tmp = options->Sandbox;
options->Sandbox = 1;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 1);
tt_int_op(r, OP_LT, 0);
options->Sandbox = tmp;
@@ -778,7 +831,7 @@ test_config_parse_transport_plugin_line(void *arg)
MOCK(pt_kickstart_proxy, pt_kickstart_proxy_mock);
old_pt_kickstart_proxy_mock_call_count =
pt_kickstart_proxy_mock_call_count;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 1);
tt_int_op(r, OP_EQ, 0);
tt_assert(pt_kickstart_proxy_mock_call_count ==
@@ -786,7 +839,7 @@ test_config_parse_transport_plugin_line(void *arg)
UNMOCK(pt_kickstart_proxy);
/* This one hits a log line in the !validate_only case only */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 proxy 1.2.3.4:567", 0, 1);
tt_int_op(r, OP_EQ, 0);
@@ -803,7 +856,7 @@ test_config_parse_transport_plugin_line(void *arg)
transport_add_from_config_mock_call_count;
old_transport_is_needed_mock_call_count =
transport_is_needed_mock_call_count;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 0);
/* Should have succeeded */
tt_int_op(r, OP_EQ, 0);
@@ -827,7 +880,7 @@ test_config_parse_transport_plugin_line(void *arg)
transport_add_from_config_mock_call_count;
old_transport_is_needed_mock_call_count =
transport_is_needed_mock_call_count;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 0);
/* Should have succeeded */
tt_int_op(r, OP_EQ, 0);
@@ -851,7 +904,7 @@ test_config_parse_transport_plugin_line(void *arg)
transport_add_from_config_mock_call_count;
old_transport_is_needed_mock_call_count =
transport_is_needed_mock_call_count;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks5 1.2.3.4:567", 0, 0);
/* Should have succeeded */
tt_int_op(r, OP_EQ, 0);
@@ -906,14 +959,12 @@ test_config_fix_my_family(void *arg)
family3->next = NULL;
or_options_t* options = options_new();
- or_options_t* defaults = options_new();
(void) arg;
options_init(options);
- options_init(defaults);
options->MyFamily_lines = family;
- options_validate(NULL, options, defaults, 0, &err) ;
+ options_validate(NULL, options, &err) ;
if (err != NULL) {
TT_FAIL(("options_validate failed: %s", err));
@@ -935,7 +986,6 @@ test_config_fix_my_family(void *arg)
done:
tor_free(err);
or_options_free(options);
- or_options_free(defaults);
}
static int n_hostname_01010101 = 0;
@@ -3658,7 +3708,7 @@ test_config_directory_fetch(void *arg)
options->ClientOnly = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 1);
@@ -3668,7 +3718,7 @@ test_config_directory_fetch(void *arg)
options->UseBridges = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 1);
@@ -3680,7 +3730,7 @@ test_config_directory_fetch(void *arg)
options->ORPort_set = 1;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 0);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 1);
@@ -3691,7 +3741,7 @@ test_config_directory_fetch(void *arg)
options->FetchDirInfoEarly = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 1);
@@ -3705,14 +3755,14 @@ test_config_directory_fetch(void *arg)
mock_router_pick_published_address_result = -1;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
mock_router_pick_published_address_result = 0;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3733,7 +3783,7 @@ test_config_directory_fetch(void *arg)
options->RefuseUnknownExits = 1;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3741,7 +3791,7 @@ test_config_directory_fetch(void *arg)
mock_router_pick_published_address_result = 0;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3763,7 +3813,7 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3772,7 +3822,7 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3780,7 +3830,7 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = NULL;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3790,7 +3840,7 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3800,7 +3850,7 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3816,7 +3866,9 @@ static void
test_config_default_fallback_dirs(void *arg)
{
const char *fallback[] = {
+#ifndef COCCI
#include "app/config/fallback_dirs.inc"
+#endif
NULL
};
@@ -3998,40 +4050,40 @@ test_config_parse_port_config__ports__no_ports_given(void *data)
slout = smartlist_new();
// Test no defaultport, no defaultaddress and no out
- ret = parse_port_config(NULL, NULL, "DNS", 0, NULL, 0, 0);
+ ret = port_parse_config(NULL, NULL, "DNS", 0, NULL, 0, 0);
tt_int_op(ret, OP_EQ, 0);
// Test with defaultport, no defaultaddress and no out
- ret = parse_port_config(NULL, NULL, "DNS", 0, NULL, 42, 0);
+ ret = port_parse_config(NULL, NULL, "DNS", 0, NULL, 42, 0);
tt_int_op(ret, OP_EQ, 0);
// Test no defaultport, with defaultaddress and no out
- ret = parse_port_config(NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
+ ret = port_parse_config(NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
tt_int_op(ret, OP_EQ, 0);
// Test with defaultport, with defaultaddress and no out
- ret = parse_port_config(NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
+ ret = port_parse_config(NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
tt_int_op(ret, OP_EQ, 0);
// Test no defaultport, no defaultaddress and with out
- ret = parse_port_config(slout, NULL, "DNS", 0, NULL, 0, 0);
+ ret = port_parse_config(slout, NULL, "DNS", 0, NULL, 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test with defaultport, no defaultaddress and with out
- ret = parse_port_config(slout, NULL, "DNS", 0, NULL, 42, 0);
+ ret = port_parse_config(slout, NULL, "DNS", 0, NULL, 42, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test no defaultport, with defaultaddress and with out
- ret = parse_port_config(slout, NULL, "DNS", 0, "127.0.0.2", 0, 0);
+ ret = port_parse_config(slout, NULL, "DNS", 0, "127.0.0.2", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test with defaultport, with defaultaddress and out, adds a new port cfg
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, NULL, "DNS", 0, "127.0.0.2", 42, 0);
+ ret = port_parse_config(slout, NULL, "DNS", 0, "127.0.0.2", 42, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
@@ -4042,7 +4094,7 @@ test_config_parse_port_config__ports__no_ports_given(void *data)
// for a unix address
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, NULL, "DNS", 0, "/foo/bar/unixdomain",
+ ret = port_parse_config(slout, NULL, "DNS", 0, "/foo/bar/unixdomain",
42, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4073,28 +4125,28 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test error when encounters an invalid Port specification
config_port_invalid = mock_config_line("DNSPort", "");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0, NULL,
0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test error when encounters an empty unix domain specification
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "unix:");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0, NULL,
0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test error when encounters a unix domain specification but the listener
// doesn't support domain sockets
config_port_valid = mock_config_line("DNSPort", "unix:/tmp/foo/bar");
- ret = parse_port_config(NULL, config_port_valid, "DNS",
+ ret = port_parse_config(NULL, config_port_valid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test valid unix domain
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0, 0);
#ifdef _WIN32
tt_int_op(ret, OP_EQ, -1);
@@ -4105,7 +4157,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(port_cfg->port, OP_EQ, 0);
tt_int_op(port_cfg->is_unix_addr, OP_EQ, 1);
tt_str_op(port_cfg->unix_addr, OP_EQ, "/tmp/foo/bar");
- /* Test entry port defaults as initialised in parse_port_config */
+ /* Test entry port defaults as initialised in port_parse_config */
tt_int_op(port_cfg->entry_cfg.dns_request, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
@@ -4119,7 +4171,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
"unix:/tmp/foo/bar NoIPv4Traffic "
"NoIPv6Traffic "
"NoOnionTraffic");
- ret = parse_port_config(NULL, config_port_invalid, "SOCKS",
+ ret = port_parse_config(NULL, config_port_invalid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4128,7 +4180,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort",
"127.0.0.1:80 NoDNSRequest");
- ret = parse_port_config(NULL, config_port_invalid, "DNS",
+ ret = port_parse_config(NULL, config_port_invalid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4141,7 +4193,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("DNSPort", "127.0.0.1:80 "
"NoIPv6Traffic "
"NoIPv4Traffic NoOnionTraffic");
- ret = parse_port_config(slout, config_port_valid, "DNS",
+ ret = port_parse_config(slout, config_port_valid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
@@ -4157,7 +4209,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_invalid = mock_config_line("SOCKSPort",
"NoIPv6Traffic "
"unix:/tmp/foo/bar NoIPv4Traffic");
- ret = parse_port_config(NULL, config_port_invalid, "SOCKS",
+ ret = port_parse_config(NULL, config_port_invalid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4170,7 +4222,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4192,7 +4244,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("SOCKSPort", "unix:\"/tmp/foo/ bar\" "
"NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4214,7 +4266,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("SOCKSPort", "unix:\"/tmp/foo/ bar "
"NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4226,7 +4278,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("SOCKSPort", "unix:\"\" "
"NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4237,7 +4289,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"OnionTrafficOnly");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4258,7 +4310,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"NoIPv4Traffic IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4277,7 +4329,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"IPv4Traffic IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4293,28 +4345,28 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test failure if we specify world writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 WorldWritable");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test failure if we specify group writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 GroupWritable");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test failure if we specify group writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 RelaxDirModeCheck");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test success with only a port (this will fail without a default address)
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort", "42");
- ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -4323,7 +4375,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateDestPort");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4336,7 +4388,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoIsolateDestPorts");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4349,7 +4401,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateDestAddr");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4362,7 +4414,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateSOCKSAuth");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4375,7 +4427,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateClientProtocol");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4388,7 +4440,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateClientAddr");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4399,7 +4451,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with ignored unknown options
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort", "42 ThisOptionDoesntExist");
- ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -4408,7 +4460,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoIsolateSOCKSAuth");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4421,7 +4473,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort",
"42 IPv6Traffic PreferIPv6");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, "127.0.0.42", 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
@@ -4434,7 +4486,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheIPv4DNS");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4447,7 +4499,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheIPv6DNS");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4460,7 +4512,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoCacheIPv4DNS");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4473,7 +4525,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheDNS");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4486,7 +4538,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseIPv4Cache");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4499,7 +4551,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseIPv6Cache");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4512,7 +4564,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseDNSCache");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4525,7 +4577,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoPreferIPv6Automap");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4537,7 +4589,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 PreferSOCKSNoAuth");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4552,14 +4604,14 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_invalid = mock_config_line("DNSPort", "0");
config_port_valid = mock_config_line("DNSPort", "42");
config_port_invalid->next = config_port_valid;
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test success with warn non-local control
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, "Control",
+ ret = port_parse_config(slout, config_port_valid, "Control",
CONN_TYPE_CONTROL_LISTENER, "127.0.0.42", 0,
CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4567,7 +4619,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with warn non-local listener
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, "ExtOR",
+ ret = port_parse_config(slout, config_port_valid, "ExtOR",
CONN_TYPE_EXT_OR_LISTENER, "127.0.0.42", 0,
CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4575,12 +4627,12 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with warn non-local other
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
// Test success with warn non-local other without out
- ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4591,7 +4643,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IPv4Traffic "
"IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.44", 0,
CL_PORT_TAKES_HOSTNAMES |
CL_PORT_NO_STREAM_OPTIONS);
@@ -4606,7 +4658,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=invalid");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4616,7 +4668,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4626,7 +4678,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123 "
"SessionGroup=321");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4635,7 +4687,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 SessionGroup=1111122");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.44", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4647,7 +4699,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "0");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.45", 0, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
@@ -4657,7 +4709,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "something");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.45", 0, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4670,48 +4722,48 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "auto");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
tor_addr_parse(&addr, "127.0.0.46");
- tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ tt_assert(tor_addr_eq(&port_cfg->addr, &addr));
// Test success with a port of auto in mixed case
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "AuTo");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
tor_addr_parse(&addr, "127.0.0.46");
- tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ tt_assert(tor_addr_eq(&port_cfg->addr, &addr));
// Test success with parsing both an address and an auto port
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.122:auto");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
tor_addr_parse(&addr, "127.0.0.122");
- tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ tt_assert(tor_addr_eq(&port_cfg->addr, &addr));
// Test failure when asked to parse an invalid address followed by auto
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "invalidstuff!!:auto");
MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
UNMOCK(tor_addr_lookup);
tt_int_op(ret, OP_EQ, -1);
@@ -4721,21 +4773,21 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.123:656");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->port, OP_EQ, 656);
tor_addr_parse(&addr, "127.0.0.123");
- tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ tt_assert(tor_addr_eq(&port_cfg->addr, &addr));
// Test failure if we can't parse anything at all
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "something wrong");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4744,7 +4796,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.1.0:123:auto");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4754,7 +4806,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/somewhere");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, "127.0.0.46", 0,
CL_PORT_DFLT_GROUP_WRITABLE);
#ifdef _WIN32
@@ -4790,7 +4842,7 @@ test_config_parse_port_config__ports__server_options(void *data)
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort",
"127.0.0.124:656 NoAdvertise");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4803,7 +4855,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 NoListen");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4817,7 +4869,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.0.124:656 NoListen "
"NoAdvertise");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4826,7 +4878,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 IPv4Only");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4839,7 +4891,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "[::1]:656 IPv6Only");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4853,7 +4905,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.0.124:656 IPv6Only "
"IPv4Only");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4862,7 +4914,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 unknown");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4873,7 +4925,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort",
"127.0.0.124:656 IPv6Only");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4882,7 +4934,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "[::1]:656 IPv4Only");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4891,7 +4943,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("ORPort", "unix:\"\"");
- ret = parse_port_config(slout, config_port_invalid, "ORPort", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4904,6 +4956,71 @@ test_config_parse_port_config__ports__server_options(void *data)
}
static void
+test_config_get_first_advertised(void *data)
+{
+ (void)data;
+ int r, w=0, n=0;
+ char *msg=NULL;
+ or_options_t *opts = options_new();
+ int port;
+ const tor_addr_t *addr;
+
+ // no ports are configured? We get NULL.
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET);
+ tt_int_op(port, OP_EQ, 0);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET);
+ tt_ptr_op(addr, OP_EQ, NULL);
+
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ tt_int_op(port, OP_EQ, 0);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ tt_ptr_op(addr, OP_EQ, NULL);
+
+ config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:8080");
+ config_line_append(&opts->ORPort_lines, "ORPort",
+ "1.2.3.4:9999 noadvertise");
+ config_line_append(&opts->ORPort_lines, "ORPort",
+ "5.6.7.8:9911 nolisten");
+
+ r = parse_ports(opts, 0, &msg, &n, &w);
+ tt_assert(r == 0);
+
+ // UNSPEC gets us nothing.
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_UNSPEC);
+ tt_int_op(port, OP_EQ, 0);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_UNSPEC);
+ tt_ptr_op(addr, OP_EQ, NULL);
+
+ // Try AF_INET.
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET);
+ tt_int_op(port, OP_EQ, 9911);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET);
+ tt_ptr_op(addr, OP_NE, NULL);
+ tt_str_op(fmt_addrport(addr,port), OP_EQ, "5.6.7.8:9911");
+
+ // Try AF_INET6
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ tt_int_op(port, OP_EQ, 8080);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ tt_ptr_op(addr, OP_NE, NULL);
+ tt_str_op(fmt_addrport(addr,port), OP_EQ, "[1234::5678]:8080");
+
+ done:
+ or_options_free(opts);
+ config_free_all();
+}
+
+static void
test_config_parse_log_severity(void *data)
{
int ret;
@@ -5640,7 +5757,6 @@ test_config_check_bridge_distribution_setting_not_a_bridge(void *arg)
{
or_options_t* options = get_options_mutable();
or_options_t* old_options = options;
- or_options_t* default_options = options;
char* message = NULL;
int ret;
@@ -5649,7 +5765,7 @@ test_config_check_bridge_distribution_setting_not_a_bridge(void *arg)
options->BridgeRelay = 0;
options->BridgeDistribution = (char*)("https");
- ret = options_validate(old_options, options, default_options, 0, &message);
+ ret = options_validate(old_options, options, &message);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(message, OP_EQ, "You set BridgeDistribution, but you "
@@ -6064,6 +6180,36 @@ test_config_kvline_parse(void *arg)
tt_str_op(lines->next->next->value, OP_EQ, "I");
enc = kvline_encode(lines, KV_OMIT_VALS|KV_QUOTED);
tt_str_op(enc, OP_EQ, "AB=\"CD E\" DE FGH=I");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=CD \"EF=GH\"", KV_OMIT_KEYS|KV_QUOTED);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "CD");
+ tt_str_op(lines->next->key, OP_EQ, "");
+ tt_str_op(lines->next->value, OP_EQ, "EF=GH");
+ enc = kvline_encode(lines, KV_OMIT_KEYS);
+ tt_assert(!enc);
+ enc = kvline_encode(lines, KV_OMIT_KEYS|KV_QUOTED);
+ tt_assert(enc);
+ tt_str_op(enc, OP_EQ, "AB=CD \"EF=GH\"");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = tor_malloc_zero(sizeof(*lines));
+ lines->key = tor_strdup("A=B");
+ lines->value = tor_strdup("CD");
+ enc = kvline_encode(lines, 0);
+ tt_assert(!enc);
+ config_free_lines(lines);
+
+ config_line_append(&lines, "A", "B C");
+ enc = kvline_encode(lines, 0);
+ tt_assert(!enc);
+ enc = kvline_encode(lines, KV_RAW);
+ tt_assert(enc);
+ tt_str_op(enc, OP_EQ, "A=B C");
done:
config_free_lines(lines);
@@ -6113,6 +6259,7 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(parse_bridge_line, 0),
CONFIG_TEST(parse_transport_options_line, 0),
CONFIG_TEST(parse_transport_plugin_line, TT_FORK),
+ CONFIG_TEST(parse_tcp_proxy_line, TT_FORK),
CONFIG_TEST(check_or_create_data_subdir, TT_FORK),
CONFIG_TEST(write_to_data_subdir, TT_FORK),
CONFIG_TEST(fix_my_family, 0),
@@ -6121,6 +6268,7 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(parse_port_config__ports__no_ports_given, 0),
CONFIG_TEST(parse_port_config__ports__server_options, 0),
CONFIG_TEST(parse_port_config__ports__ports_given, 0),
+ CONFIG_TEST(get_first_advertised, TT_FORK),
CONFIG_TEST(parse_log_severity, 0),
CONFIG_TEST(include_limit, 0),
CONFIG_TEST(include_does_not_exist, 0),
diff --git a/src/test/test_confmgr.c b/src/test/test_confmgr.c
index d5c73b48e4..a647b92e0a 100644
--- a/src/test/test_confmgr.c
+++ b/src/test/test_confmgr.c
@@ -1,19 +1,19 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
- * Tests for confparse.c's features that support multiple configuration
+ * Tests for confmgt.c's features that support multiple configuration
* formats and configuration objects.
*/
-#define CONFPARSE_PRIVATE
+#define CONFMGT_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
#include "lib/encoding/confline.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "test/test.h"
#include "test/log_test_helpers.h"
@@ -43,6 +43,8 @@ typedef struct {
int fuzziness;
char *alpacaname;
int n_wings; /* deprecated; alpacas don't have wings. */
+
+ int square_fuzziness; /* Derived from fuzziness. */
} alpaca_cfg_t;
/*
@@ -105,6 +107,84 @@ static config_abbrev_t llama_abbrevs[] = {
{ NULL, NULL, 0, 0 },
};
+static int
+legacy_validate_pasture(const void *old_, void *obj, char **msg_out)
+{
+ const pasture_cfg_t *old = old_;
+ pasture_cfg_t *p = obj;
+
+ // llamas can't find their way home if the letters are lowercase.
+ if (p->address)
+ tor_strupper(p->address);
+
+ if (old && old->address &&
+ (!p->address || strcmp(old->address, p->address))) {
+ *msg_out = tor_strdup("You can't move a pasture.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+validate_llama(const void *obj, char **msg_out)
+{
+ const llama_cfg_t *llama = obj;
+ tor_assert(llama->magic == 0x11aa11);
+
+ if (! llama->llamaname || strlen(llama->llamaname) == 0) {
+ *msg_out = tor_strdup("A llama has no name!?");
+ return -1;
+ }
+
+ if (strspn(llama->llamaname, "0123456789") == strlen(llama->llamaname)) {
+ *msg_out = tor_strdup("It is not a number; it is a free llama!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+check_transition_alpaca(const void *old_, const void *new_, char **msg_out)
+{
+ const alpaca_cfg_t *old_alpaca = old_;
+ const alpaca_cfg_t *new_alpaca = new_;
+
+ tor_assert(old_alpaca && new_alpaca);
+ tor_assert(old_alpaca->magic == 0xa15aca);
+ tor_assert(new_alpaca->magic == 0xa15aca);
+
+ if (old_alpaca->fuzziness > new_alpaca->fuzziness) {
+ *msg_out = tor_strdup("An alpaca only becomes more fuzzy over time.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+post_normalize_llama(void *obj, char **msg_out)
+{
+ (void)msg_out;
+ llama_cfg_t *llama = obj;
+ tor_assert(llama->magic == 0x11aa11);
+ tor_assert(llama->llamaname); // we have already checked for a NULL name.
+ tor_free(llama->description);
+ tor_asprintf(&llama->description, "A llama called %s.", llama->llamaname);
+ return 0;
+}
+
+static int
+pre_normalize_alpaca(void *obj, char **msg_out)
+{
+ (void)msg_out;
+ alpaca_cfg_t *alpaca = obj;
+ tor_assert(alpaca->magic == 0xa15aca);
+ alpaca->square_fuzziness = alpaca->fuzziness * alpaca->fuzziness;
+ return 0;
+}
+
static const config_format_t pasture_fmt = {
sizeof(pasture_cfg_t),
{
@@ -113,7 +193,9 @@ static const config_format_t pasture_fmt = {
offsetof(pasture_cfg_t, magic)
},
.vars = pasture_vars,
+ .has_config_suite = true,
.config_suite_offset = offsetof(pasture_cfg_t, subobjs),
+ .legacy_validate_fn = legacy_validate_pasture,
};
static const config_format_t llama_fmt = {
@@ -124,10 +206,11 @@ static const config_format_t llama_fmt = {
offsetof(llama_cfg_t, magic)
},
.vars = llama_vars,
- .config_suite_offset = -1,
.deprecations = llama_deprecations,
.abbrevs = llama_abbrevs,
.clear_fn = clear_llama_cfg,
+ .validate_fn = validate_llama,
+ .post_normalize_fn = post_normalize_llama,
};
static const config_format_t alpaca_fmt = {
@@ -138,8 +221,9 @@ static const config_format_t alpaca_fmt = {
offsetof(alpaca_cfg_t, magic)
},
.vars = alpaca_vars,
- .config_suite_offset = -1,
.deprecations = alpaca_deprecations,
+ .pre_normalize_fn = pre_normalize_alpaca,
+ .check_transition_fn = check_transition_alpaca,
};
#define LLAMA_IDX 0
@@ -313,6 +397,95 @@ test_confmgr_dump(void *arg)
tor_free(s);
}
+static pasture_cfg_t *
+parse_and_validate(config_mgr_t *mgr,
+ const char *inp, const pasture_cfg_t *old, char **msg_out)
+{
+ pasture_cfg_t *p = config_new(mgr);
+ pasture_cfg_t *result = NULL;
+ config_line_t *lines = NULL;
+
+ config_init(mgr, p); // set defaults.
+ int r = config_get_lines(inp, &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, p, lines, 0, msg_out);
+ tt_int_op(r, OP_EQ, 0);
+ tor_free(*msg_out); // sets it to NULL
+ r = config_validate(mgr, old, p, msg_out);
+ if (r < 0)
+ goto done;
+
+ tt_ptr_op(*msg_out, OP_EQ, NULL);
+ result = p;
+ p = NULL; // prevent free
+ done:
+ config_free(mgr, p);
+ config_free_lines(lines);
+ return result;
+}
+
+static void
+test_confmgr_validate(void *arg)
+{
+ (void)arg;
+ char *msg = NULL;
+ config_mgr_t *mgr = get_mgr(true);
+ pasture_cfg_t *p_orig, *p=NULL;
+
+ p_orig = parse_and_validate(mgr, "Llamaname Quest\n"
+ "Address 99 camelid way\n"
+ "Fuzziness 8\n", NULL, &msg);
+ tt_assert(p_orig);
+
+ // Make sure normalization code was run.
+ const alpaca_cfg_t *ac0 = config_mgr_get_obj(mgr, p_orig, ALPACA_IDX);
+ const llama_cfg_t *lc0 = config_mgr_get_obj(mgr, p_orig, LLAMA_IDX);
+ tt_int_op(ac0->fuzziness, OP_EQ, 8);
+ tt_int_op(ac0->square_fuzziness, OP_EQ, 64);
+ tt_str_op(lc0->description, OP_EQ, "A llama called Quest.");
+ tt_str_op(p_orig->address, OP_EQ, "99 CAMELID WAY");
+
+ // try a bad llamaname.
+ p = parse_and_validate(mgr, "llamaname 123", p_orig, &msg);
+ tt_assert(!p);
+ tt_str_op(msg, OP_EQ, "It is not a number; it is a free llama!");
+ tor_free(msg);
+
+ // try a llamaname that would crash the post_normalize step, if it ran.
+ p = parse_and_validate(mgr, "", p_orig, &msg);
+ tt_assert(!p);
+ tt_str_op(msg, OP_EQ, "A llama has no name!?");
+ tor_free(msg);
+
+ // Verify that a transition to a less fuzzy alpaca fails.
+ p = parse_and_validate(mgr, "Llamaname Quest\n"
+ "Address 99 camelid way\n"
+ "Fuzziness 4\n", p_orig, &msg);
+ tt_assert(!p);
+ tt_str_op(msg, OP_EQ, "An alpaca only becomes more fuzzy over time.");
+ tor_free(msg);
+
+ // Try a transition to a more fuzzy alpaca; it should work fine.
+ p = parse_and_validate(mgr, "Llamaname Mercutio\n"
+ // the default fuzziness is 50
+ "Address 99 camelid way\n", p_orig, &msg);
+ tt_assert(p);
+ config_free(mgr, p);
+
+ // Verify that we can't move the pasture.
+ p = parse_and_validate(mgr, "Llamaname Montague\n"
+ // the default fuzziness is 50
+ "Address 99 ungulate st\n", p_orig, &msg);
+ tt_assert(!p);
+ tt_str_op(msg, OP_EQ, "You can't move a pasture.");
+
+ done:
+ config_free(mgr, p);
+ config_free(mgr, p_orig);
+ config_mgr_free(mgr);
+ tor_free(msg);
+}
+
#define CONFMGR_TEST(name, flags) \
{ #name, test_confmgr_ ## name, flags, NULL, NULL }
@@ -321,5 +494,6 @@ struct testcase_t confmgr_tests[] = {
CONFMGR_TEST(magic, 0),
CONFMGR_TEST(parse, 0),
CONFMGR_TEST(dump, 0),
+ CONFMGR_TEST(validate, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_confparse.c b/src/test/test_confparse.c
index 5f29a22c10..21301ce75e 100644
--- a/src/test/test_confparse.c
+++ b/src/test/test_confparse.c
@@ -1,20 +1,20 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
- * Tests for confparse.c module that we use to parse various
+ * Tests for confmgt.c module that we use to parse various
* configuration/state file types.
*/
-#define CONFPARSE_PRIVATE
+#define CONFMGT_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
#include "lib/encoding/confline.h"
#include "feature/nodelist/routerset.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "test/test.h"
#include "test/log_test_helpers.h"
@@ -103,12 +103,9 @@ static config_deprecation_t test_deprecation_notes[] = {
};
static int
-test_validate_cb(void *old_options, void *options, void *default_options,
- int from_setconf, char **msg)
+test_validate_cb(const void *old_options, void *options, char **msg)
{
(void)old_options;
- (void)default_options;
- (void)from_setconf;
(void)msg;
test_struct_t *ts = options;
@@ -122,19 +119,16 @@ test_validate_cb(void *old_options, void *options, void *default_options,
#define TEST_MAGIC 0x1337
static const config_format_t test_fmt = {
- sizeof(test_struct_t),
- {
+ .size = sizeof(test_struct_t),
+ .magic = {
"test_struct_t",
TEST_MAGIC,
offsetof(test_struct_t, magic),
},
- test_abbrevs,
- test_deprecation_notes,
- test_vars,
- test_validate_cb,
- NULL,
- NULL,
- -1,
+ .abbrevs = test_abbrevs,
+ .deprecations = test_deprecation_notes,
+ .vars = test_vars,
+ .legacy_validate_fn = test_validate_cb,
};
/* Make sure that config_init sets everything to the right defaults. */
@@ -818,19 +812,17 @@ static struct_member_t extra = {
};
static config_format_t etest_fmt = {
- sizeof(test_struct_t),
- {
+ .size = sizeof(test_struct_t),
+ .magic = {
"test_struct_t (with extra lines)",
ETEST_MAGIC,
offsetof(test_struct_t, magic),
},
- test_abbrevs,
- test_deprecation_notes,
- test_vars,
- test_validate_cb,
- NULL,
- &extra,
- -1,
+ .abbrevs = test_abbrevs,
+ .deprecations = test_deprecation_notes,
+ .vars = test_vars,
+ .legacy_validate_fn = test_validate_cb,
+ .extra = &extra,
};
/* Try out the feature where we can store unrecognized lines and dump them
@@ -906,11 +898,22 @@ test_confparse_unitparse(void *args)
tt_assert(ok);
/* u64 overflow */
- /* XXXX our implementation does not currently detect this. See bug 30920. */
- /*
tt_u64_op(config_parse_memunit("20000000 TB", &ok), OP_EQ, 0);
tt_assert(!ok);
- */
+ // This test fails the double check as the float representing 15000000.5 TB
+ // is greater than (double) INT64_MAX
+ tt_u64_op(config_parse_memunit("15000000.5 TB", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+ // 8388608.1 TB passes double check because it falls in the same float
+ // value as (double)INT64_MAX (which is 2^63) due to precision.
+ // But will fail the int check because the unsigned representation of
+ // the float, which is 2^63, is strictly greater than INT64_MAX (2^63-1)
+ tt_u64_op(config_parse_memunit("8388608.1 TB", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+
+ /* negative float */
+ tt_u64_op(config_parse_memunit("-1.5 GB", &ok), OP_EQ, 0);
+ tt_assert(!ok);
/* i32 overflow */
tt_int_op(config_parse_interval("1000 months", &ok), OP_EQ, -1);
@@ -1037,12 +1040,14 @@ test_confparse_find_option_name(void *arg)
config_mgr_free(mgr);
}
+#ifndef COCCI
#define CONFPARSE_TEST(name, flags) \
{ #name, test_confparse_ ## name, flags, NULL, NULL }
#define BADVAL_TEST(name) \
{ "badval_" #name, test_confparse_assign_badval, 0, \
&passthrough_setup, (void*)&bv_ ## name }
+#endif /* !defined(COCCI) */
struct testcase_t confparse_tests[] = {
CONFPARSE_TEST(init, 0),
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index ebe7c6d36f..fca4d884bb 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -10,6 +10,7 @@
#include "core/or/or.h"
#include "test/test.h"
+#include "app/config/or_options_st.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "feature/hs/hs_common.h"
@@ -312,6 +313,25 @@ test_conn_download_status_teardown(const struct testcase_t *tc, void *arg)
return rv;
}
+static void *
+test_conn_proxy_connect_setup(const struct testcase_t *tc)
+{
+ return test_conn_get_proxy_or_connection(*(unsigned int *)tc->setup_data);
+}
+
+static int
+test_conn_proxy_connect_teardown(const struct testcase_t *tc, void *arg)
+{
+ (void)tc;
+ or_connection_t *conn = arg;
+
+ tt_assert(conn);
+ assert_connection_ok(&conn->base_, time(NULL));
+
+ done:
+ return 1;
+}
+
/* Like connection_ap_make_link(), but does much less */
static connection_t *
test_conn_get_linked_connection(connection_t *l_conn, uint8_t state)
@@ -360,6 +380,10 @@ static struct testcase_setup_t test_conn_download_status_st = {
test_conn_download_status_setup, test_conn_download_status_teardown
};
+static struct testcase_setup_t test_conn_proxy_connect_st = {
+ test_conn_proxy_connect_setup, test_conn_proxy_connect_teardown
+};
+
static void
test_conn_get_basic(void *arg)
{
@@ -788,6 +812,64 @@ test_conn_download_status(void *arg)
/* the teardown function removes all the connections in the global list*/;
}
+static void
+test_conn_https_proxy_connect(void *arg)
+{
+ size_t sz;
+ char *buf = NULL;
+ or_connection_t *conn = arg;
+
+ MOCK(connection_or_change_state, mock_connection_or_change_state);
+
+ tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_HTTPS_WANT_CONNECT_OK);
+
+ buf = buf_get_contents(conn->base_.outbuf, &sz);
+ tt_str_op(buf, OP_EQ, "CONNECT 127.0.0.1:12345 HTTP/1.0\r\n\r\n");
+
+ done:
+ UNMOCK(connection_or_change_state);
+ tor_free(buf);
+}
+
+static int handshake_start_called = 0;
+
+static int
+handshake_start(or_connection_t *conn, int receiving)
+{
+ (void)receiving;
+
+ tor_assert(conn);
+
+ handshake_start_called = 1;
+ return 0;
+}
+
+static void
+test_conn_haproxy_proxy_connect(void *arg)
+{
+ size_t sz;
+ char *buf = NULL;
+ or_connection_t *conn = arg;
+
+ MOCK(connection_or_change_state, mock_connection_or_change_state);
+ MOCK(connection_tls_start_handshake, handshake_start);
+
+ tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_HAPROXY_WAIT_FOR_FLUSH);
+
+ buf = buf_get_contents(conn->base_.outbuf, &sz);
+ tt_str_op(buf, OP_EQ, "PROXY TCP4 0.0.0.0 127.0.0.1 0 12345\r\n");
+
+ connection_or_finished_flushing(conn);
+
+ tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_CONNECTED);
+ tt_int_op(handshake_start_called, OP_EQ, 1);
+
+ done:
+ UNMOCK(connection_or_change_state);
+ UNMOCK(connection_tls_start_handshake);
+ tor_free(buf);
+}
+
static node_t test_node;
static node_t *
@@ -881,21 +963,38 @@ test_failed_orconn_tracker(void *arg)
;
}
+#ifndef COCCI
#define CONNECTION_TESTCASE(name, fork, setup) \
{ #name, test_conn_##name, fork, &setup, NULL }
+#define STR(x) #x
/* where arg is an expression (constant, variable, compound expression) */
-#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \
- { #name "_" #arg, test_conn_##name, fork, &setup, (void *)arg }
+#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \
+ { #name "_" STR(x), \
+ test_conn_##name, \
+ fork, \
+ &setup, \
+ (void *)arg }
+#endif /* !defined(COCCI) */
+
+static const unsigned int PROXY_CONNECT_ARG = PROXY_CONNECT;
+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, TT_FORK,
test_conn_download_status_st, FLAV_MICRODESC),
- CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
+ CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
test_conn_download_status_st, FLAV_NS),
+
+ CONNECTION_TESTCASE_ARG(https_proxy_connect, TT_FORK,
+ test_conn_proxy_connect_st, &PROXY_CONNECT_ARG),
+ CONNECTION_TESTCASE_ARG(haproxy_proxy_connect, TT_FORK,
+ test_conn_proxy_connect_st, &PROXY_HAPROXY_ARG),
+
//CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair),
{ "failed_orconn_tracker", test_failed_orconn_tracker, TT_FORK, NULL, NULL },
END_OF_TESTCASES
diff --git a/src/test/test_connection.h b/src/test/test_connection.h
index 40121e6d38..bf327c0a3d 100644
--- a/src/test/test_connection.h
+++ b/src/test/test_connection.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_CONNECTION_H
@@ -7,9 +7,10 @@
/** Some constants used by test_connection and helpers */
#define TEST_CONN_FAMILY (AF_INET)
#define TEST_CONN_ADDRESS "127.0.0.1"
+#define TEST_CONN_ADDRESS_2 "127.0.0.2"
#define TEST_CONN_PORT (12345)
#define TEST_CONN_ADDRESS_PORT "127.0.0.1:12345"
-#define TEST_CONN_FD_INIT 50
+#define TEST_CONN_FD_INIT 0x10000
void test_conn_lookup_addr_helper(const char *address,
int family, tor_addr_t *addr);
diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c
index 095ff09350..c805774fa3 100644
--- a/src/test/test_conscache.c
+++ b/src/test/test_conscache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, 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 7c4c92ea42..242e2f7818 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFF_PRIVATE
@@ -1030,7 +1030,7 @@ test_consdiff_apply_diff(void *arg)
/* diff doesn't have enough lines. */
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("too short")
+ expect_single_log_msg_containing("too short");
/* first line doesn't match format-version string. */
smartlist_add_linecpy(diff, area, "foo-bar");
@@ -1038,7 +1038,7 @@ test_consdiff_apply_diff(void *arg)
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("format is not known")
+ expect_single_log_msg_containing("format is not known");
/* The first word of the second header line is not "hash". */
smartlist_clear(diff);
@@ -1048,7 +1048,7 @@ test_consdiff_apply_diff(void *arg)
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("does not include the necessary digests")
+ expect_single_log_msg_containing("does not include the necessary digests");
/* Wrong number of words after "hash". */
smartlist_clear(diff);
@@ -1057,7 +1057,7 @@ test_consdiff_apply_diff(void *arg)
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("does not include the necessary digests")
+ expect_single_log_msg_containing("does not include the necessary digests");
/* base16 digests do not have the expected length. */
smartlist_clear(diff);
@@ -1067,7 +1067,7 @@ test_consdiff_apply_diff(void *arg)
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
expect_single_log_msg_containing("includes base16-encoded digests of "
- "incorrect size")
+ "incorrect size");
/* base16 digests contain non-base16 characters. */
smartlist_clear(diff);
@@ -1078,7 +1078,7 @@ test_consdiff_apply_diff(void *arg)
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("includes malformed digests")
+ expect_single_log_msg_containing("includes malformed digests");
/* Invalid ed diff.
* As tested in apply_ed_diff, but check that apply_diff does return NULL if
@@ -1095,7 +1095,7 @@ test_consdiff_apply_diff(void *arg)
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
expect_single_log_msg_containing("because an ed command was missing a line "
- "number")
+ "number");
/* Base consensus doesn't match its digest as found in the diff. */
smartlist_clear(diff);
diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c
index 74226b8c52..4bec6baeb0 100644
--- a/src/test/test_consdiffmgr.c
+++ b/src/test/test_consdiffmgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFFMGR_PRIVATE
@@ -119,7 +119,7 @@ typedef struct fake_work_queue_ent_t {
void (*reply_fn)(void *);
void *arg;
} fake_work_queue_ent_t;
-static struct workqueue_entry_s *
+static struct workqueue_entry_t *
mock_cpuworker_queue_work(workqueue_priority_t prio,
enum workqueue_reply_t (*fn)(void *, void *),
void (*reply_fn)(void *),
@@ -135,7 +135,7 @@ mock_cpuworker_queue_work(workqueue_priority_t prio,
ent->reply_fn = reply_fn;
ent->arg = arg;
smartlist_add(fake_cpuworker_queue, ent);
- return (struct workqueue_entry_s *)ent;
+ return (struct workqueue_entry_t *)ent;
}
static int
mock_cpuworker_run_work(void)
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 67ba457975..6072148d1b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 55eb79e448..a69ec17db8 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -1,9 +1,10 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONTROL_CMD_PRIVATE
#define CONTROL_GETINFO_PRIVATE
#include "core/or/or.h"
+#include "app/config/config.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "feature/client/bridges.h"
#include "feature/control/control.h"
@@ -11,6 +12,8 @@
#include "feature/control/control_getinfo.h"
#include "feature/control/control_proto.h"
#include "feature/client/entrynodes.h"
+#include "feature/dircache/cached_dir_st.h"
+#include "feature/dircache/dirserv.h"
#include "feature/hs/hs_common.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/rend/rendservice.h"
@@ -119,6 +122,7 @@ test_controller_parse_cmd(void *arg)
control_cmd_args_free(result);
}
+#ifndef COCCI
#define OK(inp, out) \
{ inp "\r\n", out, NULL }
#define ERR(inp, err) \
@@ -128,6 +132,7 @@ test_controller_parse_cmd(void *arg)
{ &syntax, \
ARRAY_LENGTH(array), \
array }
+#endif /* !defined(COCCI) */
static const parser_testcase_t one_to_three_tests[] = {
ERR("", "Need at least 1 argument(s)"),
@@ -1691,6 +1696,138 @@ test_download_status_bridge(void *arg)
return;
}
+/** Mock cached consensus */
+static cached_dir_t *mock_ns_consensus_cache;
+static cached_dir_t *mock_microdesc_consensus_cache;
+
+/** Mock the function that retrieves consensus from cache. These use a
+ * global variable so that they can be cleared from within the test.
+ * The actual code retains the pointer to the consensus data, but
+ * we are doing this here, to prevent memory leaks
+ * from within the tests */
+static cached_dir_t *
+mock_dirserv_get_consensus(const char *flavor_name)
+{
+ if (!strcmp(flavor_name, "ns")) {
+ mock_ns_consensus_cache = tor_malloc_zero(sizeof(cached_dir_t));
+ mock_ns_consensus_cache->dir = tor_strdup("mock_ns_consensus");
+ return mock_ns_consensus_cache;
+ } else {
+ mock_microdesc_consensus_cache = tor_malloc_zero(sizeof(cached_dir_t));
+ mock_microdesc_consensus_cache->dir = tor_strdup(
+ "mock_microdesc_consensus");
+ return mock_microdesc_consensus_cache;
+ }
+}
+
+/** Mock the function that retrieves consensuses
+ * from a files in the directory. */
+static tor_mmap_t *
+mock_tor_mmap_file(const char* filename)
+{
+ tor_mmap_t *res;
+ res = tor_malloc_zero(sizeof(tor_mmap_t));
+ if (strstr(filename, "cached-consensus") != NULL) {
+ res->data = "mock_ns_consensus";
+ } else if (strstr(filename, "cached-microdesc-consensus") != NULL) {
+ res->data = "mock_microdesc_consensus";
+ } else {
+ res->data = ".";
+ }
+ res->size = strlen(res->data);
+ return res;
+}
+
+/** Mock the function that clears file data
+ * loaded into the memory */
+static int
+mock_tor_munmap_file(tor_mmap_t *handle)
+{
+ tor_free(handle);
+ return 0;
+}
+
+static void
+test_getinfo_helper_current_consensus_from_file(void *arg)
+{
+ /* We just need one of these to pass, it doesn't matter what's in it */
+ control_connection_t dummy;
+ /* Get results out */
+ char *answer = NULL;
+ const char *errmsg = NULL;
+
+ (void)arg;
+
+ MOCK(tor_mmap_file, mock_tor_mmap_file);
+ MOCK(tor_munmap_file, mock_tor_munmap_file);
+
+ getinfo_helper_dir(&dummy,
+ "dir/status-vote/current/consensus",
+ &answer,
+ &errmsg);
+ tt_str_op(answer, OP_EQ, "mock_ns_consensus");
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_dir(&dummy,
+ "dir/status-vote/current/consensus-microdesc",
+ &answer,
+ &errmsg);
+ tt_str_op(answer, OP_EQ, "mock_microdesc_consensus");
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ errmsg = NULL;
+
+ done:
+ tor_free(answer);
+ UNMOCK(tor_mmap_file);
+ UNMOCK(tor_munmap_file);
+ return;
+}
+
+static void
+test_getinfo_helper_current_consensus_from_cache(void *arg)
+{
+ /* We just need one of these to pass, it doesn't matter what's in it */
+ control_connection_t dummy;
+ /* Get results out */
+ char *answer = NULL;
+ const char *errmsg = NULL;
+
+ (void)arg;
+ or_options_t *options = get_options_mutable();
+ options->FetchUselessDescriptors = 1;
+ MOCK(dirserv_get_consensus, mock_dirserv_get_consensus);
+
+ getinfo_helper_dir(&dummy,
+ "dir/status-vote/current/consensus",
+ &answer,
+ &errmsg);
+ tt_str_op(answer, OP_EQ, "mock_ns_consensus");
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tor_free(answer);
+ tor_free(mock_ns_consensus_cache->dir);
+ tor_free(mock_ns_consensus_cache);
+ errmsg = NULL;
+
+ getinfo_helper_dir(&dummy,
+ "dir/status-vote/current/consensus-microdesc",
+ &answer,
+ &errmsg);
+ tt_str_op(answer, OP_EQ, "mock_microdesc_consensus");
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tor_free(mock_microdesc_consensus_cache->dir);
+ tor_free(answer);
+ errmsg = NULL;
+
+ done:
+ options->FetchUselessDescriptors = 0;
+ tor_free(answer);
+ tor_free(mock_microdesc_consensus_cache);
+ UNMOCK(dirserv_get_consensus);
+ return;
+}
+
/** Set timeval to a mock date and time. This is necessary
* to make tor_gettimeofday() mockable. */
static void
@@ -1820,9 +1957,166 @@ test_getinfo_md_all(void *arg)
return;
}
+static smartlist_t *reply_strs;
+
+static void
+mock_control_write_reply_list(control_connection_t *conn, int code, int c,
+ const char *s)
+{
+ (void)conn;
+ /* To make matching easier, don't append "\r\n" */
+ smartlist_add_asprintf(reply_strs, "%03d%c%s", code, c, s);
+}
+
+static void
+test_control_reply(void *arg)
+{
+ (void)arg;
+ smartlist_t *lines = smartlist_new();
+
+ MOCK(control_write_reply, mock_control_write_reply);
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ control_reply_add_str(lines, 250, "FOO");
+ control_write_reply_lines(NULL, lines);
+ tt_str_op(reply_str, OP_EQ, "FOO");
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ control_reply_add_done(lines);
+ control_write_reply_lines(NULL, lines);
+ tt_str_op(reply_str, OP_EQ, "OK");
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ UNMOCK(control_write_reply);
+ MOCK(control_write_reply, mock_control_write_reply_list);
+ reply_strs = smartlist_new();
+ control_reply_add_one_kv(lines, 250, 0, "A", "B");
+ control_reply_add_one_kv(lines, 250, 0, "C", "D");
+ control_write_reply_lines(NULL, lines);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 2);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250-A=B");
+ tt_str_op((char *)smartlist_get(reply_strs, 1), OP_EQ, "250 C=D");
+
+ control_reply_clear(lines);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+ control_reply_add_printf(lines, 250, "PROTOCOLINFO %d", 1);
+ control_reply_add_one_kv(lines, 250, KV_OMIT_VALS|KV_RAW, "AUTH", "");
+ control_reply_append_kv(lines, "METHODS", "COOKIE");
+ control_reply_append_kv(lines, "COOKIEFILE", escaped("/tmp/cookie"));
+ control_reply_add_done(lines);
+ control_write_reply_lines(NULL, lines);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 3);
+ tt_str_op((char *)smartlist_get(reply_strs, 0),
+ OP_EQ, "250-PROTOCOLINFO 1");
+ tt_str_op((char *)smartlist_get(reply_strs, 1),
+ OP_EQ, "250-AUTH METHODS=COOKIE COOKIEFILE=\"/tmp/cookie\"");
+ tt_str_op((char *)smartlist_get(reply_strs, 2),
+ OP_EQ, "250 OK");
+
+ done:
+ UNMOCK(control_write_reply);
+ tor_free(reply_str);
+ control_reply_free(lines);
+ if (reply_strs)
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_free(reply_strs);
+ return;
+}
+
+static void
+test_control_getconf(void *arg)
+{
+ (void)arg;
+ control_connection_t conn;
+ char *args = NULL;
+ int r = -1;
+
+ memset(&conn, 0, sizeof(conn));
+ conn.current_cmd = tor_strdup("GETCONF");
+
+ MOCK(control_write_reply, mock_control_write_reply_list);
+ reply_strs = smartlist_new();
+
+ args = tor_strdup("");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 1);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250 OK");
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+ tor_free(args);
+
+ args = tor_strdup("NoSuch");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 1);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ,
+ "552 Unrecognized configuration key \"NoSuch\"");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ args = tor_strdup("NoSuch1 NoSuch2");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 2);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ,
+ "552-Unrecognized configuration key \"NoSuch1\"");
+ tt_str_op((char *)smartlist_get(reply_strs, 1), OP_EQ,
+ "552 Unrecognized configuration key \"NoSuch2\"");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ args = tor_strdup("ControlPort NoSuch");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ /* Valid keys ignored if there are any invalid ones */
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 1);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ,
+ "552 Unrecognized configuration key \"NoSuch\"");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ args = tor_strdup("ClientOnly");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 1);
+ /* According to config.c, this is an exception for the unit tests */
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250 ClientOnly=0");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ args = tor_strdup("BridgeRelay ClientOnly");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 2);
+ /* Change if config.c changes BridgeRelay default (unlikely) */
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250-BridgeRelay=0");
+ tt_str_op((char *)smartlist_get(reply_strs, 1), OP_EQ, "250 ClientOnly=0");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ done:
+ tor_free(conn.current_cmd);
+ tor_free(args);
+ UNMOCK(control_write_reply);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_free(reply_strs);
+}
+
+#ifndef COCCI
#define PARSER_TEST(type) \
{ "parse/" #type, test_controller_parse_cmd, 0, &passthrough_setup, \
(void*)&parse_ ## type ## _params }
+#endif
struct testcase_t controller_tests[] = {
PARSER_TEST(one_to_three),
@@ -1840,11 +2134,17 @@ struct testcase_t controller_tests[] = {
NULL },
{ "download_status_consensus", test_download_status_consensus, 0, NULL,
NULL },
+ {"getinfo_helper_current_consensus_from_cache",
+ test_getinfo_helper_current_consensus_from_cache, 0, NULL, NULL },
+ {"getinfo_helper_current_consensus_from_file",
+ test_getinfo_helper_current_consensus_from_file, 0, NULL, NULL },
{ "download_status_cert", test_download_status_cert, 0, NULL,
NULL },
{ "download_status_desc", test_download_status_desc, 0, NULL, NULL },
{ "download_status_bridge", test_download_status_bridge, 0, NULL, NULL },
{ "current_time", test_current_time, 0, NULL, NULL },
{ "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL },
+ { "control_reply", test_control_reply, 0, NULL, NULL },
+ { "control_getconf", test_control_getconf, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
index 0d276ef8a6..60dfbd630a 100644
--- a/src/test/test_controller_events.c
+++ b/src/test/test_controller_events.c
@@ -1,8 +1,8 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CONTROL_PRIVATE
#define CONTROL_EVENTS_PRIVATE
#define OCIRC_EVENT_PRIVATE
@@ -16,12 +16,15 @@
#include "core/or/orconn_event.h"
#include "core/mainloop/connection.h"
#include "feature/control/control_events.h"
+#include "feature/control/control_fmt.h"
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
+#include "core/or/entry_connection_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
+#include "core/or/socks_request_st.h"
static void
add_testing_cell_stats_entry(circuit_t *circ, uint8_t command,
@@ -575,6 +578,133 @@ test_cntev_orconn_state_proxy(void *arg)
UNMOCK(queue_control_event_string);
}
+static void
+test_cntev_format_stream(void *arg)
+{
+ entry_connection_t *ec = NULL;
+ char *conndesc = NULL;
+ (void)arg;
+
+ ec = entry_connection_new(CONN_TYPE_AP, AF_INET);
+
+ char *username = tor_strdup("jeremy");
+ char *password = tor_strdup("letmein");
+ ec->socks_request->username = username; // steal reference
+ ec->socks_request->usernamelen = strlen(username);
+ ec->socks_request->password = password; // steal reference
+ ec->socks_request->passwordlen = strlen(password);
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "SOCKS_USERNAME=\"jeremy\""));
+ tt_assert(strstr(conndesc, "SOCKS_PASSWORD=\"letmein\""));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_LISTENER;
+ ec->socks_request->socks_version = 4;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=SOCKS4"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_LISTENER;
+ ec->socks_request->socks_version = 5;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=SOCKS5"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_LISTENER;
+ ec->socks_request->socks_version = 6;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=UNKNOWN"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_TRANS_LISTENER;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=TRANS"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_NATD_LISTENER;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=NATD"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_DNS_LISTENER;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=DNS"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_HTTP_CONNECT_LISTENER;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=HTTPCONNECT"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_OR;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=UNKNOWN"));
+ tor_free(conndesc);
+
+ ec->nym_epoch = 1337;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "NYM_EPOCH=1337"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.session_group = 4321;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "SESSION_GROUP=4321"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_DESTPORT;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=DESTPORT"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=DESTPORT,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_DESTADDR;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=DESTADDR"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=DESTADDR,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_SOCKSAUTH;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=SOCKS_USERNAME,SOCKS_PASSWORD"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=SOCKS_USERNAME,SOCKS_PASSWORD,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_CLIENTPROTO;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=CLIENT_PROTOCOL"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=CLIENT_PROTOCOL,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_CLIENTADDR;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=CLIENTADDR"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=CLIENTADDR,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_SESSIONGRP;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=SESSION_GROUP"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=SESSION_GROUP,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_NYM_EPOCH;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=NYM_EPOCH"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=NYM_EPOCH,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_DESTPORT | ISO_SOCKSAUTH | ISO_NYM_EPOCH;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc,
+ "ISO_FIELDS=DESTPORT,SOCKS_USERNAME,SOCKS_PASSWORD,NYM_EPOCH"));
+ tt_assert(!strstr(conndesc,
+ "ISO_FIELDS=DESTPORT,SOCKS_USERNAME,SOCKS_PASSWORD,NYM_EPOCH,"));
+
+ done:
+ tor_free(conndesc);
+ connection_free_minimal(ENTRY_TO_CONN(ec));
+}
+
#define TEST(name, flags) \
{ #name, test_cntev_ ## name, flags, 0, NULL }
@@ -586,9 +716,10 @@ struct testcase_t controller_event_tests[] = {
TEST(append_cell_stats, TT_FORK),
TEST(format_cell_stats, TT_FORK),
TEST(event_mask, TT_FORK),
+ TEST(format_stream, TT_FORK),
+ TEST(signal, TT_FORK),
T_PUBSUB(dirboot_defer_desc, TT_FORK),
T_PUBSUB(dirboot_defer_orconn, TT_FORK),
- T_PUBSUB(signal, TT_FORK),
T_PUBSUB(orconn_state, TT_FORK),
T_PUBSUB(orconn_state_pt, TT_FORK),
T_PUBSUB(orconn_state_proxy, TT_FORK),
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index ed39f41560..0d75a212e9 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -29,9 +29,9 @@
#if defined(ENABLE_OPENSSL)
#include "lib/crypt_ops/compat_openssl.h"
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/dh.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#endif /* defined(ENABLE_OPENSSL) */
/** Run unit tests for Diffie-Hellman functionality. */
@@ -3009,6 +3009,7 @@ test_crypto_failure_modes(void *arg)
;
}
+#ifndef COCCI
#define CRYPTO_LEGACY(name) \
{ #name, test_crypto_ ## name , 0, NULL, NULL }
@@ -3019,6 +3020,7 @@ test_crypto_failure_modes(void *arg)
#define ED25519_TEST(name, fl) \
ED25519_TEST_ONE(name, (fl), "donna"), \
ED25519_TEST_ONE(name, (fl), "ref10")
+#endif /* !defined(COCCI) */
struct testcase_t crypto_tests[] = {
CRYPTO_LEGACY(formats),
diff --git a/src/test/test_crypto_ope.c b/src/test/test_crypto_ope.c
index dc67c02676..119ebc114a 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 42dc3f6be2..989f4a56ca 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 6b7749a889..b0dc4c117c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 3b20dfa587..1702427b08 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -342,7 +342,7 @@ test_crypto_scrypt_vectors(void *arg)
#endif
/* Test vectors from
- http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
+ https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
Note that the names of 'r' and 'N' are switched in that section. Or
possibly in libscrypt.
@@ -584,6 +584,7 @@ test_crypto_ed25519_fuzz_donna(void *arg)
;
}
+#ifndef COCCI
#define CRYPTO_LEGACY(name) \
{ #name, test_crypto_ ## name , 0, NULL, NULL }
@@ -594,6 +595,7 @@ test_crypto_ed25519_fuzz_donna(void *arg)
#define ED25519_TEST(name, fl) \
ED25519_TEST_ONE(name, (fl), "donna"), \
ED25519_TEST_ONE(name, (fl), "ref10")
+#endif /* !defined(COCCI) */
struct testcase_t slow_crypto_tests[] = {
CRYPTO_LEGACY(s2k_rfc2440),
diff --git a/src/test/test_data.c b/src/test/test_data.c
index fe1190ea77..30c14fcfff 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 6329ff7750..3a0b8237cb 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -9,9 +9,9 @@
#define BWAUTH_PRIVATE
#define CONFIG_PRIVATE
#define CONTROL_GETINFO_PRIVATE
+#define DIRAUTH_SYS_PRIVATE
#define DIRCACHE_PRIVATE
#define DIRCLIENT_PRIVATE
-#define DIRSERV_PRIVATE
#define DIRVOTE_PRIVATE
#define DLSTATUS_PRIVATE
#define HIBERNATE_PRIVATE
@@ -26,7 +26,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "core/mainloop/connection.h"
#include "core/or/relay.h"
#include "core/or/versions.h"
@@ -34,6 +34,7 @@
#include "feature/client/entrynodes.h"
#include "feature/control/control_getinfo.h"
#include "feature/dirauth/bwauth.h"
+#include "feature/dirauth/dirauth_sys.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/dsigs_parse.h"
#include "feature/dirauth/process_descs.h"
@@ -46,10 +47,11 @@
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/dircommon/fp_pair.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/hibernate/hibernate.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
+#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nickname.h"
#include "feature/nodelist/node_select.h"
@@ -71,13 +73,16 @@
#include "lib/memarea/memarea.h"
#include "lib/osinfo/uname.h"
#include "test/log_test_helpers.h"
+#include "test/opts_test_helpers.h"
#include "test/test.h"
#include "test/test_dir_common.h"
#include "core/or/addr_policy_st.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/document_signature_st.h"
#include "feature/nodelist/extrainfo_st.h"
+#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/networkstatus_voter_info_st.h"
#include "feature/dirauth/ns_detached_signatures_st.h"
@@ -95,8 +100,6 @@
#include <unistd.h>
#endif
-#define NS_MODULE dir
-
static networkstatus_t *
networkstatus_parse_vote_from_string_(const char *s,
const char **eos_out,
@@ -635,7 +638,6 @@ setup_dir_formats_options(const char *arg, or_options_t *options)
STMT_BEGIN \
tt_assert(r1); \
tt_assert(rp1); \
-\
tt_int_op(rp1->addr,OP_EQ, r1->addr); \
tt_int_op(rp1->or_port,OP_EQ, r1->or_port); \
tt_int_op(rp1->dir_port,OP_EQ, r1->dir_port); \
@@ -3003,6 +3005,7 @@ test_dir_param_voting_lookup(void *arg)
tt_int_op(99, OP_EQ,
dirvote_get_intermediate_param_value(lst, "abcd", 1000));
+#ifndef ALL_BUGS_ARE_FATAL
/* moomin appears twice. That's a bug. */
tor_capture_bugs_(1);
tt_int_op(-100, OP_EQ,
@@ -3020,7 +3023,7 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "jack", -100));
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
/* electricity and opa aren't integers. */
tor_capture_bugs_(1);
@@ -3028,7 +3031,7 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "electricity", -100));
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
tor_capture_bugs_(1);
@@ -3036,8 +3039,9 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "opa", -100));
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
done:
SMARTLIST_FOREACH(lst, char *, cp, tor_free(cp));
@@ -3608,7 +3612,7 @@ test_a_networkstatus(
sign_skey_2 = crypto_pk_new();
sign_skey_3 = crypto_pk_new();
sign_skey_leg1 = pk_generate(4);
- voting_schedule_recalculate_timing(get_options(), now);
+ dirauth_sched_recalculate_timing(get_options(), now);
sr_state_init(0, 0);
tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_1,
@@ -4691,10 +4695,13 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
(void)arg;
/* Init options */
+ dirauth_options_t *dirauth_options =
+ tor_malloc_zero(sizeof(dirauth_options_t));
+
mock_options = tor_malloc(sizeof(or_options_t));
reset_options(mock_options, &mock_get_options_calls);
-
MOCK(get_options, mock_get_options);
+ dirauth_set_options(dirauth_options);
/* Init routersets */
routerset_t *routerset_all = routerset_new();
@@ -4734,16 +4741,15 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check that "*" sets flags on all routers: Exit
* Check the flags aren't being confused with each other */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_all;
- mock_options->TestingDirAuthVoteExitIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteExit = routerset_all;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 2);
tt_uint_op(rs_a->is_exit, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 1);
@@ -4756,18 +4762,17 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check that "*" sets flags on all routers: Guard & HSDir
* Cover the remaining flags in one test */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteGuard = routerset_all;
- mock_options->TestingDirAuthVoteGuardIsStrict = 0;
- mock_options->TestingDirAuthVoteHSDir = routerset_all;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_all;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_all;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 2);
tt_uint_op(rs_a->is_possible_guard, OP_EQ, 1);
tt_uint_op(rs_b->is_possible_guard, OP_EQ, 1);
@@ -4780,20 +4785,19 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check routerset A sets all flags on router A,
* but leaves router B unmodified */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_a;
- mock_options->TestingDirAuthVoteExitIsStrict = 0;
- mock_options->TestingDirAuthVoteGuard = routerset_a;
- mock_options->TestingDirAuthVoteGuardIsStrict = 0;
- mock_options->TestingDirAuthVoteHSDir = routerset_a;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteExit = routerset_a;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_a;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_a;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 2);
tt_uint_op(rs_a->is_exit, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 0);
@@ -4804,21 +4808,21 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check routerset A unsets all flags on router B when Strict is set */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_a;
- mock_options->TestingDirAuthVoteExitIsStrict = 1;
- mock_options->TestingDirAuthVoteGuard = routerset_a;
- mock_options->TestingDirAuthVoteGuardIsStrict = 1;
- mock_options->TestingDirAuthVoteHSDir = routerset_a;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteExit = routerset_a;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_a;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_a;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 1;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 0);
tt_uint_op(rs_b->is_possible_guard, OP_EQ, 0);
@@ -4826,21 +4830,21 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check routerset A doesn't modify flags on router B without Strict set */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_a;
- mock_options->TestingDirAuthVoteExitIsStrict = 0;
- mock_options->TestingDirAuthVoteGuard = routerset_a;
- mock_options->TestingDirAuthVoteGuardIsStrict = 0;
- mock_options->TestingDirAuthVoteHSDir = routerset_a;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteExit = routerset_a;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_a;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_a;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 0;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 1);
tt_uint_op(rs_b->is_possible_guard, OP_EQ, 1);
@@ -4849,21 +4853,21 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check the empty routerset zeroes all flags
* on routers A & B with Strict set */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_none;
- mock_options->TestingDirAuthVoteExitIsStrict = 1;
- mock_options->TestingDirAuthVoteGuard = routerset_none;
- mock_options->TestingDirAuthVoteGuardIsStrict = 1;
- mock_options->TestingDirAuthVoteHSDir = routerset_none;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteExit = routerset_none;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_none;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_none;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 1;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 0);
tt_uint_op(rs_b->is_possible_guard, OP_EQ, 0);
@@ -4872,24 +4876,23 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check the empty routerset doesn't modify any flags
* on A or B without Strict set */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_none;
- mock_options->TestingDirAuthVoteExitIsStrict = 0;
- mock_options->TestingDirAuthVoteGuard = routerset_none;
- mock_options->TestingDirAuthVoteGuardIsStrict = 0;
- mock_options->TestingDirAuthVoteHSDir = routerset_none;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteExit = routerset_none;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_none;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_none;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 0;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_a);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 2);
tt_uint_op(rs_a->is_exit, OP_EQ, 0);
tt_uint_op(rs_a->is_possible_guard, OP_EQ, 0);
@@ -4900,6 +4903,7 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
done:
tor_free(mock_options);
+ tor_free(dirauth_options);
mock_options = NULL;
UNMOCK(get_options);
@@ -4987,6 +4991,14 @@ test_dir_purpose_needs_anonymity_returns_true_by_default(void *arg)
{
(void)arg;
+#ifdef ALL_BUGS_ARE_FATAL
+ /* Coverity (and maybe clang analyser) complain that the code following
+ * tt_skip() is unconditionally unreachable. */
+#if !defined(__COVERITY__) && !defined(__clang_analyzer__)
+ tt_skip();
+#endif
+#endif /* defined(ALL_BUGS_ARE_FATAL) */
+
tor_capture_bugs_(1);
setup_full_capture_of_logs(LOG_WARN);
tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, 0, NULL));
@@ -5474,15 +5486,15 @@ test_dir_conn_purpose_to_string(void *data)
teardown_capture_of_logs();
}
-NS_DECL(int,
-public_server_mode, (const or_options_t *options));
+static int dir_tests_public_server_mode(const or_options_t *options);
+ATTR_UNUSED static int dir_tests_public_server_mode_called = 0;
static int
-NS(public_server_mode)(const or_options_t *options)
+dir_tests_public_server_mode(const or_options_t *options)
{
(void)options;
- if (CALLED(public_server_mode)++ == 0) {
+ if (dir_tests_public_server_mode_called++ == 0) {
return 1;
}
@@ -5496,13 +5508,14 @@ test_dir_should_use_directory_guards(void *data)
char *errmsg = NULL;
(void)data;
- NS_MOCK(public_server_mode);
+ MOCK(public_server_mode,
+ dir_tests_public_server_mode);
options = options_new();
options_init(options);
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 1);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 1);
options->UseEntryGuards = 1;
options->DownloadExtraInfo = 0;
@@ -5510,41 +5523,41 @@ test_dir_should_use_directory_guards(void *data)
options->FetchDirInfoExtraEarly = 0;
options->FetchUselessDescriptors = 0;
tt_int_op(should_use_directory_guards(options), OP_EQ, 1);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 2);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 2);
options->UseEntryGuards = 0;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 3);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 3);
options->UseEntryGuards = 1;
options->DownloadExtraInfo = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 4);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 4);
options->DownloadExtraInfo = 0;
options->FetchDirInfoEarly = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 5);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 5);
options->FetchDirInfoEarly = 0;
options->FetchDirInfoExtraEarly = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 6);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 6);
options->FetchDirInfoExtraEarly = 0;
options->FetchUselessDescriptors = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 7);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 7);
options->FetchUselessDescriptors = 0;
done:
- NS_UNMOCK(public_server_mode);
+ UNMOCK(public_server_mode);
or_options_free(options);
tor_free(errmsg);
}
-NS_DECL(void,
-directory_initiate_request, (directory_request_t *req));
+static void dir_tests_directory_initiate_request(directory_request_t *req);
+ATTR_UNUSED static int dir_tests_directory_initiate_request_called = 0;
static void
test_dir_should_not_init_request_to_ourselves(void *data)
@@ -5554,7 +5567,8 @@ test_dir_should_not_init_request_to_ourselves(void *data)
crypto_pk_t *key = pk_generate(2);
(void) data;
- NS_MOCK(directory_initiate_request);
+ MOCK(directory_initiate_request,
+ dir_tests_directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -5569,15 +5583,15 @@ test_dir_should_not_init_request_to_ourselves(void *data)
dir_server_add(ourself);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 0);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 0);
done:
- NS_UNMOCK(directory_initiate_request);
+ UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
crypto_pk_free(key);
@@ -5591,7 +5605,8 @@ test_dir_should_not_init_request_to_dir_auths_without_v3_info(void *data)
| MICRODESC_DIRINFO;
(void) data;
- NS_MOCK(directory_initiate_request);
+ MOCK(directory_initiate_request,
+ dir_tests_directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -5602,14 +5617,14 @@ test_dir_should_not_init_request_to_dir_auths_without_v3_info(void *data)
dir_server_add(ds);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 0);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 0);
done:
- NS_UNMOCK(directory_initiate_request);
+ UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
}
@@ -5620,7 +5635,8 @@ test_dir_should_init_request_to_dir_auths(void *data)
dir_server_t *ds = NULL;
(void) data;
- NS_MOCK(directory_initiate_request);
+ MOCK(directory_initiate_request,
+ dir_tests_directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -5631,23 +5647,23 @@ test_dir_should_init_request_to_dir_auths(void *data)
dir_server_add(ds);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 1);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 1);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 2);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 2);
done:
- NS_UNMOCK(directory_initiate_request);
+ UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
}
void
-NS(directory_initiate_request)(directory_request_t *req)
+dir_tests_directory_initiate_request(directory_request_t *req)
{
(void)req;
- CALLED(directory_initiate_request)++;
+ dir_tests_directory_initiate_request_called++;
}
static void
@@ -7067,98 +7083,6 @@ test_dir_platform_str(void *arg)
;
}
-static networkstatus_t *mock_networkstatus;
-
-static networkstatus_t *
-mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
-{
- (void)f;
- return mock_networkstatus;
-}
-
-static void
-test_dir_networkstatus_consensus_has_ipv6(void *arg)
-{
- (void)arg;
-
- int has_ipv6 = 0;
-
- /* Init options and networkstatus */
- or_options_t our_options;
- mock_options = &our_options;
- reset_options(mock_options, &mock_get_options_calls);
- MOCK(get_options, mock_get_options);
-
- networkstatus_t our_networkstatus;
- mock_networkstatus = &our_networkstatus;
- memset(mock_networkstatus, 0, sizeof(*mock_networkstatus));
- MOCK(networkstatus_get_latest_consensus_by_flavor,
- mock_networkstatus_get_latest_consensus_by_flavor);
-
- /* A live consensus */
- mock_networkstatus->valid_after = time(NULL) - 3600;
- mock_networkstatus->valid_until = time(NULL) + 3600;
-
- /* Test the bounds for A lines in the NS consensus */
- mock_options->UseMicrodescriptors = 0;
-
- mock_networkstatus->consensus_method = MIN_SUPPORTED_CONSENSUS_METHOD;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- /* Test the bounds for A lines in the microdesc consensus */
- mock_options->UseMicrodescriptors = 1;
-
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- mock_networkstatus->consensus_method = MAX_SUPPORTED_CONSENSUS_METHOD + 20;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS + 1;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS + 20;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS - 1;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(!has_ipv6);
-
- /* Test the edge cases */
- mock_options->UseMicrodescriptors = 1;
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
-
- /* Reasonably live */
- mock_networkstatus->valid_until = approx_time() - 60;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- /* Not reasonably live */
- mock_networkstatus->valid_after = approx_time() - 24*60*60 - 3600;
- mock_networkstatus->valid_until = approx_time() - 24*60*60 - 60;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(!has_ipv6);
-
- /* NULL consensus */
- mock_networkstatus = NULL;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(!has_ipv6);
-
- done:
- UNMOCK(get_options);
- UNMOCK(networkstatus_get_latest_consensus_by_flavor);
-}
-
static void
test_dir_format_versions_list(void *arg)
{
@@ -7210,6 +7134,301 @@ test_dir_format_versions_list(void *arg)
teardown_capture_of_logs();
}
+static void
+test_dir_add_fingerprint(void *arg)
+{
+ (void)arg;
+ authdir_config_t *list;
+ int ret;
+ ed25519_secret_key_t seckey;
+ ed25519_public_key_t pubkey_good, pubkey_bad;
+
+ authdir_init_fingerprint_list();
+ list = authdir_return_fingerprint_list();
+
+ setup_capture_of_logs(LOG_WARN);
+
+ /* RSA test - successful */
+ ret = add_rsa_fingerprint_to_dir("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ list, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* RSA test - failure */
+ ret = add_rsa_fingerprint_to_dir("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
+ list, 0);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* ed25519 test - successful */
+ ed25519_secret_key_generate(&seckey, 0);
+ ed25519_public_key_generate(&pubkey_good, &seckey);
+
+ ret = add_ed25519_to_dir(&pubkey_good, list, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* ed25519 test - failure */
+ digest256_from_base64((char *) pubkey_bad.pubkey, "gibberish");
+
+ ret = add_ed25519_to_dir(&pubkey_bad, list, 0);
+ tt_int_op(ret, OP_EQ, -1);
+
+ done:
+ teardown_capture_of_logs();
+ dirserv_free_fingerprint_list();
+}
+
+static void
+test_dir_dirserv_load_fingerprint_file(void *arg)
+{
+ (void)arg;
+ char *fname = tor_strdup(get_fname("approved-routers"));
+
+ // Neither RSA nor ed25519
+ const char *router_lines_invalid =
+ "!badexit notafingerprint";
+ const char *router_lines_too_long =
+ "!badexit thisisareallylongstringthatislongerthanafingerprint\n";
+ const char *router_lines_bad_fmt_str =
+ "!badexit ABCDEFGH|%1$p|%2$p|%3$p|%4$p|%5$p|%6$p\n";
+ const char *router_lines_valid_rsa =
+ "!badexit AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n";
+ const char *router_lines_invalid_rsa =
+ "!badexit ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\n";
+ const char *router_lines_valid_ed25519 =
+ "!badexit wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n";
+ const char *router_lines_invalid_ed25519 =
+ "!badexit --fLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx--\n";
+
+ // Test: Invalid Fingerprint (not RSA or ed25519)
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_invalid, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ // Test: Very long string (longer than RSA or ed25519 key)
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_too_long, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ // Test: Formt string exploit
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_bad_fmt_str, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ // Test: Valid RSA
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_valid_rsa, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ teardown_capture_of_logs();
+
+ // Test: Invalid RSA
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_invalid_rsa, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ // Test: Valid ed25519
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_valid_ed25519, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ teardown_capture_of_logs();
+
+ // Test: Invalid ed25519
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_invalid_ed25519, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ done:
+ tor_free(fname);
+ dirserv_free_fingerprint_list();
+}
+
+#define RESET_FP_LIST(list) STMT_BEGIN \
+ dirserv_free_fingerprint_list(); \
+ authdir_init_fingerprint_list(); \
+ list = authdir_return_fingerprint_list(); \
+ STMT_END
+
+static void
+test_dir_dirserv_router_get_status(void *arg)
+{
+ authdir_config_t *list;
+ routerinfo_t *ri = NULL;
+ ed25519_keypair_t kp1, kp2;
+ char d[DIGEST_LEN];
+ char fp[HEX_DIGEST_LEN+1];
+ int ret;
+ const char *msg;
+ time_t now = time(NULL);
+
+ (void)arg;
+
+ crypto_pk_t *pk = pk_generate(0);
+
+ authdir_init_fingerprint_list();
+ list = authdir_return_fingerprint_list();
+
+ /* Set up the routerinfo */
+ ri = tor_malloc_zero(sizeof(routerinfo_t));
+ ri->addr = 0xc0a80001u;
+ ri->or_port = 9001;
+ ri->platform = tor_strdup("0.4.0.1-alpha");
+ ri->nickname = tor_strdup("Jessica");
+ ri->identity_pkey = crypto_pk_dup_key(pk);
+
+ curve25519_keypair_t ri_onion_keypair;
+ curve25519_keypair_generate(&ri_onion_keypair, 0);
+ ri->onion_curve25519_pkey = tor_memdup(&ri_onion_keypair.pubkey,
+ sizeof(curve25519_public_key_t));
+
+ ed25519_secret_key_from_seed(&kp1.seckey,
+ (const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
+ ed25519_public_key_generate(&kp1.pubkey, &kp1.seckey);
+ ed25519_secret_key_from_seed(&kp2.seckey,
+ (const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
+ ri->cache_info.signing_key_cert = tor_cert_create(&kp1,
+ CERT_TYPE_ID_SIGNING,
+ &kp2.pubkey,
+ now, 86400,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+
+ crypto_pk_get_digest(ri->identity_pkey, d);
+ base16_encode(fp, HEX_DIGEST_LEN + 1, d, DIGEST_LEN);
+
+ /* Try on an empty fingerprint list */
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, 0);
+ RESET_FP_LIST(list);
+
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, 0);
+ RESET_FP_LIST(list);
+
+ /* Try an accepted router */
+ add_rsa_fingerprint_to_dir(fp, list, 0);
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, 0);
+ RESET_FP_LIST(list);
+
+ add_ed25519_to_dir(&kp1.pubkey, list, 0);
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, 0);
+ RESET_FP_LIST(list);
+
+ /* Try a rejected router */
+ add_rsa_fingerprint_to_dir(fp, list, RTR_REJECT);
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, RTR_REJECT);
+ RESET_FP_LIST(list);
+
+ add_ed25519_to_dir(&kp1.pubkey, list, RTR_REJECT);
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, RTR_REJECT);
+ RESET_FP_LIST(list);
+
+ done:
+ dirserv_free_fingerprint_list();
+ routerinfo_free(ri);
+ crypto_pk_free(pk);
+}
+
+static void
+test_dir_dirserv_would_reject_router(void *arg)
+{
+ authdir_config_t *list;
+ routerstatus_t rs;
+ vote_routerstatus_t vrs;
+ ed25519_keypair_t kp;
+ char fp[HEX_DIGEST_LEN+1];
+
+ (void)arg;
+
+ authdir_init_fingerprint_list();
+ list = authdir_return_fingerprint_list();
+
+ /* Set up the routerstatus */
+ memset(&rs, 0, sizeof(rs));
+ rs.addr = 0xc0a80001u;
+ rs.or_port = 9001;
+ strlcpy(rs.nickname, "Nicole", sizeof(rs.nickname));
+ memcpy(rs.identity_digest, "Cloud nine is great ", DIGEST_LEN);
+
+ ed25519_secret_key_from_seed(&kp.seckey,
+ (const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
+ ed25519_public_key_generate(&kp.pubkey, &kp.seckey);
+
+ base16_encode(fp, HEX_DIGEST_LEN + 1, rs.identity_digest, DIGEST_LEN);
+
+ /* Setup the vote_routerstatus_t. */
+ memcpy(vrs.ed25519_id, &kp.pubkey, ED25519_PUBKEY_LEN);
+
+ /* Try an empty fingerprint list */
+ tt_assert(!dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ tt_assert(!dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ /* Try an accepted router */
+ add_rsa_fingerprint_to_dir(fp, list, 0);
+ tt_assert(!dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ add_ed25519_to_dir(&kp.pubkey, list, 0);
+ tt_assert(!dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ /* Try a rejected router */
+ add_rsa_fingerprint_to_dir(fp, list, RTR_REJECT);
+ tt_assert(dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ add_ed25519_to_dir(&kp.pubkey, list, RTR_REJECT);
+ tt_assert(dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ done:
+ dirserv_free_fingerprint_list();
+}
+
+static void
+test_dir_dirserv_add_own_fingerprint(void *arg)
+{
+ authdir_config_t *list;
+ char digest[DIGEST_LEN];
+ crypto_pk_t *pk = pk_generate(0);
+
+ (void)arg;
+
+ init_mock_ed_keys(pk);
+ authdir_init_fingerprint_list();
+ list = authdir_return_fingerprint_list();
+ dirserv_add_own_fingerprint(pk, get_master_identity_key());
+
+ /* Check if we have a RSA key. */
+ crypto_pk_get_digest(pk, digest);
+ tt_assert(digestmap_get(list->status_by_digest, digest));
+
+ /* Check if we have a ed25519 key. */
+ tt_assert(digest256map_get(list->status_by_digest256,
+ get_master_identity_key()->pubkey));
+
+ RESET_FP_LIST(list);
+
+ done:
+ dirserv_free_fingerprint_list();
+ crypto_pk_free(pk);
+}
+
+#ifndef COCCI
#define DIR_LEGACY(name) \
{ #name, test_dir_ ## name , TT_FORK, NULL, NULL }
@@ -7219,6 +7438,7 @@ test_dir_format_versions_list(void *arg)
/* where arg is a string constant */
#define DIR_ARG(name,flags,arg) \
{ #name "_" arg, test_dir_##name, (flags), &passthrough_setup, (void*) arg }
+#endif /* !defined(COCCI) */
struct testcase_t dir_tests[] = {
DIR_LEGACY(nicknames),
@@ -7260,7 +7480,7 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(clip_unmeasured_bw_kb),
DIR_LEGACY(clip_unmeasured_bw_kb_alt),
DIR(fmt_control_ns, 0),
- DIR(dirserv_set_routerstatus_testing, 0),
+ DIR(dirserv_set_routerstatus_testing, TT_FORK),
DIR(http_handling, 0),
DIR(purpose_needs_anonymity_returns_true_for_bridges, 0),
DIR(purpose_needs_anonymity_returns_false_for_own_bridge_desc, 0),
@@ -7295,7 +7515,11 @@ struct testcase_t dir_tests[] = {
DIR(matching_flags, 0),
DIR(networkstatus_compute_bw_weights_v10, 0),
DIR(platform_str, 0),
- DIR(networkstatus_consensus_has_ipv6, TT_FORK),
DIR(format_versions_list, TT_FORK),
+ DIR(add_fingerprint, TT_FORK),
+ DIR(dirserv_load_fingerprint_file, TT_FORK),
+ DIR(dirserv_router_get_status, TT_FORK),
+ DIR(dirserv_would_reject_router, TT_FORK),
+ DIR(dirserv_add_own_fingerprint, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index 0b87e29873..f2b4e8724b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -13,7 +13,7 @@
#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/ns_parse.h"
#include "test/test_dir_common.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/networkstatus_st.h"
diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h
index 619dc83eb9..d37496465c 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 edfd0c74e1..f446bbb5eb 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define RENDCOMMON_PRIVATE
@@ -20,6 +20,7 @@
#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"
@@ -37,7 +38,7 @@
#include "feature/dircache/dirserv.h"
#include "feature/dirauth/dirvote.h"
#include "test/log_test_helpers.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/dirclient/dir_server_st.h"
@@ -54,17 +55,15 @@
#endif /* defined(_WIN32) */
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-DISABLE_GCC_WARNING(overlength-strings)
+DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
* at large. */
#endif
#include "vote_descriptors.inc"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-ENABLE_GCC_WARNING(overlength-strings)
+ENABLE_GCC_WARNING("-Woverlength-strings")
#endif
-#define NS_MODULE dir_handle_get
-
#define NOT_FOUND "HTTP/1.0 404 Not found\r\n\r\n"
#define BAD_REQUEST "HTTP/1.0 400 Bad request\r\n\r\n"
#define SERVER_BUSY "HTTP/1.0 503 Directory busy, try again later\r\n\r\n"
@@ -118,7 +117,7 @@ test_dir_handle_get_v1_command_not_found(void *data)
conn = new_dir_conn();
// no frontpage configured
- tt_ptr_op(get_dirportfrontpage(), OP_EQ, NULL);
+ tt_ptr_op(relay_get_dirportfrontpage(), OP_EQ, NULL);
/* V1 path */
tt_int_op(directory_handle_command_get(conn, GET("/tor/"), NULL, 0),
@@ -152,9 +151,9 @@ test_dir_handle_get_v1_command(void *data)
(void) data;
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
- MOCK(get_dirportfrontpage, mock_get_dirportfrontpage);
+ MOCK(relay_get_dirportfrontpage, mock_get_dirportfrontpage);
- exp_body = get_dirportfrontpage();
+ exp_body = relay_get_dirportfrontpage();
body_len = strlen(exp_body);
conn = new_dir_conn();
@@ -177,7 +176,7 @@ test_dir_handle_get_v1_command(void *data)
done:
UNMOCK(connection_write_to_buf_impl_);
- UNMOCK(get_dirportfrontpage);
+ UNMOCK(relay_get_dirportfrontpage);
connection_free_minimal(TO_CONN(conn));
tor_free(header);
tor_free(body);
@@ -257,7 +256,7 @@ test_dir_handle_get_rendezvous2_not_found_if_not_encrypted(void *data)
conn = new_dir_conn();
// connection is not encrypted
- tt_assert(!connection_dir_is_encrypted(conn))
+ tt_assert(!connection_dir_is_encrypted(conn));
tt_int_op(directory_handle_command_get(conn, RENDEZVOUS2_GET(), NULL, 0),
OP_EQ, 0);
@@ -363,12 +362,13 @@ test_dir_handle_get_rendezvous2_not_found(void *data)
rend_cache_free_all();
}
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static const routerinfo_t * dhg_tests_router_get_my_routerinfo(void);
+ATTR_UNUSED static int dhg_tests_router_get_my_routerinfo_called = 0;
static routerinfo_t *mock_routerinfo;
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+dhg_tests_router_get_my_routerinfo(void)
{
if (!mock_routerinfo) {
mock_routerinfo = tor_malloc_zero(sizeof(routerinfo_t));
@@ -393,7 +393,8 @@ test_dir_handle_get_rendezvous2_on_encrypted_conn_success(void *data)
(void) data;
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ dhg_tests_router_get_my_routerinfo);
rend_cache_init();
@@ -436,7 +437,7 @@ test_dir_handle_get_rendezvous2_on_encrypted_conn_success(void *data)
done:
UNMOCK(connection_write_to_buf_impl_);
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
connection_free_minimal(TO_CONN(conn));
tor_free(header);
@@ -768,7 +769,8 @@ test_dir_handle_get_server_descriptors_all(void* data)
helper_setup_fake_routerlist();
//TODO: change to router_get_my_extrainfo when testing "extra" path
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ dhg_tests_router_get_my_routerinfo);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
// We are one of the routers
@@ -810,7 +812,7 @@ test_dir_handle_get_server_descriptors_all(void* data)
tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
UNMOCK(connection_write_to_buf_impl_);
connection_free_minimal(TO_CONN(conn));
tor_free(header);
@@ -867,7 +869,8 @@ test_dir_handle_get_server_descriptors_authority(void* data)
crypto_pk_t *identity_pkey = pk_generate(0);
(void) data;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ dhg_tests_router_get_my_routerinfo);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
/* init mock */
@@ -912,7 +915,7 @@ test_dir_handle_get_server_descriptors_authority(void* data)
tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
UNMOCK(connection_write_to_buf_impl_);
tor_free(mock_routerinfo->cache_info.signed_descriptor_body);
tor_free(mock_routerinfo);
@@ -932,7 +935,8 @@ test_dir_handle_get_server_descriptors_fp(void* data)
crypto_pk_t *identity_pkey = pk_generate(0);
(void) data;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ dhg_tests_router_get_my_routerinfo);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
/* init mock */
@@ -984,7 +988,7 @@ test_dir_handle_get_server_descriptors_fp(void* data)
tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
UNMOCK(connection_write_to_buf_impl_);
tor_free(mock_routerinfo->cache_info.signed_descriptor_body);
tor_free(mock_routerinfo);
@@ -1788,13 +1792,14 @@ test_dir_handle_get_status_vote_current_consensus_too_old(void *data)
or_options_free(mock_options); mock_options = NULL;
}
-NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+static int dhg_tests_geoip_get_country_by_addr(const tor_addr_t *addr);
+ATTR_UNUSED static int dhg_tests_geoip_get_country_by_addr_called = 0;
int
-NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+dhg_tests_geoip_get_country_by_addr(const tor_addr_t *addr)
{
(void)addr;
- CALLED(geoip_get_country_by_addr)++;
+ dhg_tests_geoip_get_country_by_addr_called++;
return 1;
}
@@ -1858,7 +1863,8 @@ test_dir_handle_get_status_vote_current_consensus_ns(void* data)
dirserv_free_all();
clear_geoip_db();
- NS_MOCK(geoip_get_country_by_addr);
+ MOCK(geoip_get_country_by_addr,
+ dhg_tests_geoip_get_country_by_addr);
MOCK(get_options, mock_get_options);
init_mock_options();
@@ -1895,7 +1901,7 @@ test_dir_handle_get_status_vote_current_consensus_ns(void* data)
tt_str_op("ab=8", OP_EQ, hist);
done:
- NS_UNMOCK(geoip_get_country_by_addr);
+ UNMOCK(geoip_get_country_by_addr);
UNMOCK(get_options);
tor_free(header);
tor_free(comp_body);
@@ -2074,12 +2080,12 @@ test_dir_handle_get_status_vote_d(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455 -1;
- voting_schedule_recalculate_timing(mock_options, now);
+ dirauth_sched_recalculate_timing(mock_options, now);
const char *msg_out = NULL;
int status_out = 0;
- struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(pv);
status_vote_current_d_test(&header, &body, &body_used);
@@ -2247,11 +2253,11 @@ test_dir_handle_get_status_vote_next_bandwidth_not_found(void* data)
tor_free(header);
}
-NS_DECL(const char*,
-dirvote_get_pending_consensus, (consensus_flavor_t flav));
+static const char* dhg_tests_dirvote_get_pending_consensus(
+ consensus_flavor_t flav);
const char*
-NS(dirvote_get_pending_consensus)(consensus_flavor_t flav)
+dhg_tests_dirvote_get_pending_consensus(consensus_flavor_t flav)
{
(void)flav;
return "pending consensus";
@@ -2264,7 +2270,8 @@ test_dir_handle_get_status_vote_next_consensus(void* data)
size_t body_used = 0;
(void) data;
- NS_MOCK(dirvote_get_pending_consensus);
+ MOCK(dirvote_get_pending_consensus,
+ dhg_tests_dirvote_get_pending_consensus);
status_vote_next_consensus_test(&header, &body, &body_used);
tt_assert(header);
@@ -2277,7 +2284,7 @@ test_dir_handle_get_status_vote_next_consensus(void* data)
tt_str_op("pending consensus", OP_EQ, body);
done:
- NS_UNMOCK(dirvote_get_pending_consensus);
+ UNMOCK(dirvote_get_pending_consensus);
tor_free(header);
tor_free(body);
}
@@ -2290,7 +2297,8 @@ test_dir_handle_get_status_vote_next_consensus_busy(void* data)
(void) data;
MOCK(get_options, mock_get_options);
- NS_MOCK(dirvote_get_pending_consensus);
+ MOCK(dirvote_get_pending_consensus,
+ dhg_tests_dirvote_get_pending_consensus);
//Make it busy
init_mock_options();
@@ -2302,7 +2310,7 @@ test_dir_handle_get_status_vote_next_consensus_busy(void* data)
tt_str_op(SERVER_BUSY, OP_EQ, header);
done:
- NS_UNMOCK(dirvote_get_pending_consensus);
+ UNMOCK(dirvote_get_pending_consensus);
UNMOCK(get_options);
tor_free(header);
tor_free(body);
@@ -2346,11 +2354,10 @@ test_dir_handle_get_status_vote_next_consensus_signatures_not_found(void* data)
tor_free(body);
}
-NS_DECL(const char*,
-dirvote_get_pending_detached_signatures, (void));
+static const char* dhg_tests_dirvote_get_pending_detached_signatures(void);
const char*
-NS(dirvote_get_pending_detached_signatures)(void)
+dhg_tests_dirvote_get_pending_detached_signatures(void)
{
return "pending detached sigs";
}
@@ -2362,7 +2369,8 @@ test_dir_handle_get_status_vote_next_consensus_signatures(void* data)
size_t body_used = 0;
(void) data;
- NS_MOCK(dirvote_get_pending_detached_signatures);
+ MOCK(dirvote_get_pending_detached_signatures,
+ dhg_tests_dirvote_get_pending_detached_signatures);
status_vote_next_consensus_signatures_test(&header, &body, &body_used);
tt_assert(header);
@@ -2375,7 +2383,7 @@ test_dir_handle_get_status_vote_next_consensus_signatures(void* data)
tt_str_op("pending detached sigs", OP_EQ, body);
done:
- NS_UNMOCK(dirvote_get_pending_detached_signatures);
+ UNMOCK(dirvote_get_pending_detached_signatures);
tor_free(header);
tor_free(body);
}
@@ -2387,7 +2395,8 @@ test_dir_handle_get_status_vote_next_consensus_signatures_busy(void* data)
size_t body_used;
(void) data;
- NS_MOCK(dirvote_get_pending_detached_signatures);
+ MOCK(dirvote_get_pending_detached_signatures,
+ dhg_tests_dirvote_get_pending_detached_signatures);
MOCK(get_options, mock_get_options);
//Make it busy
@@ -2401,7 +2410,7 @@ test_dir_handle_get_status_vote_next_consensus_signatures_busy(void* data)
done:
UNMOCK(get_options);
- NS_UNMOCK(dirvote_get_pending_detached_signatures);
+ UNMOCK(dirvote_get_pending_detached_signatures);
tor_free(header);
tor_free(body);
or_options_free(mock_options); mock_options = NULL;
@@ -2448,10 +2457,10 @@ test_dir_handle_get_status_vote_next_authority(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455 -1;
- voting_schedule_recalculate_timing(mock_options, now);
+ dirauth_sched_recalculate_timing(mock_options, now);
- struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(vote);
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
@@ -2608,10 +2617,10 @@ test_dir_handle_get_status_vote_current_authority(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455;
- voting_schedule_recalculate_timing(mock_options, now-1);
+ dirauth_sched_recalculate_timing(mock_options, now-1);
- struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(vote);
// move the pending vote to previous vote
@@ -2649,6 +2658,183 @@ test_dir_handle_get_status_vote_current_authority(void* data)
dirvote_free_all();
}
+/* Test that a late vote is rejected, but an on-time vote is accepted. */
+static void
+test_dir_handle_get_status_vote_too_late(void* data)
+{
+ dir_connection_t *conn = NULL;
+ char *header = NULL, *body = NULL;
+ const char *msg_out = NULL;
+ int status_out = 0;
+ size_t body_used = 0;
+ const char digest[DIGEST_LEN] = "";
+
+ dir_server_t *ds = NULL;
+ const char* mode = (const char *)data;
+
+ clear_dir_servers();
+ routerlist_free_all();
+ dirvote_free_all();
+
+ mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE,
+ strlen(TEST_CERTIFICATE),
+ NULL);
+
+ /* create a trusted ds */
+ ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+ NULL, V3_DIRINFO, 1.0);
+ tt_assert(ds);
+ dir_server_add(ds);
+
+ /* ds v3_identity_digest is the certificate's identity_key */
+ base16_decode(ds->v3_identity_digest, DIGEST_LEN,
+ TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN);
+
+ tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE,
+ TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL));
+
+ init_mock_options();
+ mock_options->AuthoritativeDir = 1;
+ mock_options->V3AuthoritativeDir = 1;
+
+ int base_delay = 0;
+ int vote_interval = 0;
+ int start_offset = 0;
+
+ tt_assert(mode);
+ /* Set the required timings, see below for details */
+ if (strcmp(mode, "min") == 0) {
+ /* The minimum valid test network timing */
+ base_delay = 2;
+ vote_interval = 10;
+ start_offset = vote_interval - 5;
+ } else if (strcmp(mode, "chutney") == 0) {
+ /* The test network timing used by chutney */
+ base_delay = 4;
+ vote_interval = 20;
+ start_offset = vote_interval - 5;
+ } else if (strcmp(mode, "half-public") == 0) {
+ /* The short consensus failure timing used in the public network */
+ base_delay = 5*60;
+ vote_interval = 30*60;
+ start_offset = vote_interval - 9*60 - 5;
+ } else if (strcmp(mode, "public") == 0) {
+ /* The standard timing used in the public network */
+ base_delay = 5*60;
+ vote_interval = 60*60;
+ start_offset = vote_interval - 9*60 - 5;
+ }
+
+ tt_assert(base_delay > 0);
+ tt_assert(vote_interval > 0);
+ tt_assert(start_offset > 0);
+
+ /* Skew the time to fit the fixed time in the vote */
+ mock_options->TestingV3AuthVotingStartOffset = start_offset;
+ /* Calculate the rest of the timings */
+ mock_options->TestingV3AuthInitialVotingInterval = vote_interval;
+ mock_options->TestingV3AuthInitialVoteDelay = base_delay;
+ mock_options->TestingV3AuthInitialDistDelay = base_delay;
+
+ time_t now = 1441223455;
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+ const time_t voting_starts = voting_schedule.voting_starts;
+ const time_t fetch_missing = voting_schedule.fetch_missing_votes;
+
+ struct pending_vote_t *vote = NULL;
+
+ /* Next voting interval */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing + vote_interval,
+ &msg_out, &status_out);
+ tt_assert(!vote);
+ tt_int_op(status_out, OP_EQ, 400);
+ tt_str_op(msg_out, OP_EQ,
+ "Posted vote received too late, would be dangerous to count it");
+
+ /* Just after fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing + 1,
+ &msg_out, &status_out);
+ tt_assert(!vote);
+ tt_int_op(status_out, OP_EQ, 400);
+ tt_str_op(msg_out, OP_EQ,
+ "Posted vote received too late, would be dangerous to count it");
+
+ /* On fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* Between voting starts and fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts + 1,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* On voting starts */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* Just before voting starts */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts - 1,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+
+ MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ conn = new_dir_conn();
+ tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
+ GET("/tor/status-vote/current/authority"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ &body, &body_used, strlen(VOTE_BODY_V3)+1, 0);
+
+ tt_assert(header);
+ tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header);
+ tt_assert(strstr(header, "Content-Type: text/plain\r\n"));
+ tt_assert(strstr(header, "Content-Encoding: identity\r\n"));
+ tt_assert(strstr(header, "Content-Length: 4135\r\n"));
+
+ tt_str_op(VOTE_BODY_V3, OP_EQ, body);
+
+ done:
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(get_my_v3_authority_cert);
+ connection_free_minimal(TO_CONN(conn));
+ tor_free(header);
+ tor_free(body);
+ authority_cert_free(mock_cert); mock_cert = NULL;
+ or_options_free(mock_options); mock_options = NULL;
+
+ clear_dir_servers();
+ routerlist_free_all();
+ dirvote_free_all();
+}
+
static void
test_dir_handle_get_parse_accept_encoding(void *arg)
{
@@ -2699,6 +2885,16 @@ test_dir_handle_get_parse_accept_encoding(void *arg)
#define DIR_HANDLE_CMD(name,flags) \
{ #name, test_dir_handle_get_##name, (flags), NULL, NULL }
+#ifdef COCCI
+/* Coccinelle doesn't like the stringification in this macro */
+#define DIR_HANDLE_CMD_ARG(name,flags,arg) \
+ DIR_HANDLE_CMD(name,flags)
+#else
+#define DIR_HANDLE_CMD_ARG(name,flags,arg) \
+ { #name "/" arg, test_dir_handle_get_##name, (flags), \
+ &passthrough_setup, (void *)(arg) }
+#endif /* defined(COCCI) */
+
struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(not_found, 0),
DIR_HANDLE_CMD(bad_request, 0),
@@ -2738,6 +2934,10 @@ struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(status_vote_next_not_found, 0),
DIR_HANDLE_CMD(status_vote_current_authority_not_found, 0),
DIR_HANDLE_CMD(status_vote_current_authority, 0),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "min"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "chutney"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "half-public"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "public"),
DIR_HANDLE_CMD(status_vote_next_authority_not_found, 0),
DIR_HANDLE_CMD(status_vote_next_authority, 0),
DIR_HANDLE_CMD(status_vote_next_bandwidth_not_found, 0),
diff --git a/src/test/test_dispatch.c b/src/test/test_dispatch.c
index a62c18e0c9..77f33e4b15 100644
--- a/src/test/test_dispatch.c
+++ b/src/test/test_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DISPATCH_NEW_PRIVATE
@@ -167,7 +167,7 @@ test_dispatch_no_recipient(void *arg)
dcfg_free(cfg);
}
-struct coord { int x; int y; };
+struct coord_t { int x; int y; };
static void
free_coord(msg_aux_data_t d)
{
@@ -177,7 +177,7 @@ static char *
fmt_coord(msg_aux_data_t d)
{
char *v;
- struct coord *c = d.ptr;
+ struct coord_t *c = d.ptr;
tor_asprintf(&v, "[%d, %d]", c->x, c->y);
return v;
}
@@ -225,7 +225,7 @@ test_dispatch_with_types(void *arg)
r = dispatch_set_alert_fn(d, 2, alert_run_immediate, NULL);
tt_int_op(r, OP_EQ, 0);
- struct coord *xy = tor_malloc(sizeof(*xy));
+ struct coord_t *xy = tor_malloc(sizeof(*xy));
xy->x = 13;
xy->y = 37;
msg_aux_data_t data = {.ptr = xy};
diff --git a/src/test/test_dns.c b/src/test/test_dns.c
index 51ff8729d0..299321ab64 100644
--- a/src/test/test_dns.c
+++ b/src/test/test_dns.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -20,10 +20,7 @@
#include <event2/event.h>
#include <event2/dns.h>
-#define NS_MODULE dns
-
#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
-#define NS_SUBMODULE configure_nameservers_fallback
static or_options_t options = {
.ORPort_set = 1,
@@ -36,7 +33,7 @@ mock_get_options(void)
}
static void
-NS(test_main)(void *arg)
+test_dns_configure_ns_fallback(void *arg)
{
(void)arg;
tor_addr_t *nameserver_addr = NULL;
@@ -76,30 +73,23 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
#endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */
-#define NS_SUBMODULE clip_ttl
-
static void
-NS(test_main)(void *arg)
+test_dns_clip_ttl(void *arg)
{
(void)arg;
- uint32_t ttl_mid = MIN_DNS_TTL_AT_EXIT / 2 + MAX_DNS_TTL_AT_EXIT / 2;
+ uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2;
- tt_int_op(dns_clip_ttl(MIN_DNS_TTL_AT_EXIT - 1),OP_EQ,MIN_DNS_TTL_AT_EXIT);
- tt_int_op(dns_clip_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL_AT_EXIT);
- tt_int_op(dns_clip_ttl(MAX_DNS_TTL_AT_EXIT + 1),OP_EQ,MAX_DNS_TTL_AT_EXIT);
+ tt_int_op(clip_dns_ttl(MIN_DNS_TTL - 1),OP_EQ,MIN_DNS_TTL);
+ tt_int_op(clip_dns_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL);
+ tt_int_op(clip_dns_ttl(MAX_DNS_TTL + 1),OP_EQ,MAX_DNS_TTL);
done:
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE resolve
-
static int resolve_retval = 0;
static int resolve_made_conn_pending = 0;
static char *resolved_name = NULL;
@@ -107,10 +97,11 @@ static cached_resolve_t *cache_entry_mock = NULL;
static int n_fake_impl = 0;
-NS_DECL(int, dns_resolve_impl, (edge_connection_t *exitconn, int is_resolve,
- or_circuit_t *oncirc, char **hostname_out,
- int *made_connection_pending_out,
- cached_resolve_t **resolve_out));
+static int dns_resolve_dns_resolve_impl(edge_connection_t *exitconn,
+ int is_resolve, or_circuit_t *oncirc,
+ char **hostname_out, int *made_connection_pending_out,
+ cached_resolve_t **resolve_out);
+ATTR_UNUSED static int dns_resolve_dns_resolve_impl_called = 0;
/** This will be our configurable substitute for <b>dns_resolve_impl</b> in
* dns.c. It will return <b>resolve_retval</b>,
@@ -121,7 +112,7 @@ NS_DECL(int, dns_resolve_impl, (edge_connection_t *exitconn, int is_resolve,
* 1.
*/
static int
-NS(dns_resolve_impl)(edge_connection_t *exitconn, int is_resolve,
+dns_resolve_dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
or_circuit_t *oncirc, char **hostname_out,
int *made_connection_pending_out,
cached_resolve_t **resolve_out)
@@ -151,7 +142,7 @@ static uint8_t last_answer_type = 0;
static cached_resolve_t *last_resolved;
static void
-NS(send_resolved_cell)(edge_connection_t *conn, uint8_t answer_type,
+dns_resolve_send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
const cached_resolve_t *resolved)
{
conn_for_resolved_cell = conn;
@@ -167,7 +158,7 @@ static int n_send_resolved_hostname_cell_replacement = 0;
static char *last_resolved_hostname = NULL;
static void
-NS(send_resolved_hostname_cell)(edge_connection_t *conn,
+dns_resolve_send_resolved_hostname_cell(edge_connection_t *conn,
const char *hostname)
{
conn_for_resolved_cell = conn;
@@ -181,7 +172,7 @@ NS(send_resolved_hostname_cell)(edge_connection_t *conn,
static int n_dns_cancel_pending_resolve_replacement = 0;
static void
-NS(dns_cancel_pending_resolve)(const char *address)
+dns_resolve_dns_cancel_pending_resolve(const char *address)
{
(void) address;
n_dns_cancel_pending_resolve_replacement++;
@@ -191,7 +182,7 @@ static int n_connection_free = 0;
static connection_t *last_freed_conn = NULL;
static void
-NS(connection_free_)(connection_t *conn)
+dns_resolve_connection_free_(connection_t *conn)
{
n_connection_free++;
@@ -199,7 +190,7 @@ NS(connection_free_)(connection_t *conn)
}
static void
-NS(test_main)(void *arg)
+test_dns_resolve(void *arg)
{
(void) arg;
int retval;
@@ -218,9 +209,12 @@ NS(test_main)(void *arg)
memset(exitconn,0,sizeof(edge_connection_t));
memset(nextconn,0,sizeof(edge_connection_t));
- NS_MOCK(dns_resolve_impl);
- NS_MOCK(send_resolved_cell);
- NS_MOCK(send_resolved_hostname_cell);
+ MOCK(dns_resolve_impl,
+ dns_resolve_dns_resolve_impl);
+ MOCK(send_resolved_cell,
+ dns_resolve_send_resolved_cell);
+ MOCK(send_resolved_hostname_cell,
+ dns_resolve_send_resolved_hostname_cell);
/*
* CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
@@ -333,8 +327,10 @@ NS(test_main)(void *arg)
* on exitconn with type being RESOLVED_TYPE_ERROR.
*/
- NS_MOCK(dns_cancel_pending_resolve);
- NS_MOCK(connection_free_);
+ MOCK(dns_cancel_pending_resolve,
+ dns_resolve_dns_cancel_pending_resolve);
+ MOCK(connection_free_,
+ dns_resolve_connection_free_);
exitconn->on_circuit = &(on_circuit->base_);
exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
@@ -357,11 +353,11 @@ NS(test_main)(void *arg)
tt_assert(last_freed_conn == TO_CONN(exitconn));
done:
- NS_UNMOCK(dns_resolve_impl);
- NS_UNMOCK(send_resolved_cell);
- NS_UNMOCK(send_resolved_hostname_cell);
- NS_UNMOCK(dns_cancel_pending_resolve);
- NS_UNMOCK(connection_free_);
+ UNMOCK(dns_resolve_impl);
+ UNMOCK(send_resolved_cell);
+ UNMOCK(send_resolved_hostname_cell);
+ UNMOCK(dns_cancel_pending_resolve);
+ UNMOCK(connection_free_);
tor_free(on_circuit);
tor_free(exitconn);
tor_free(nextconn);
@@ -371,8 +367,6 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
/** Create an <b>edge_connection_t</b> instance that is considered a
* valid exit connection by asserts in dns_resolve_impl.
*/
@@ -389,8 +383,6 @@ create_valid_exitconn(void)
return exitconn;
}
-#define NS_SUBMODULE ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve)
-
/*
* Given that <b>exitconn->base_.address</b> is IP address string, we
* want dns_resolve_impl() to parse it and store in
@@ -399,7 +391,7 @@ create_valid_exitconn(void)
*/
static void
-NS(test_main)(void *arg)
+test_dns_impl_addr_is_ip(void *arg)
{
int retval;
int made_pending;
@@ -432,21 +424,17 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, non_exit)
-
/** Given that Tor instance is not configured as an exit node, we want
* dns_resolve_impl() to fail with return value -1.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_non_exit_router_my_exit_policy_is_reject_star(void)
{
return 1;
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_non_exit(void *arg)
{
int retval;
int made_pending;
@@ -458,7 +446,8 @@ NS(test_main)(void *arg)
TO_CONN(exitconn)->address = tor_strdup("torproject.org");
- NS_MOCK(router_my_exit_policy_is_reject_star);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_non_exit_router_my_exit_policy_is_reject_star);
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
@@ -469,27 +458,23 @@ NS(test_main)(void *arg)
tor_free(TO_CONN(exitconn)->address);
tor_free(exitconn);
tor_free(on_circ);
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(router_my_exit_policy_is_reject_star);
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, addr_is_invalid_dest)
-
/** Given that address is not a valid destination (as judged by
* address_is_invalid_destination() function), we want dns_resolve_impl()
* function to fail with return value -1.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_addr_is_invalid_dest(void *arg)
{
int retval;
int made_pending;
@@ -499,7 +484,8 @@ NS(test_main)(void *arg)
(void)arg;
- NS_MOCK(router_my_exit_policy_is_reject_star);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star);
TO_CONN(exitconn)->address = tor_strdup("invalid#@!.org");
@@ -509,29 +495,25 @@ NS(test_main)(void *arg)
tt_int_op(retval,OP_EQ,-1);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(router_my_exit_policy_is_reject_star);
tor_free(TO_CONN(exitconn)->address);
tor_free(exitconn);
tor_free(on_circ);
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, malformed_ptr)
-
/** Given that address is a malformed PTR name, we want dns_resolve_impl to
* fail.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_malformed_ptr(void *arg)
{
int retval;
int made_pending;
@@ -543,7 +525,8 @@ NS(test_main)(void *arg)
TO_CONN(exitconn)->address = tor_strdup("1.0.0.127.in-addr.arpa");
- NS_MOCK(router_my_exit_policy_is_reject_star);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star);
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
@@ -561,30 +544,26 @@ NS(test_main)(void *arg)
tt_int_op(retval,OP_EQ,-1);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(router_my_exit_policy_is_reject_star);
tor_free(TO_CONN(exitconn)->address);
tor_free(exitconn);
tor_free(on_circ);
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_pending)
-
/* Given that there is already a pending resolve for the given address,
* we want dns_resolve_impl to append our exit connection to list
* of pending connections for the pending DNS request and return 0.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_cache_hit_pending(void *arg)
{
int retval;
int made_pending = 0;
@@ -607,7 +586,8 @@ NS(test_main)(void *arg)
strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
sizeof(cache_entry->address));
- NS_MOCK(router_my_exit_policy_is_reject_star);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star);
dns_init();
@@ -625,7 +605,7 @@ NS(test_main)(void *arg)
tt_assert(pending_conn->conn == exitconn);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(router_my_exit_policy_is_reject_star);
tor_free(on_circ);
tor_free(TO_CONN(exitconn)->address);
tor_free(cache_entry->pending_connections);
@@ -634,16 +614,12 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_cached)
-
/* Given that a finished DNS resolve is available in our cache, we want
* dns_resolve_impl() return it to called via resolve_out and pass the
* handling to set_exitconn_info_from_resolve function.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
@@ -652,7 +628,8 @@ static edge_connection_t *last_exitconn = NULL;
static cached_resolve_t *last_resolve = NULL;
static int
-NS(set_exitconn_info_from_resolve)(edge_connection_t *exitconn,
+dns_impl_cache_hit_cached_set_exitconn_info_from_resolve(
+ edge_connection_t *exitconn,
const cached_resolve_t *resolve,
char **hostname_out)
{
@@ -665,7 +642,7 @@ NS(set_exitconn_info_from_resolve)(edge_connection_t *exitconn,
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_cache_hit_cached(void *arg)
{
int retval;
int made_pending = 0;
@@ -688,8 +665,10 @@ NS(test_main)(void *arg)
strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
sizeof(cache_entry->address));
- NS_MOCK(router_my_exit_policy_is_reject_star);
- NS_MOCK(set_exitconn_info_from_resolve);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star);
+ MOCK(set_exitconn_info_from_resolve,
+ dns_impl_cache_hit_cached_set_exitconn_info_from_resolve);
dns_init();
@@ -706,8 +685,8 @@ NS(test_main)(void *arg)
tt_assert(last_resolve == cache_entry);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
- NS_UNMOCK(set_exitconn_info_from_resolve);
+ UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(set_exitconn_info_from_resolve);
tor_free(on_circ);
tor_free(TO_CONN(exitconn)->address);
tor_free(cache_entry->pending_connections);
@@ -715,10 +694,6 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, cache_miss)
-
/* Given that there are neither pending nor pre-cached resolve for a given
* address, we want dns_resolve_impl() to create a new cached_resolve_t
* object, mark it as pending, insert it into the cache, attach the exit
@@ -726,7 +701,7 @@ NS(test_main)(void *arg)
* with the cached_resolve_t object it created.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_cache_miss_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
@@ -734,7 +709,7 @@ NS(router_my_exit_policy_is_reject_star)(void)
static cached_resolve_t *last_launched_resolve = NULL;
static int
-NS(launch_resolve)(cached_resolve_t *resolve)
+dns_impl_cache_miss_launch_resolve(cached_resolve_t *resolve)
{
last_launched_resolve = resolve;
@@ -742,7 +717,7 @@ NS(launch_resolve)(cached_resolve_t *resolve)
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_cache_miss(void *arg)
{
int retval;
int made_pending = 0;
@@ -761,8 +736,10 @@ NS(test_main)(void *arg)
strlcpy(query.address, TO_CONN(exitconn)->address, sizeof(query.address));
- NS_MOCK(router_my_exit_policy_is_reject_star);
- NS_MOCK(launch_resolve);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_cache_miss_router_my_exit_policy_is_reject_star);
+ MOCK(launch_resolve,
+ dns_impl_cache_miss_launch_resolve);
dns_init();
@@ -785,8 +762,8 @@ NS(test_main)(void *arg)
tt_str_op(cache_entry->address,OP_EQ,TO_CONN(exitconn)->address);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
- NS_UNMOCK(launch_resolve);
+ UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(launch_resolve);
tor_free(on_circ);
tor_free(TO_CONN(exitconn)->address);
if (cache_entry)
@@ -796,22 +773,22 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
struct testcase_t dns_tests[] = {
#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
- TEST_CASE(configure_nameservers_fallback),
+ { "configure_ns_fallback", test_dns_configure_ns_fallback,
+ TT_FORK, NULL, NULL },
#endif
- TEST_CASE(clip_ttl),
- TEST_CASE(resolve),
- TEST_CASE_ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve),
- TEST_CASE_ASPECT(resolve_impl, non_exit),
- TEST_CASE_ASPECT(resolve_impl, addr_is_invalid_dest),
- TEST_CASE_ASPECT(resolve_impl, malformed_ptr),
- TEST_CASE_ASPECT(resolve_impl, cache_hit_pending),
- TEST_CASE_ASPECT(resolve_impl, cache_hit_cached),
- TEST_CASE_ASPECT(resolve_impl, cache_miss),
+ { "clip_ttl", test_dns_clip_ttl, TT_FORK, NULL, NULL },
+ { "resolve", test_dns_resolve, TT_FORK, NULL, NULL },
+ { "impl_addr_is_ip", test_dns_impl_addr_is_ip, TT_FORK, NULL, NULL },
+ { "impl_non_exit", test_dns_impl_non_exit, TT_FORK, NULL, NULL },
+ { "impl_addr_is_invalid_dest", test_dns_impl_addr_is_invalid_dest,
+ TT_FORK, NULL, NULL },
+ { "impl_malformed_ptr", test_dns_impl_malformed_ptr, TT_FORK, NULL, NULL },
+ { "impl_cache_hit_pending", test_dns_impl_cache_hit_pending,
+ TT_FORK, NULL, NULL },
+ { "impl_cache_hit_cached", test_dns_impl_cache_hit_cached,
+ TT_FORK, NULL, NULL },
+ { "impl_cache_miss", test_dns_impl_cache_miss, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
-
-#undef NS_MODULE
diff --git a/src/test/test_dos.c b/src/test/test_dos.c
index c17cfedbf6..527e5bbe7f 100644
--- a/src/test/test_dos.c
+++ b/src/test/test_dos.c
@@ -1,8 +1,8 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DOS_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CIRCUITLIST_PRIVATE
#include "core/or/or.h"
diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c
index 8f2d507743..9cdd7f6d0e 100644
--- a/src/test/test_entryconn.c
+++ b/src/test/test_entryconn.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -11,7 +11,7 @@
#include "feature/client/addressmap.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "feature/nodelist/nodelist.h"
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index d59b1c7153..5ddd1a3db0 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -18,7 +18,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuitbuild.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "feature/dircommon/directory.h"
#include "feature/dirclient/dirclient.h"
@@ -390,12 +390,13 @@ test_entry_guard_encode_for_state_minimal(void *arg)
eg->confirmed_idx = -1;
char *s = NULL;
- s = entry_guard_encode_for_state(eg);
+ s = entry_guard_encode_for_state(eg, 0);
tt_str_op(s, OP_EQ,
"in=wubwub "
"rsa_id=706C75727079666C75727079736C75727079646F "
"sampled_on=2016-11-14T00:00:00 "
+ "sampled_idx=0 "
"listed=0");
done:
@@ -421,10 +422,11 @@ test_entry_guard_encode_for_state_maximal(void *arg)
eg->currently_listed = 1;
eg->confirmed_on_date = 1479081690;
eg->confirmed_idx = 333;
+ eg->sampled_idx = 42;
eg->extra_state_fields = tor_strdup("and the green grass grew all around");
char *s = NULL;
- s = entry_guard_encode_for_state(eg);
+ s = entry_guard_encode_for_state(eg, 0);
tt_str_op(s, OP_EQ,
"in=default "
@@ -432,6 +434,7 @@ test_entry_guard_encode_for_state_maximal(void *arg)
"bridge_addr=8.8.4.4:9999 "
"nickname=Fred "
"sampled_on=2016-11-14T00:00:00 "
+ "sampled_idx=0 "
"sampled_by=1.2.3 "
"unlisted_since=2016-11-14T00:00:45 "
"listed=1 "
@@ -621,39 +624,47 @@ test_entry_guard_parse_from_state_full(void *arg)
const char STATE[] =
"Guard in=default rsa_id=214F44BD5B638E8C817D47FF7C97397790BF0345 "
"nickname=TotallyNinja sampled_on=2016-11-12T19:32:49 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1\n"
"Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
"nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
+ "sampled_idx=1 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
"pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
"pb_successful_circuits_closed=2.000000\n"
"Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
"nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_idx=2 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=4 "
"pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
"pb_successful_circuits_closed=5.000000\n"
"Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
"nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1\n"
"Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E "
"nickname=maibrunn sampled_on=2016-11-25T22:36:38 "
+ "sampled_idx=3 "
"sampled_by=0.3.0.0-alpha-dev listed=1\n"
"Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E "
"nickname=Unnamed sampled_on=2016-11-25T14:34:00 "
+ "sampled_idx=10 "
"sampled_by=0.3.0.0-alpha-dev listed=1\n"
"Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E "
"bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev listed=1 "
"confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 "
"pb_circ_attempts=8.000000 pb_circ_successes=8.000000 "
"pb_successful_circuits_closed=13.000000\n"
"Guard in=bridges rsa_id=5800000000000000000000000000000000000000 "
"bridge_addr=37.218.246.143:28366 "
- "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n";
+ "sampled_on=2016-11-18T15:07:34 sampled_idx=1 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n";
config_line_t *lines = NULL;
or_state_t *state = tor_malloc_zero(sizeof(or_state_t));
@@ -729,35 +740,42 @@ test_entry_guard_parse_from_state_full(void *arg)
tt_str_op(joined, OP_EQ,
"Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
"nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
"pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
"pb_successful_circuits_closed=2.000000\n"
"Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
"nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_idx=1 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=1 "
"pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
"pb_successful_circuits_closed=5.000000\n"
"Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E "
"nickname=maibrunn sampled_on=2016-11-25T22:36:38 "
+ "sampled_idx=2 "
"sampled_by=0.3.0.0-alpha-dev listed=1\n"
"Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E "
"nickname=Unnamed sampled_on=2016-11-25T14:34:00 "
+ "sampled_idx=3 "
"sampled_by=0.3.0.0-alpha-dev listed=1\n"
"Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
"nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1\n"
"Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E "
"bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev listed=1 "
"confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 "
"pb_circ_attempts=8.000000 pb_circ_successes=8.000000 "
"pb_successful_circuits_closed=13.000000\n"
"Guard in=bridges rsa_id=5800000000000000000000000000000000000000 "
"bridge_addr=37.218.246.143:28366 "
- "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n");
+ "sampled_on=2016-11-18T15:07:34 sampled_idx=1 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n");
done:
config_free_lines(lines);
@@ -1461,8 +1479,8 @@ test_entry_guard_confirming_guards(void *arg)
tt_i64_op(g1->confirmed_on_date, OP_EQ, start+10);
tt_i64_op(g2->confirmed_on_date, OP_EQ, start);
tt_i64_op(g3->confirmed_on_date, OP_EQ, start+10);
- tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g2);
- tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g2);
tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3);
/* Now make sure we can regenerate the confirmed_entry_guards list. */
@@ -1474,8 +1492,8 @@ test_entry_guard_confirming_guards(void *arg)
tt_int_op(g1->confirmed_idx, OP_EQ, 1);
tt_int_op(g2->confirmed_idx, OP_EQ, 0);
tt_int_op(g3->confirmed_idx, OP_EQ, 2);
- tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g2);
- tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g2);
tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3);
/* Now make sure we can regenerate the confirmed_entry_guards list if
@@ -1492,9 +1510,9 @@ test_entry_guard_confirming_guards(void *arg)
g1 = smartlist_get(gs->confirmed_entry_guards, 0);
g2 = smartlist_get(gs->confirmed_entry_guards, 1);
g3 = smartlist_get(gs->confirmed_entry_guards, 2);
- tt_int_op(g1->confirmed_idx, OP_EQ, 0);
- tt_int_op(g2->confirmed_idx, OP_EQ, 1);
- tt_int_op(g3->confirmed_idx, OP_EQ, 2);
+ tt_int_op(g1->sampled_idx, OP_EQ, 0);
+ tt_int_op(g2->sampled_idx, OP_EQ, 1);
+ tt_int_op(g3->sampled_idx, OP_EQ, 8);
tt_assert(g1 != g2);
tt_assert(g1 != g3);
tt_assert(g2 != g3);
@@ -1510,9 +1528,6 @@ test_entry_guard_sample_reachable_filtered(void *arg)
(void)arg;
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
entry_guards_expand_sample(gs);
- const int N = 10000;
- bitarray_t *selected = NULL;
- int i, j;
/* We've got a sampled list now; let's make one non-usable-filtered; some
* confirmed, some primary, some pending.
@@ -1547,32 +1562,21 @@ test_entry_guard_sample_reachable_filtered(void *arg)
{ SAMPLE_EXCLUDE_PENDING, 0 },
{ -1, -1},
};
-
+ int j;
for (j = 0; tests[j].flag >= 0; ++j) {
- selected = bitarray_init_zero(n_guards);
const int excluded_flags = tests[j].flag;
const int excluded_idx = tests[j].idx;
- for (i = 0; i < N; ++i) {
- g = sample_reachable_filtered_entry_guards(gs, NULL, excluded_flags);
- tor_assert(g);
- int pos = smartlist_pos(gs->sampled_entry_guards, g);
- tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards);
- tt_int_op(pos, OP_GE, 0);
- tt_int_op(pos, OP_LT, n_guards);
- bitarray_set(selected, pos);
- }
- for (i = 0; i < n_guards; ++i) {
- const int should_be_set = (i != excluded_idx &&
- i != 3); // filtered out.
- tt_int_op(!!bitarray_is_set(selected, i), OP_EQ, should_be_set);
- }
- bitarray_free(selected);
- selected = NULL;
+ g = first_reachable_filtered_entry_guard(gs, NULL, excluded_flags);
+ tor_assert(g);
+ int pos = smartlist_pos(gs->sampled_entry_guards, g);
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards);
+ const int should_be_set = (pos != excluded_idx &&
+ pos != 3); // filtered out.
+ tt_int_op(1, OP_EQ, should_be_set);
}
done:
guard_selection_free(gs);
- bitarray_free(selected);
}
static void
@@ -1584,7 +1588,7 @@ test_entry_guard_sample_reachable_filtered_empty(void *arg)
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n,
n->is_possible_guard = 0);
- entry_guard_t *g = sample_reachable_filtered_entry_guards(gs, NULL, 0);
+ entry_guard_t *g = first_reachable_filtered_entry_guard(gs, NULL, 0);
tt_ptr_op(g, OP_EQ, NULL);
done:
@@ -1675,10 +1679,13 @@ test_entry_guard_manage_primary(void *arg)
tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx));
});
- /* If we have one confirmed guard, that guards becomes the first primary
- * guard, and the other primary guards get kept. */
+ /**
+ * If we have one confirmed guard, that guards becomes the first primary
+ * only if its sampled_idx is smaller
+ * */
- /* find a non-primary guard... */
+ /* find a non-primary guard... it should have a sampled_idx higher than
+ * existing primary guards */
entry_guard_t *confirmed = NULL;
SMARTLIST_FOREACH(gs->sampled_entry_guards, entry_guard_t *, g, {
if (! g->is_primary) {
@@ -1694,15 +1701,13 @@ test_entry_guard_manage_primary(void *arg)
smartlist_add_all(prev_guards, gs->primary_entry_guards);
entry_guards_update_primary(gs);
- /* and see what's primary now! */
+ /* the confirmed guard should be at the end of the primary list! Hopefully,
+ * one of the primary guards with a lower sampled_idx will confirm soon :)
+ * Doing this won't make the client switches between primaries depending on
+ * the order of confirming events */
tt_int_op(smartlist_len(gs->primary_entry_guards), OP_EQ, n_primary);
- tt_ptr_op(smartlist_get(gs->primary_entry_guards, 0), OP_EQ, confirmed);
- SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, g, {
- tt_assert(g->is_primary);
- if (g_sl_idx == 0)
- continue;
- tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx - 1));
- });
+ tt_ptr_op(smartlist_get(gs->primary_entry_guards,
+ smartlist_len(gs->primary_entry_guards)-1), OP_EQ, confirmed);
{
entry_guard_t *prev_last_guard = smartlist_get(prev_guards, n_primary-1);
tt_assert(! prev_last_guard->is_primary);
@@ -1793,6 +1798,57 @@ test_entry_guard_guard_preferred(void *arg)
}
static void
+test_entry_guard_correct_cascading_order(void *arg)
+{
+ (void)arg;
+ smartlist_t *old_primary_guards = smartlist_new();
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ entry_guards_expand_sample(gs);
+ /** First, a test in which the primary guards need be pulled from different
+ * lists to fill up the primary list -- this may happen, if for example, not
+ * enough guards have confirmed yet */
+ entry_guard_t *g;
+ /** just one confirmed */
+ g = smartlist_get(gs->sampled_entry_guards, 2);
+ make_guard_confirmed(gs, g);
+ entry_guards_update_primary(gs);
+ g = smartlist_get(gs->primary_entry_guards, 0);
+ tt_int_op(g->sampled_idx, OP_EQ, 0);
+ g = smartlist_get(gs->primary_entry_guards, 1);
+ tt_int_op(g->sampled_idx, OP_EQ, 1);
+ g = smartlist_get(gs->primary_entry_guards, 2);
+ tt_int_op(g->sampled_idx, OP_EQ, 2);
+
+ /** Now the primaries get all confirmed, and the primary list should not
+ * change */
+ make_guard_confirmed(gs, smartlist_get(gs->primary_entry_guards, 0));
+ make_guard_confirmed(gs, smartlist_get(gs->primary_entry_guards, 1));
+ smartlist_add_all(old_primary_guards, gs->primary_entry_guards);
+ entry_guards_update_primary(gs);
+ smartlist_ptrs_eq(gs->primary_entry_guards, old_primary_guards);
+ /** the confirmed guards should also have the same set of guards, in the same
+ * order :-) */
+ smartlist_ptrs_eq(gs->confirmed_entry_guards, gs->primary_entry_guards);
+ /** Now select a guard for a circuit, and make sure it is the first primary
+ * guard */
+ unsigned state = 9999;
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_ptr_op(g, OP_EQ, smartlist_get(gs->primary_entry_guards, 0));
+ /** Now, let's mark this guard as unreachable and let's update the lists */
+ g->is_reachable = GUARD_REACHABLE_NO;
+ g->failing_since = approx_time() - 10;
+ g->last_tried_to_connect = approx_time() - 10;
+ state = 9999;
+ entry_guards_update_primary(gs);
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ /** we should have switched to the next one is sampled order */
+ tt_int_op(g->sampled_idx, OP_EQ, 1);
+ done:
+ smartlist_free(old_primary_guards);
+ guard_selection_free(gs);
+}
+
+static void
test_entry_guard_select_for_circuit_no_confirmed(void *arg)
{
/* Simpler cases: no gaurds are confirmed yet. */
@@ -3039,6 +3095,7 @@ static const struct testcase_setup_t upgrade_circuits = {
upgrade_circuits_setup, upgrade_circuits_cleanup
};
+#ifndef COCCI
#define NO_PREFIX_TEST(name) \
{ #name, test_ ## name, 0, NULL, NULL }
@@ -3061,6 +3118,7 @@ static const struct testcase_setup_t upgrade_circuits = {
&upgrade_circuits, (void*)(arg REASONABLY_FUTURE) }, \
{ #name "_reasonably_past", test_entry_guard_ ## name, TT_FORK, \
&upgrade_circuits, (void*)(arg REASONABLY_PAST) }
+#endif /* !defined(COCCI) */
struct testcase_t entrynodes_tests[] = {
NO_PREFIX_TEST(node_preferred_orport),
@@ -3092,6 +3150,7 @@ struct testcase_t entrynodes_tests[] = {
BFN_TEST(sample_reachable_filtered_empty),
BFN_TEST(retry_unreachable),
BFN_TEST(manage_primary),
+ BFN_TEST(correct_cascading_order),
EN_TEST_FORK(guard_preferred),
diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c
index cb53a4e662..7935530653 100644
--- a/src/test/test_extorport.c
+++ b/src/test/test_extorport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c
index 16c566bdbc..bf9932c169 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 ac8bfbfded..00c200e0fd 100644
--- a/src/test/test_guardfraction.c
+++ b/src/test/test_guardfraction.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, 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 7f1d6e1898..dbb5b1a18e 100644
--- a/src/test/test_handles.c
+++ b/src/test/test_handles.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 8eb3c2c928..f31c28b24d 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,6 +9,7 @@
#define ROUTERLIST_PRIVATE
#define CONFIG_PRIVATE
#define CONNECTION_PRIVATE
+#define CONNECTION_OR_PRIVATE
#define MAINLOOP_PRIVATE
#include "orconfig.h"
@@ -16,9 +17,10 @@
#include "lib/buf/buffers.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "app/main/subsysmgr.h"
#include "core/mainloop/connection.h"
+#include "core/or/connection_or.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "core/mainloop/mainloop.h"
#include "feature/nodelist/nodelist.h"
@@ -33,6 +35,7 @@
#include "core/or/cell_st.h"
#include "core/or/connection_st.h"
+#include "core/or/or_connection_st.h"
#include "feature/nodelist/node_st.h"
#include "core/or/origin_circuit_st.h"
#include "feature/nodelist/routerlist_st.h"
@@ -42,14 +45,14 @@
#include "test/test_connection.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-DISABLE_GCC_WARNING(overlength-strings)
+DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
* at large. */
#endif
#include "test_descriptors.inc"
#include "core/or/circuitlist.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-ENABLE_GCC_WARNING(overlength-strings)
+ENABLE_GCC_WARNING("-Woverlength-strings")
#endif
/* Return a statically allocated string representing yesterday's date
@@ -194,6 +197,14 @@ fake_close_socket(tor_socket_t sock)
return 0;
}
+/* Helper for test_conn_get_proxy_or_connection() */
+void
+mock_connection_or_change_state(or_connection_t *conn, uint8_t state)
+{
+ tor_assert(conn);
+ conn->base_.state = state;
+}
+
static int mock_connection_connect_sockaddr_called = 0;
static int fake_socket_number = TEST_CONN_FD_INIT;
@@ -228,6 +239,77 @@ mock_connection_connect_sockaddr(connection_t *conn,
return 1;
}
+or_connection_t *
+test_conn_get_proxy_or_connection(unsigned int proxy_type)
+{
+ or_connection_t *conn = NULL;
+ tor_addr_t dst_addr;
+ tor_addr_t proxy_addr;
+ int socket_err = 0;
+ int in_progress = 0;
+
+ MOCK(connection_connect_sockaddr,
+ mock_connection_connect_sockaddr);
+ MOCK(connection_write_to_buf_impl_,
+ connection_write_to_buf_mock);
+ MOCK(connection_or_change_state,
+ mock_connection_or_change_state);
+ MOCK(tor_close_socket, fake_close_socket);
+
+ tor_init_connection_lists();
+
+ conn = or_connection_new(CONN_TYPE_OR, TEST_CONN_FAMILY);
+ tt_assert(conn);
+
+ /* Set up a destination address. */
+ test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY,
+ &dst_addr);
+ tt_assert(!tor_addr_is_null(&dst_addr));
+
+ conn->proxy_type = proxy_type;
+ conn->base_.proxy_state = PROXY_INFANT;
+
+ tor_addr_copy_tight(&conn->base_.addr, &dst_addr);
+ conn->base_.address = tor_addr_to_str_dup(&dst_addr);
+ conn->base_.port = TEST_CONN_PORT;
+
+ /* Set up a proxy address. */
+ test_conn_lookup_addr_helper(TEST_CONN_ADDRESS_2, TEST_CONN_FAMILY,
+ &proxy_addr);
+ tt_assert(!tor_addr_is_null(&proxy_addr));
+
+ conn->base_.state = OR_CONN_STATE_CONNECTING;
+
+ mock_connection_connect_sockaddr_called = 0;
+ in_progress = connection_connect(TO_CONN(conn), TEST_CONN_ADDRESS_PORT,
+ &proxy_addr, TEST_CONN_PORT, &socket_err);
+ tt_int_op(mock_connection_connect_sockaddr_called, OP_EQ, 1);
+ tt_assert(!socket_err);
+ tt_assert(in_progress == 0 || in_progress == 1);
+
+ assert_connection_ok(TO_CONN(conn), time(NULL));
+
+ in_progress = connection_or_finished_connecting(conn);
+ tt_int_op(in_progress, OP_EQ, 0);
+
+ assert_connection_ok(TO_CONN(conn), time(NULL));
+
+ UNMOCK(connection_connect_sockaddr);
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(connection_or_change_state);
+ UNMOCK(tor_close_socket);
+ return conn;
+
+ /* On failure */
+ done:
+ UNMOCK(connection_connect_sockaddr);
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(connection_or_change_state);
+ UNMOCK(tor_close_socket);
+ connection_free_(TO_CONN(conn));
+ return NULL;
+}
+
/** Create and return a new connection/stream */
connection_t *
test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose)
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index d82072bb34..eaf18e19e2 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_HELPERS_H
@@ -26,6 +26,9 @@ char *buf_get_contents(buf_t *buf, size_t *sz_out);
int mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
uint16_t family, tor_addr_t *out);
+void mock_connection_or_change_state(or_connection_t *conn, uint8_t state);
+
+or_connection_t *test_conn_get_proxy_or_connection(unsigned int proxy_type);
connection_t *test_conn_get_connection(uint8_t state,
uint8_t type, uint8_t purpose);
or_options_t *helper_parse_options(const char *conf);
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index 2b69aae547..46b4493a3d 100644
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
index 86ac7e7fb1..f25bba3584 100644
--- a/src/test/test_hs_cache.c
+++ b/src/test/test_hs_cache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,7 +10,7 @@
#define DIRCACHE_PRIVATE
#define DIRCLIENT_PRIVATE
#define HS_CACHE_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#include "trunnel/ed25519_cert.h"
#include "feature/hs/hs_cache.h"
@@ -20,9 +20,10 @@
#include "feature/nodelist/networkstatus.h"
#include "core/mainloop/connection.h"
#include "core/proto/proto_http.h"
-#include "lib/crypt_ops/crypto_format.h"
#include "core/or/circuitlist.h"
#include "core/or/channel.h"
+#include "lib/crypt_ops/crypto_format.h"
+#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/edge_connection_st.h"
#include "core/or/or_circuit_st.h"
@@ -369,7 +370,7 @@ test_hsdir_revision_counter_check(void *arg)
hs_descriptor_t *published_desc = NULL;
char *published_desc_str = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *received_desc_str = NULL;
hs_descriptor_t *received_desc = NULL;
@@ -406,12 +407,12 @@ test_hsdir_revision_counter_check(void *arg)
const ed25519_public_key_t *blinded_key;
blinded_key = &published_desc->plaintext_data.blinded_pubkey;
- hs_get_subcredential(&signing_kp.pubkey, blinded_key, subcredential);
+ hs_get_subcredential(&signing_kp.pubkey, blinded_key, &subcredential);
received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
retval = hs_desc_decode_descriptor(received_desc_str,
- subcredential, NULL, &received_desc);
- tt_int_op(retval, OP_EQ, 0);
+ &subcredential, NULL, &received_desc);
+ tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(received_desc);
/* Check that the revision counter is correct */
@@ -443,8 +444,8 @@ test_hsdir_revision_counter_check(void *arg)
received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
retval = hs_desc_decode_descriptor(received_desc_str,
- subcredential, NULL, &received_desc);
- tt_int_op(retval, OP_EQ, 0);
+ &subcredential, NULL, &received_desc);
+ tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(received_desc);
/* Check that the revision counter is the latest */
@@ -475,7 +476,7 @@ test_client_cache(void *arg)
ed25519_keypair_t signing_kp;
hs_descriptor_t *published_desc = NULL;
char *published_desc_str = NULL;
- uint8_t wanted_subcredential[DIGEST256_LEN];
+ hs_subcredential_t wanted_subcredential;
response_handler_args_t *args = NULL;
dir_connection_t *conn = NULL;
@@ -504,8 +505,10 @@ test_client_cache(void *arg)
retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
NULL, &published_desc_str);
tt_int_op(retval, OP_EQ, 0);
- memcpy(wanted_subcredential, published_desc->subcredential, DIGEST256_LEN);
- tt_assert(!fast_mem_is_zero((char*)wanted_subcredential, DIGEST256_LEN));
+ memcpy(&wanted_subcredential, &published_desc->subcredential,
+ sizeof(hs_subcredential_t));
+ tt_assert(!fast_mem_is_zero((char*)wanted_subcredential.subcred,
+ DIGEST256_LEN));
}
/* Test handle_response_fetch_hsdesc_v3() */
@@ -539,8 +542,9 @@ test_client_cache(void *arg)
const hs_descriptor_t *cached_desc = NULL;
cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
tt_assert(cached_desc);
- tt_mem_op(cached_desc->subcredential, OP_EQ, wanted_subcredential,
- DIGEST256_LEN);
+ tt_mem_op(cached_desc->subcredential.subcred,
+ OP_EQ, wanted_subcredential.subcred,
+ SUBCRED_LEN);
}
/* Progress time to next TP and check that desc was cleaned */
@@ -567,6 +571,136 @@ test_client_cache(void *arg)
}
}
+/** Test that we can store HS descriptors in the client HS cache. */
+static void
+test_client_cache_decrypt(void *arg)
+{
+ int ret;
+ char *desc_encoded = NULL;
+ uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
+ curve25519_keypair_t client_kp;
+ ed25519_keypair_t service_kp;
+ hs_descriptor_t *desc = NULL;
+ const hs_descriptor_t *search_desc;
+ const char *search_desc_encoded;
+
+ (void) arg;
+
+ /* Initialize HSDir cache subsystem */
+ hs_init();
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* Set consensus time */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ /* Generate a valid descriptor with normal values. */
+ {
+ ret = ed25519_keypair_generate(&service_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = curve25519_keypair_generate(&client_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
+
+ desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie,
+ &client_kp.pubkey,
+ &service_kp);
+ tt_assert(desc);
+ ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
+ &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Put it in the cache. Should not be decrypted since the client
+ * authorization creds were not added to the global map. */
+ ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
+
+ /* We should not be able to decrypt anything. */
+ ret = hs_cache_client_new_auth_parse(&service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, false);
+
+ /* Add client auth to global map. */
+ hs_helper_add_client_auth(&service_kp.pubkey, &client_kp.seckey);
+
+ /* We should not be able to decrypt anything. */
+ ret = hs_cache_client_new_auth_parse(&service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, true);
+
+ /* Lookup the cache to make sure it is usable and there. */
+ search_desc = hs_cache_lookup_as_client(&service_kp.pubkey);
+ tt_assert(search_desc);
+ search_desc_encoded = hs_cache_lookup_encoded_as_client(&service_kp.pubkey);
+ tt_mem_op(search_desc_encoded, OP_EQ, desc_encoded, strlen(desc_encoded));
+
+ done:
+ hs_descriptor_free(desc);
+ tor_free(desc_encoded);
+
+ hs_free_all();
+
+ UNMOCK(networkstatus_get_live_consensus);
+}
+
+static void
+test_client_cache_remove(void *arg)
+{
+ int ret;
+ ed25519_keypair_t service_kp;
+ hs_descriptor_t *desc1 = NULL;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* Set consensus time. Lookup will not return the entry if it has expired
+ * and it is checked against the consensus valid_after time. */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+
+ /* Build a descriptor and cache it. */
+ {
+ char *encoded;
+ desc1 = hs_helper_build_hs_desc_with_ip(&service_kp);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(encoded);
+
+ /* Store it */
+ ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
+ tor_free(encoded);
+ tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
+ }
+
+ /* Remove the cached entry. */
+ hs_cache_remove_as_client(&service_kp.pubkey);
+ tt_assert(!hs_cache_lookup_as_client(&service_kp.pubkey));
+
+ done:
+ hs_descriptor_free(desc1);
+ hs_free_all();
+
+ UNMOCK(networkstatus_get_live_consensus);
+}
+
struct testcase_t hs_cache[] = {
/* Encoding tests. */
{ "directory", test_directory, TT_FORK,
@@ -579,6 +713,10 @@ struct testcase_t hs_cache[] = {
NULL, NULL },
{ "client_cache", test_client_cache, TT_FORK,
NULL, NULL },
+ { "client_cache_decrypt", test_client_cache_decrypt, TT_FORK,
+ NULL, NULL },
+ { "client_cache_remove", test_client_cache_remove, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c
index 403509fbc8..5406339276 100644
--- a/src/test/test_hs_cell.c
+++ b/src/test/test_hs_cell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index b777dafdfb..ae5cc5ed84 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,7 +10,7 @@
#define CRYPTO_PRIVATE
#define MAINLOOP_PRIVATE
#define HS_CLIENT_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CIRCUITBUILD_PRIVATE
#define CIRCUITLIST_PRIVATE
#define CONNECTION_PRIVATE
@@ -25,6 +25,7 @@
#include "app/config/config.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_dh.h"
+#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/channeltls.h"
#include "feature/dircommon/directory.h"
#include "core/mainloop/mainloop.h"
@@ -79,6 +80,23 @@ mock_networkstatus_get_live_consensus(time_t now)
}
static int
+mock_write_str_to_file(const char *path, const char *str, int bin)
+{
+ (void) bin;
+ (void) path;
+ (void) str;
+ return 0;
+}
+
+static or_options_t mocked_options;
+
+static const or_options_t *
+mock_get_options(void)
+{
+ return &mocked_options;
+}
+
+static int
helper_config_client(const char *conf, int validate_only)
{
int ret = 0;
@@ -92,6 +110,24 @@ helper_config_client(const char *conf, int validate_only)
return ret;
}
+static void
+helper_add_random_client_auth(const ed25519_public_key_t *service_pk)
+{
+ char *conf = NULL;
+#define conf_fmt "ClientOnionAuthDir %s\n"
+ tor_asprintf(&conf, conf_fmt, get_fname("auth_keys"));
+#undef conf_fmt
+ helper_config_client(conf, 0);
+ tor_free(conf);
+
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ hs_client_service_authorization_t *auth =
+ tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+ curve25519_secret_key_generate(&auth->enc_seckey, 0);
+ hs_build_address(service_pk, HS_VERSION_THREE, auth->onion_address);
+ digest256map_set(client_auths, service_pk->pubkey, auth);
+}
+
/* Test helper function: Setup a circuit and a stream with the same hidden
* service destination, and put them in <b>circ_out</b> and
* <b>conn_out</b>. Make the stream wait for circuits to be established to the
@@ -287,7 +323,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, 0);
tt_int_op(retval, OP_EQ, 0);
tt_assert(or_circ);
tt_assert(conn);
@@ -303,9 +339,8 @@ test_e2e_rend_circuit_setup(void *arg)
/**********************************************/
/* Setup the circuit */
- retval = hs_circuit_setup_e2e_rend_circ(or_circ,
- ntor_key_seed, sizeof(ntor_key_seed),
- 0);
+ retval = hs_circuit_setup_e2e_rend_circ(or_circ, ntor_key_seed,
+ sizeof(ntor_key_seed), 0);
tt_int_op(retval, OP_EQ, 0);
/**********************************************/
@@ -315,11 +350,9 @@ test_e2e_rend_circuit_setup(void *arg)
tt_int_op(retval, OP_EQ, 1);
/* Check that the crypt path has prop224 algorithm parameters */
- tt_int_op(
- crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_int_op(
- crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
OP_EQ, DIGEST_SHA3_256);
tt_assert(or_circ->cpath->pvt_crypto.f_crypto);
tt_assert(or_circ->cpath->pvt_crypto.b_crypto);
@@ -393,15 +426,17 @@ test_client_pick_intro(void *arg)
tt_assert(encoded);
/* store it */
- hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
/* fetch it to make sure it works */
const hs_descriptor_t *fetched_desc =
hs_cache_lookup_as_client(&service_kp.pubkey);
tt_assert(fetched_desc);
- tt_mem_op(fetched_desc->subcredential, OP_EQ, desc->subcredential,
- DIGEST256_LEN);
- tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential,
+ tt_mem_op(fetched_desc->subcredential.subcred,
+ OP_EQ, desc->subcredential.subcred,
+ SUBCRED_LEN);
+ tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential.subcred,
DIGEST256_LEN));
tor_free(encoded);
}
@@ -550,6 +585,17 @@ mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
}
static void
+mock_connection_mark_unattached_ap_no_close(entry_connection_t *conn,
+ int endreason, int line,
+ const char *file)
+{
+ (void) conn;
+ (void) endreason;
+ (void) line;
+ (void) file;
+}
+
+static void
test_descriptor_fetch(void *arg)
{
int ret;
@@ -687,6 +733,10 @@ test_parse_auth_file_content(void *arg)
/* Bigger key than it should be */
tt_assert(!parse_auth_file_content("xx:descriptor:x25519:"
"vjqea4jbhwwc4hto7ekyvqfbeodghbaq6nxi45hz4wr3qvhqv3yqa"));
+ /* All-zeroes key */
+ tt_assert(!parse_auth_file_content("xx:descriptor:x25519:"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+
done:
tor_free(auth);
}
@@ -824,6 +874,7 @@ test_desc_has_arrived_cleanup(void *arg)
ed25519_keypair_t signing_kp;
entry_connection_t *socks1 = NULL, *socks2 = NULL;
hs_ident_dir_conn_t hs_dir_ident;
+ dir_connection_t *dir_conn = NULL;
(void) arg;
@@ -852,7 +903,7 @@ test_desc_has_arrived_cleanup(void *arg)
/* Store in the client cache. */
ret = hs_cache_store_as_client(desc_str, &signing_kp.pubkey);
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
tt_assert(cached_desc);
hs_helper_desc_equal(desc, cached_desc);
@@ -880,9 +931,11 @@ test_desc_has_arrived_cleanup(void *arg)
* SOCKS connection to be ended with a resolved failed. */
hs_ident_dir_conn_init(&signing_kp.pubkey,
&desc->plaintext_data.blinded_pubkey, &hs_dir_ident);
- hs_client_desc_has_arrived(&hs_dir_ident);
+ dir_conn = dir_connection_new(AF_INET);
+ dir_conn->hs_ident = hs_ident_dir_conn_dup(&hs_dir_ident);
+ hs_client_dir_fetch_done(dir_conn, "A reason", desc_str, 200);
+ connection_free_minimal(TO_CONN(dir_conn));
tt_int_op(socks1->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
- /* XXX: MUST work with OP_EQ. */
tt_int_op(socks2->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
/* Now let say tor cleans up the intro state cache which resets all intro
@@ -891,7 +944,6 @@ test_desc_has_arrived_cleanup(void *arg)
/* Retrying all SOCKS which should basically do nothing since we don't have
* any pending SOCKS connection in AP_CONN_STATE_RENDDESC_WAIT state. */
- /* XXX: BUG() is triggered here, shouldn't if socks2 wasn't alive. */
retry_all_socks_conn_waiting_for_desc();
done:
@@ -918,6 +970,7 @@ 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(). */
@@ -942,6 +995,51 @@ test_close_intro_circuits_new_desc(void *arg)
circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
ocirc = TO_ORIGIN_CIRCUIT(circ);
+ /* Build a descriptor _without_ client authorization and thus not
+ * decryptable. Make sure the close circuit code path is not triggered. */
+ {
+ char *desc_encoded = NULL;
+ uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
+ curve25519_keypair_t client_kp;
+ hs_descriptor_t *desc = NULL;
+
+ tt_int_op(0, OP_EQ, curve25519_keypair_generate(&client_kp, 0));
+ crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
+
+ desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie,
+ &client_kp.pubkey,
+ &service_kp);
+ tt_assert(desc);
+ ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
+ &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Associate descriptor intro key with the dummy circuit. */
+ const hs_desc_intro_point_t *ip =
+ smartlist_get(desc->encrypted_data.intro_points, 0);
+ tt_assert(ip);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
+ &ip->auth_key_cert->signed_key);
+ hs_descriptor_free(desc);
+ tt_assert(desc_encoded);
+ /* Put it in the cache. Should not be decrypted since the client
+ * authorization creds were not added to the global map. */
+ ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey);
+ tor_free(desc_encoded);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
+
+ /* Clean cache with a future timestamp. It will trigger the clean up and
+ * attempt to close the circuit but only if the descriptor is decryptable.
+ * Cache object should be removed and circuit untouched. */
+ hs_cache_clean_as_client(mock_ns.valid_after + (60 * 60 * 24));
+ tt_assert(!hs_cache_lookup_as_client(&service_kp.pubkey));
+
+ /* Make sure the circuit still there. */
+ tt_assert(circuit_get_next_intro_circ(NULL, true));
+ /* Get rid of the ident, it will be replaced in the next tests. */
+ hs_ident_circuit_free(ocirc->hs_ident);
+ }
+
/* Build the first descriptor and cache it. */
{
char *encoded;
@@ -953,7 +1051,7 @@ test_close_intro_circuits_new_desc(void *arg)
/* Store it */
ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tor_free(encoded);
tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
}
@@ -988,8 +1086,8 @@ test_close_intro_circuits_new_desc(void *arg)
tt_int_op(ret, OP_EQ, 0);
tt_assert(encoded);
- hs_cache_store_as_client(encoded, &service_kp.pubkey);
- tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tor_free(encoded);
tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
}
@@ -1091,6 +1189,366 @@ test_close_intro_circuits_cache_clean(void *arg)
UNMOCK(networkstatus_get_live_consensus);
}
+static void
+test_socks_hs_errors(void *arg)
+{
+ int ret;
+ char digest[DIGEST_LEN];
+ char *desc_encoded = NULL;
+ circuit_t *circ = NULL;
+ origin_circuit_t *ocirc = NULL;
+ tor_addr_t addr;
+ ed25519_keypair_t service_kp;
+ ed25519_keypair_t signing_kp;
+ entry_connection_t *socks_conn = NULL;
+ dir_connection_t *dir_conn = NULL;
+ hs_descriptor_t *desc = NULL;
+ uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
+
+ (void) arg;
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+ MOCK(connection_mark_unattached_ap_,
+ mock_connection_mark_unattached_ap_no_close);
+ MOCK(read_file_to_str, mock_read_file_to_str);
+ MOCK(tor_listdir, mock_tor_listdir);
+ MOCK(check_private_dir, mock_check_private_dir);
+
+ /* Set consensus time */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ hs_init();
+
+ ret = ed25519_keypair_generate(&service_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ socks_conn = helper_build_socks_connection(&service_kp.pubkey,
+ AP_CONN_STATE_RENDDESC_WAIT);
+ tt_assert(socks_conn);
+
+ /* Create directory connection. */
+ dir_conn = dir_connection_new(AF_INET);
+ dir_conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t));
+ TO_CONN(dir_conn)->purpose = DIR_PURPOSE_FETCH_HSDESC;
+ ed25519_pubkey_copy(&dir_conn->hs_ident->identity_pk, &service_kp.pubkey);
+
+ /* Encode descriptor so we can decode it. */
+ desc = hs_helper_build_hs_desc_with_ip(&service_kp);
+ tt_assert(desc);
+
+ /* Before testing the client authentication error code, encode the
+ * descriptor with no client auth. */
+ ret = hs_desc_encode_descriptor(desc, &service_kp, NULL, &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(desc_encoded);
+
+ /*
+ * Test the introduction failure codes (X'F2' and X'F7')
+ */
+
+ /* First, we have to put all the IPs in the failure cache. */
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ hs_cache_client_intro_state_note(&service_kp.pubkey,
+ &ip->auth_key_cert->signed_key,
+ INTRO_POINT_FAILURE_GENERIC);
+ } SMARTLIST_FOREACH_END(ip);
+
+ hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_INTRO_FAILED);
+
+ /* Purge client cache of the descriptor so we can go again. */
+ hs_cache_purge_as_client();
+
+ /* Second, set all failures to be time outs. */
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ hs_cache_client_intro_state_note(&service_kp.pubkey,
+ &ip->auth_key_cert->signed_key,
+ INTRO_POINT_FAILURE_TIMEOUT);
+ } SMARTLIST_FOREACH_END(ip);
+
+ hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_INTRO_TIMEDOUT);
+
+ /* Purge client cache of the descriptor so we can go again. */
+ hs_cache_purge_as_client();
+
+ /*
+ * Test the rendezvous failure codes (X'F3')
+ */
+
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ /* Code path will log this exit so build it. */
+ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
+ NULL, NULL, NULL, &addr,
+ 4242);
+ /* 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. */
+ circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
+
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_REND_FAILED);
+
+ /*
+ * Test client authorization codes.
+ */
+
+ tor_free(desc_encoded);
+ crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
+ ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
+ &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(desc_encoded);
+
+ /* Try decoding. Point this to an existing descriptor. The following should
+ * fail thus the desc_out should be set to NULL. */
+ hs_descriptor_t *desc_out = desc;
+ ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey,
+ &desc_out);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
+ tt_assert(desc_out == NULL);
+
+ /* The caching will fail to decrypt because the descriptor_cookie used above
+ * is not known to the HS subsystem. This will lead to a missing client
+ * auth. */
+ hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
+
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_MISSING_CLIENT_AUTH);
+
+ /* Add in the global client auth list bad creds for this service. */
+ helper_add_random_client_auth(&service_kp.pubkey);
+
+ ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey,
+ &desc_out);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH);
+ tt_assert(desc_out == NULL);
+
+ /* Simmulate a fetch done again. This should replace the cached descriptor
+ * and signal a bad client authorization. */
+ hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_BAD_CLIENT_AUTH);
+
+ done:
+ connection_free_minimal(ENTRY_TO_CONN(socks_conn));
+ connection_free_minimal(TO_CONN(dir_conn));
+ hs_descriptor_free(desc);
+ tor_free(desc_encoded);
+ circuit_free(circ);
+
+ hs_free_all();
+
+ UNMOCK(networkstatus_get_live_consensus);
+ UNMOCK(connection_mark_unattached_ap_);
+ UNMOCK(read_file_to_str);
+ UNMOCK(tor_listdir);
+ UNMOCK(check_private_dir);
+}
+
+static void
+test_close_intro_circuit_failure(void *arg)
+{
+ char digest[DIGEST_LEN];
+ circuit_t *circ = NULL;
+ ed25519_keypair_t service_kp, intro_kp;
+ origin_circuit_t *ocirc = NULL;
+ tor_addr_t addr;
+ const hs_cache_intro_state_t *entry;
+
+ (void) arg;
+
+ hs_init();
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&intro_kp, 0));
+
+ /* Create and add to the global list a dummy client introduction circuit at
+ * the ACK WAIT state. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ /* Code path will log this exit so build it. */
+ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
+ NULL, NULL, NULL, &addr,
+ 4242);
+ 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_
+ * end up in the failure cache just yet. We do that on free() only. */
+ circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
+ tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey));
+ /* Time to free. It should get removed. */
+ circuit_free(circ);
+ entry = hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey);
+ tt_assert(entry);
+ tt_uint_op(entry->timed_out, OP_EQ, 1);
+ hs_cache_client_intro_state_purge();
+
+ /* Again, create and add to the global list a dummy client introduction
+ * circuit at the INTRODUCING state. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ /* Code path will log this exit so build it. */
+ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
+ NULL, NULL, NULL, &addr,
+ 4242);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
+
+ /* On free, we should get an unreachable failure. */
+ circuit_free(circ);
+ entry = hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey);
+ tt_assert(entry);
+ tt_uint_op(entry->unreachable_count, OP_EQ, 1);
+ hs_cache_client_intro_state_purge();
+
+ /* Again, create and add to the global list a dummy client introduction
+ * circuit at the INTRODUCING state but we'll close it for timeout. It
+ * should not be noted as a timeout failure. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ /* Code path will log this exit so build it. */
+ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
+ NULL, NULL, NULL, &addr,
+ 4242);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
+
+ circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
+ circuit_free(circ);
+ tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey));
+
+ /* Again, create and add to the global list a dummy client introduction
+ * circuit at the INTRODUCING state but without a chosen_exit. In theory, it
+ * can not happen but we'll make sure it doesn't end up in the failure cache
+ * anyway. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
+
+ circuit_free(circ);
+ tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey));
+
+ done:
+ circuit_free(circ);
+ hs_free_all();
+}
+
+static void
+test_purge_ephemeral_client_auth(void *arg)
+{
+ ed25519_keypair_t service_kp;
+ hs_client_service_authorization_t *auth = NULL;
+ hs_client_register_auth_status_t status;
+
+ (void) arg;
+
+ /* We will try to write on disk client credentials. */
+ MOCK(check_private_dir, mock_check_private_dir);
+ MOCK(get_options, mock_get_options);
+ MOCK(write_str_to_file, mock_write_str_to_file);
+
+ /* Boggus directory so when we try to write the permanent client
+ * authorization data to disk, we don't fail. See
+ * store_permanent_client_auth_credentials() for more details. */
+ mocked_options.ClientOnionAuthDir = tor_strdup("auth_dir");
+
+ hs_init();
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+
+ /* Generate a client authorization object. */
+ auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+
+ /* Set it up. No flags meaning it is ephemeral. */
+ curve25519_secret_key_generate(&auth->enc_seckey, 0);
+ hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address);
+ auth->flags = 0;
+
+ /* Confirm that there is nothing in the client auth map. It is unallocated
+ * until we add the first entry. */
+ tt_assert(!get_hs_client_auths_map());
+
+ /* Add an entry to the client auth list. We loose ownership of the auth
+ * object so nullify it. */
+ status = hs_client_register_auth_credentials(auth);
+ auth = NULL;
+ tt_int_op(status, OP_EQ, REGISTER_SUCCESS);
+
+ /* We should have the entry now. */
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ tt_assert(client_auths);
+ tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
+
+ /* Purge the cache that should remove all ephemeral values. */
+ purge_ephemeral_client_auth();
+ tt_int_op(digest256map_size(client_auths), OP_EQ, 0);
+
+ /* Now add a new authorization object but permanent. */
+ /* Generate a client authorization object. */
+ auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+ curve25519_secret_key_generate(&auth->enc_seckey, 0);
+ hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address);
+ auth->flags = CLIENT_AUTH_FLAG_IS_PERMANENT;
+
+ /* Add an entry to the client auth list. We loose ownership of the auth
+ * object so nullify it. */
+ status = hs_client_register_auth_credentials(auth);
+ auth = NULL;
+ tt_int_op(status, OP_EQ, REGISTER_SUCCESS);
+ tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
+
+ /* Purge again, the entry should still be there. */
+ purge_ephemeral_client_auth();
+ tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
+
+ done:
+ client_service_authorization_free(auth);
+ hs_free_all();
+ tor_free(mocked_options.ClientOnionAuthDir);
+
+ UNMOCK(check_private_dir);
+ UNMOCK(get_options);
+ UNMOCK(write_str_to_file);
+}
+
struct testcase_t hs_client_tests[] = {
{ "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
TT_FORK, NULL, NULL },
@@ -1108,10 +1566,19 @@ struct testcase_t hs_client_tests[] = {
TT_FORK, NULL, NULL },
{ "desc_has_arrived_cleanup", test_desc_has_arrived_cleanup,
TT_FORK, NULL, NULL },
+ { "close_intro_circuit_failure", test_close_intro_circuit_failure,
+ TT_FORK, NULL, NULL },
{ "close_intro_circuits_new_desc", test_close_intro_circuits_new_desc,
TT_FORK, NULL, NULL },
{ "close_intro_circuits_cache_clean", test_close_intro_circuits_cache_clean,
TT_FORK, NULL, NULL },
+ /* SOCKS5 Extended Error Code. */
+ { "socks_hs_errors", test_socks_hs_errors, TT_FORK, NULL, NULL },
+
+ /* Client authorization. */
+ { "purge_ephemeral_client_auth", test_purge_ephemeral_client_auth, TT_FORK,
+ NULL, NULL },
+
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index de3f7e04f7..9202074e25 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,6 +6,7 @@
* \brief Test hidden service common functionalities.
*/
+#define CONNECTION_EDGE_PRIVATE
#define HS_COMMON_PRIVATE
#define HS_CLIENT_PRIVATE
#define HS_SERVICE_PRIVATE
@@ -31,7 +32,7 @@
#include "app/config/statefile.h"
#include "core/or/circuitlist.h"
#include "feature/dirauth/shared_random.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -52,14 +53,14 @@ test_validate_address(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = hs_address_is_valid("blah");
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg_containing("has an invalid length");
+ expect_log_msg_containing("Invalid length");
teardown_capture_of_logs();
setup_full_capture_of_logs(LOG_WARN);
ret = hs_address_is_valid(
"p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnadb");
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg_containing("has an invalid length");
+ expect_log_msg_containing("Invalid length");
teardown_capture_of_logs();
/* Invalid checksum (taken from prop224) */
@@ -82,7 +83,7 @@ test_validate_address(void *arg)
ret = hs_address_is_valid(
"????????????????????????????????????????????????????????");
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg_containing("can't be decoded");
+ expect_log_msg_containing("Unable to base32 decode");
teardown_capture_of_logs();
/* Valid address. */
@@ -778,6 +779,7 @@ static void
test_parse_extended_hostname(void *arg)
{
(void) arg;
+ hostname_type_t type;
char address1[] = "fooaddress.onion";
char address2[] = "aaaaaaaaaaaaaaaa.onion";
@@ -788,21 +790,48 @@ test_parse_extended_hostname(void *arg)
char address7[] = ".abcdefghijklmnop.onion";
char address8[] =
"www.25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion";
+ char address9[] =
+ "www.15njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion";
+ char address10[] =
+ "15njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid7jdl.onion";
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
- tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address2));
- tt_str_op(address2,OP_EQ, "aaaaaaaaaaaaaaaa");
- tt_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
- tt_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
- tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address5));
- tt_str_op(address5,OP_EQ, "abcdefghijklmnop");
- tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address6));
- tt_str_op(address6,OP_EQ, "abcdefghijklmnop");
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
- tt_assert(ONION_V3_HOSTNAME == parse_extended_hostname(address8));
+ 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, ONION_V2_HOSTNAME);
+ tt_str_op(address2, OP_EQ, "aaaaaaaaaaaaaaaa");
+
+ tt_assert(parse_extended_hostname(address3, &type));
+ tt_int_op(type, OP_EQ, EXIT_HOSTNAME);
+
+ tt_assert(parse_extended_hostname(address4, &type));
+ tt_int_op(type, OP_EQ, NORMAL_HOSTNAME);
+
+ tt_assert(parse_extended_hostname(address5, &type));
+ tt_int_op(type, OP_EQ, ONION_V2_HOSTNAME);
+ tt_str_op(address5, OP_EQ, "abcdefghijklmnop");
+
+ tt_assert(parse_extended_hostname(address6, &type));
+ tt_int_op(type, OP_EQ, ONION_V2_HOSTNAME);
+ tt_str_op(address6, OP_EQ, "abcdefghijklmnop");
+
+ tt_assert(!parse_extended_hostname(address7, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
+ tt_assert(parse_extended_hostname(address8, &type));
+ tt_int_op(type, OP_EQ, ONION_V3_HOSTNAME);
tt_str_op(address8, OP_EQ,
"25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
+ /* Invalid v3 address. */
+ tt_assert(!parse_extended_hostname(address9, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
+ /* Invalid v3 address: too long */
+ tt_assert(!parse_extended_hostname(address10, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
done: ;
}
@@ -830,7 +859,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 26 Oct 1985 01:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -838,7 +867,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 26 Oct 1985 12:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -846,7 +875,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 1);
@@ -854,7 +883,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 27 Oct 1985 00:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 1);
@@ -862,7 +891,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 27 Oct 1985 01:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -1349,7 +1378,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
&mock_service_ns->valid_until);
set_consensus_times(cfg->service_valid_until,
&mock_service_ns->fresh_until);
- voting_schedule_recalculate_timing(get_options(),
+ dirauth_sched_recalculate_timing(get_options(),
mock_service_ns->valid_after);
/* Check that service is in the right time period point */
tt_int_op(hs_in_period_between_tp_and_srv(mock_service_ns, 0), OP_EQ,
@@ -1362,7 +1391,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
&mock_client_ns->valid_until);
set_consensus_times(cfg->client_valid_until,
&mock_client_ns->fresh_until);
- voting_schedule_recalculate_timing(get_options(),
+ dirauth_sched_recalculate_timing(get_options(),
mock_client_ns->valid_after);
/* Check that client is in the right time period point */
tt_int_op(hs_in_period_between_tp_and_srv(mock_client_ns, 0), OP_EQ,
@@ -1585,7 +1614,7 @@ helper_set_consensus_and_system_time(networkstatus_t *ns, int position)
} else {
tt_assert(0);
}
- voting_schedule_recalculate_timing(get_options(), ns->valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns->valid_after);
/* Set system time: pretend to be just 2 minutes before consensus expiry */
real_time = ns->valid_until - 120;
diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c
index 71e1529216..dc3b598c34 100644
--- a/src/test/test_hs_config.c
+++ b/src/test/test_hs_config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -62,8 +62,9 @@ test_invalid_service(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 1);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceAllowUnknownPorts must be "
- "between 0 and 1, not 2");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceAllowUnknownPorts: Unrecognized "
+ "value 2. Allowed values are 0 and 1.");
teardown_capture_of_logs();
}
@@ -76,8 +77,9 @@ test_invalid_service(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 1);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceDirGroupReadable must be "
- "between 0 and 1, not 2");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceDirGroupReadable: "
+ "Unrecognized value 2.");
teardown_capture_of_logs();
}
@@ -90,8 +92,9 @@ test_invalid_service(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 1);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceMaxStreamsCloseCircuit must "
- "be between 0 and 1, not 2");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceMaxStreamsCloseCircuit: "
+ "Unrecognized value 2");
teardown_capture_of_logs();
}
@@ -228,8 +231,8 @@ test_invalid_service_v2(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, validate_only);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceNumIntroductionPoints should "
- "be between 0 and 10, not 11");
+ expect_log_msg_containing("HiddenServiceNumIntroductionPoints must "
+ "be between 0 and 10, not 11.");
teardown_capture_of_logs();
}
@@ -243,8 +246,9 @@ test_invalid_service_v2(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, validate_only);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceNumIntroductionPoints should "
- "be between 0 and 10, not -1");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceNumIntroductionPoints: "
+ "Integer -1 is malformed or out of bounds.");
teardown_capture_of_logs();
}
@@ -532,9 +536,10 @@ test_dos_parameters(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceEnableIntroDoSRatePerSec must "
- "be between 0 and 2147483647, "
- "not 137438953472");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSRatePerSec: "
+ "Integer 137438953472 is malformed or out of "
+ "bounds.");
teardown_capture_of_logs();
}
@@ -551,9 +556,10 @@ test_dos_parameters(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceEnableIntroDoSBurstPerSec must "
- "be between 0 and 2147483647, "
- "not 274877906944");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSBurstPerSec: "
+ "Integer 274877906944 is malformed or out "
+ "of bounds.");
teardown_capture_of_logs();
}
@@ -588,8 +594,9 @@ test_dos_parameters(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceEnableIntroDoSRatePerSec must be "
- "between 0 and 2147483647, not -1");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSRatePerSec: "
+ "Integer -1 is malformed or out of bounds.");
teardown_capture_of_logs();
}
diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
index 7cedc987bb..1f574179e9 100644
--- a/src/test/test_hs_control.c
+++ b/src/test/test_hs_control.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -7,14 +7,20 @@
**/
#define CONTROL_EVENTS_PRIVATE
+#define HS_CLIENT_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_fmt.h"
+#include "feature/control/control_connection_st.h"
#include "app/config/config.h"
#include "feature/hs/hs_common.h"
+#include "feature/hs/hs_client.h"
#include "feature/hs/hs_control.h"
#include "feature/nodelist/nodelist.h"
@@ -22,7 +28,16 @@
#include "feature/nodelist/routerstatus_st.h"
#include "lib/crypt_ops/crypto_format.h"
-#include "test/test_helpers.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#else
+#include <dirent.h>
+#endif /* defined(_WIN32) */
/* mock ID digest and longname for node that's in nodelist */
#define HSDIR_EXIST_ID \
@@ -187,9 +202,511 @@ test_hs_desc_event(void *arg)
tor_free(expected_msg);
}
+/** Test that we can correctly add, remove and view client auth credentials
+ * using the control port. */
+static void
+test_hs_control_good_onion_client_auth_add(void *arg)
+{
+ (void) arg;
+
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ int retval;
+ ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4;
+ control_connection_t conn;
+ char *args = NULL;
+ char *cp1 = NULL;
+ size_t sz;
+
+ hs_init();
+
+ { /* Setup the control conn */
+ memset(&conn, 0, sizeof(control_connection_t));
+ TO_CONN(&conn)->outbuf = buf_new();
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
+ }
+
+ { /* Setup the services */
+ retval = hs_parse_address(
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd",
+ &service_identity_pk_2fv,
+ NULL, NULL);
+ tt_int_op(retval, OP_EQ, 0);
+
+ retval = hs_parse_address(
+ "jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd",
+ &service_identity_pk_jt4,
+ NULL, NULL);
+ tt_int_op(retval, OP_EQ, 0);
+ }
+
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ tt_assert(!client_auths);
+
+ /* Register first service */
+ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
+ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= ");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check contents */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Register second service (even with an unrecognized argument) */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA= DropSound=No");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check contents */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+ tor_free(cp1);
+
+ client_auths = get_hs_client_auths_map();
+ tt_assert(client_auths);
+ tt_uint_op(digest256map_size(client_auths), OP_EQ, 2);
+
+ hs_client_service_authorization_t *client_2fv =
+ digest256map_get(client_auths, service_identity_pk_2fv.pubkey);
+ tt_assert(client_2fv);
+ tt_int_op(client_2fv->flags, OP_EQ, 0);
+
+ hs_client_service_authorization_t *client_jt4 =
+ digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
+ tt_assert(client_jt4);
+ tt_int_op(client_jt4->flags, OP_EQ, 0);
+
+ /* Now let's VIEW the auth credentials */
+ tor_free(conn.current_cmd);
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW");
+
+ /* First go with no arguments, so that we view all the credentials */
+ tor_free(args);
+ args = tor_strdup("");
+
+#define VIEW_CORRECT_REPLY_NO_ADDR "250-ONION_CLIENT_AUTH_VIEW\r\n" \
+ "250-CLIENT 2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " \
+ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=\r\n" \
+ "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \
+ "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \
+ "250 OK\r\n"
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_NO_ADDR);
+ tor_free(cp1);
+
+ /* Now specify an HS addr, and see that we only view those creds */
+ tor_free(args);
+ args =
+ tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd");
+
+#define VIEW_CORRECT_REPLY_JT4 "250-ONION_CLIENT_AUTH_VIEW " \
+ "jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd\r\n" \
+ "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \
+ "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \
+ "250 OK\r\n"
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_JT4);
+ tor_free(cp1);
+
+ /* Now try to REMOVE the auth credentials */
+ tor_free(conn.current_cmd);
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_REMOVE");
+
+ /* First try with a wrong addr */
+ tor_free(args);
+ args = tor_strdup("thatsok");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"thatsok\"\r\n");
+ tor_free(cp1);
+
+ client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
+ tt_assert(client_jt4);
+
+ /* Now actually remove them. */
+ tor_free(args);
+ args =tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+ tor_free(cp1);
+
+ client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
+ tt_assert(!client_jt4);
+
+ /* Now try another time (we should get 'already removed' msg) */
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "251 No credentials for "
+ "\"jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd\"\r\n");
+ tor_free(cp1);
+
+ client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
+ tt_assert(!client_jt4);
+
+ /* Now also remove the other one */
+ tor_free(args);
+ args =tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+ tor_free(cp1);
+
+ /* Finally, do another VIEW and see that we get nothing. */
+ tor_free(conn.current_cmd);
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW");
+ tor_free(args);
+ args = tor_strdup("");
+
+#define VIEW_CORRECT_REPLY_NOTHING "250-ONION_CLIENT_AUTH_VIEW\r\n250 OK\r\n"
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_NOTHING);
+ tor_free(cp1);
+
+ /* And a final VIEW with a wrong HS addr */
+ tor_free(args);
+ args = tor_strdup("house");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"house\"\r\n");
+
+ done:
+ tor_free(args);
+ tor_free(cp1);
+ buf_free(TO_CONN(&conn)->outbuf);
+ tor_free(conn.current_cmd);
+ hs_client_free_all();
+}
+
+/** Test some error cases of ONION_CLIENT_AUTH_ADD */
+static void
+test_hs_control_bad_onion_client_auth_add(void *arg)
+{
+ (void) arg;
+
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ int retval;
+ control_connection_t conn;
+ char *cp1 = NULL;
+ size_t sz;
+ char *args = NULL;
+
+ hs_init();
+
+ { /* Setup the control conn */
+ memset(&conn, 0, sizeof(control_connection_t));
+ TO_CONN(&conn)->outbuf = buf_new();
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
+ }
+
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ tt_assert(!client_auths);
+
+ /* Register first service */
+ args = tor_strdup(
+ "badaddr x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check contents */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"badaddr\"\r\n");
+
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Register second service (even with an unrecognized argument) */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "love:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check contents */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "552 Unrecognized key type \"love\"\r\n");
+
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Register second service (even with an unrecognized argument) */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "x25519:QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEK");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check contents */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "512 Failed to decode x25519 private key\r\n");
+
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Register with an all zero client key */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "x25519:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check contents */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "553 Invalid private key \"AAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAAAAAAAA=\"\r\n");
+
+ client_auths = get_hs_client_auths_map();
+ tt_assert(!client_auths);
+
+ done:
+ tor_free(args);
+ tor_free(cp1);
+ buf_free(TO_CONN(&conn)->outbuf);
+ tor_free(conn.current_cmd);
+ hs_client_free_all();
+}
+
+/** Test that we can correctly add permanent client auth credentials using the
+ * control port. */
+static void
+test_hs_control_store_permanent_creds(void *arg)
+{
+ (void) arg;
+
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ int retval;
+ ed25519_public_key_t service_identity_pk_2fv;
+ control_connection_t conn;
+ char *args = NULL;
+ char *cp1 = NULL;
+ char *creds_file_str = NULL;
+ char *creds_fname = NULL;
+
+ size_t sz;
+
+ hs_init();
+
+ { /* Setup the control conn */
+ memset(&conn, 0, sizeof(control_connection_t));
+ TO_CONN(&conn)->outbuf = buf_new();
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
+ }
+
+ { /* Setup the services */
+ retval = hs_parse_address(
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd",
+ &service_identity_pk_2fv,
+ NULL, NULL);
+ tt_int_op(retval, OP_EQ, 0);
+ }
+
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ tt_assert(!client_auths);
+
+ /* Try registering first service with no ClientOnionAuthDir set */
+ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
+ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= "
+ "Flags=Permanent");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check control port response. This one should fail. */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "553 Unable to store creds for "
+ "\"2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd\"\r\n");
+
+ { /* Setup ClientOnionAuthDir */
+ int ret;
+ char *perm_creds_dir = tor_strdup(get_fname("permanent_credentials"));
+ get_options_mutable()->ClientOnionAuthDir = perm_creds_dir;
+
+ #ifdef _WIN32
+ ret = mkdir(perm_creds_dir);
+ #else
+ ret = mkdir(perm_creds_dir, 0700);
+ #endif
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ tor_free(args);
+ tor_free(cp1);
+
+ /* Try the control port command again. This time it should work! */
+ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
+ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= "
+ "Flags=Permanent");
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check control port response */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+
+ /* Check file contents! */
+ creds_fname = tor_strdup(get_fname("permanent_credentials/"
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd.auth_private"));
+ creds_file_str = read_file_to_str(creds_fname, RFTS_BIN, NULL);
+
+ tt_assert(creds_file_str);
+ tt_str_op(creds_file_str, OP_EQ,
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd:descriptor:"
+ /* This is the base32 represenation of the base64 iJ1t... key above */
+ "x25519:rcow3dfavmyanyqvhwnvnmfdqw34ydtrgv7jnelmqs4wi4uuxrca");
+
+ tor_free(args);
+ tor_free(cp1);
+
+ /* Overwrite the credentials and check that they got overwrited. */
+ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
+ "x25519:UDRvZLvcJo0QRLvDfkpgbtsqbkhIUQZyeo2FNBrgS18= "
+ "Flags=Permanent");
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check control port response: we replaced! */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "251 Client for onion existed and replaced\r\n");
+
+ tor_free(creds_file_str);
+
+ /* Check creds file contents again. See that the key got updated */
+ creds_file_str = read_file_to_str(creds_fname, RFTS_BIN, NULL);
+ tt_assert(creds_file_str);
+ tt_str_op(creds_file_str, OP_EQ,
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd:descriptor:"
+ /* This is the base32 represenation of the base64 UDRv... key above */
+ "x25519:ka2g6zf33qti2ecexpbx4stan3nsu3sijbiqm4t2rwctigxajnpq");
+
+ /* Now for our next act!!! Actually get the HS client subsystem to parse the
+ * whole directory and make sure that it extracted the right credential! */
+ hs_config_client_authorization(get_options(), 0);
+
+ client_auths = get_hs_client_auths_map();
+ tt_assert(client_auths);
+ tt_uint_op(digest256map_size(client_auths), OP_EQ, 1);
+
+ hs_client_service_authorization_t *client_2fv =
+ digest256map_get(client_auths, service_identity_pk_2fv.pubkey);
+ tt_assert(client_2fv);
+ tt_int_op(client_2fv->flags, OP_EQ, CLIENT_AUTH_FLAG_IS_PERMANENT);
+ tt_str_op(hex_str((char*)client_2fv->enc_seckey.secret_key, 32), OP_EQ,
+ "50346F64BBDC268D1044BBC37E4A606EDB2A6E48485106727A8D85341AE04B5F");
+
+ /* And now for the final act! Use the REMOVE control port command to remove
+ the credential, and ensure that the file has also been removed! */
+ tor_free(conn.current_cmd);
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Ensure that the creds file exists */
+ tt_int_op(file_status(creds_fname), OP_EQ, FN_FILE);
+
+ /* Do the REMOVE */
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_REMOVE");
+ args =tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd");
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+
+ /* Ensure that the file has been removed and the map is empty */
+ tt_int_op(file_status(creds_fname), OP_EQ, FN_NOENT);
+ tt_uint_op(digest256map_size(client_auths), OP_EQ, 0);
+
+ done:
+ tor_free(get_options_mutable()->ClientOnionAuthDir);
+ tor_free(args);
+ tor_free(cp1);
+ buf_free(TO_CONN(&conn)->outbuf);
+ tor_free(conn.current_cmd);
+ tor_free(creds_fname);
+ tor_free(creds_file_str);
+ hs_client_free_all();
+}
+
+/** Test that ADD_ONION properly handles an attacker passing it a bad private
+ * key. */
+static void
+test_hs_control_add_onion_with_bad_pubkey(void *arg)
+{
+ (void) arg;
+
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ int retval;
+ control_connection_t conn;
+ char *args = NULL;
+ char *cp1 = NULL;
+ size_t sz;
+
+ hs_init();
+
+ { /* Setup the control conn */
+ 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:AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
+ "Port=9735,127.0.0.1 Flags=DiscardPK");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check control port response */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "551 Failed to generate onion address\r\n");
+
+ done:
+ tor_free(args);
+ tor_free(cp1);
+ buf_free(TO_CONN(&conn)->outbuf);
+ tor_free(conn.current_cmd);
+}
+
struct testcase_t hs_control_tests[] = {
{ "hs_desc_event", test_hs_desc_event, TT_FORK,
NULL, NULL },
+ { "hs_control_good_onion_client_auth_add",
+ test_hs_control_good_onion_client_auth_add, TT_FORK,
+ NULL, NULL },
+ { "hs_control_bad_onion_client_auth_add",
+ test_hs_control_bad_onion_client_auth_add, TT_FORK,
+ NULL, NULL },
+ { "hs_control_store_permanent_creds",
+ 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 },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 6fe5573c0f..782b78306c 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "trunnel/ed25519_cert.h"
#include "core/or/or.h"
+#include "app/config/config.h"
#include "feature/hs/hs_descriptor.h"
#include "test/test.h"
#include "feature/nodelist/torcert.h"
@@ -24,12 +25,12 @@
#include "test/rng_test_helpers.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-DISABLE_GCC_WARNING(overlength-strings)
+DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
* at large. */
#endif
#include "test_hs_descriptor.inc"
-ENABLE_GCC_WARNING(overlength-strings)
+ENABLE_GCC_WARNING("-Woverlength-strings")
/* Test certificate encoding put in a descriptor. */
static void
@@ -37,7 +38,6 @@ test_cert_encoding(void *arg)
{
int ret;
char *encoded = NULL;
- time_t now = time(NULL);
ed25519_keypair_t kp;
ed25519_public_key_t signed_key;
ed25519_secret_key_t secret_key;
@@ -45,6 +45,10 @@ test_cert_encoding(void *arg)
(void) arg;
+ /* Change time to 03-01-2002 23:36 UTC */
+ update_approx_time(1010101010);
+ time_t now = approx_time();
+
ret = ed25519_keypair_generate(&kp, 0);
tt_int_op(ret, == , 0);
ret = ed25519_secret_key_generate(&secret_key, 0);
@@ -88,13 +92,31 @@ test_cert_encoding(void *arg)
/* The cert did have the signing key? */
ret= ed25519_pubkey_eq(&parsed_cert->signing_key, &kp.pubkey);
tt_int_op(ret, OP_EQ, 1);
- tor_cert_free(parsed_cert);
/* Get to the end part of the certificate. */
pos += b64_cert_len;
tt_int_op(strcmpstart(pos, "-----END ED25519 CERT-----"), OP_EQ, 0);
pos += strlen("-----END ED25519 CERT-----");
tt_str_op(pos, OP_EQ, "");
+
+ /* Check that certificate expiry works properly and emits the right log
+ message */
+ const char *msg = "fire";
+ /* Move us forward 4 hours so that the the certificate is definitely
+ expired */
+ update_approx_time(approx_time() + 3600*4);
+ setup_full_capture_of_logs(LOG_PROTOCOL_WARN);
+ ret = cert_is_valid(parsed_cert, CERT_TYPE_SIGNING_AUTH, msg);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Since the current time at the creation of the cert was "03-01-2002
+ * 23:36", and the expiration date of the cert was two hours, the Tor code
+ * will ceiling that and make it 02:00. Make sure that the right log
+ * message is emitted */
+ expect_log_msg_containing("Invalid signature for fire: expired"
+ " (2002-01-04 02:00:00)");
+ teardown_capture_of_logs();
+
+ tor_cert_free(parsed_cert);
}
done:
@@ -221,7 +243,7 @@ test_decode_descriptor(void *arg)
hs_descriptor_t *desc = NULL;
hs_descriptor_t *decoded = NULL;
hs_descriptor_t *desc_no_ip = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
(void) arg;
@@ -230,19 +252,19 @@ test_decode_descriptor(void *arg)
desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
hs_helper_get_subcred_from_identity_keypair(&signing_kp,
- subcredential);
+ &subcredential);
/* Give some bad stuff to the decoding function. */
- ret = hs_desc_decode_descriptor("hladfjlkjadf", subcredential,
+ ret = hs_desc_decode_descriptor("hladfjlkjadf", &subcredential,
NULL, &decoded);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &encoded);
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(encoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded);
- tt_int_op(ret, OP_EQ, 0);
+ ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
hs_helper_desc_equal(desc, decoded);
@@ -253,7 +275,7 @@ test_decode_descriptor(void *arg)
ret = ed25519_keypair_generate(&signing_kp_no_ip, 0);
tt_int_op(ret, OP_EQ, 0);
hs_helper_get_subcred_from_identity_keypair(&signing_kp_no_ip,
- subcredential);
+ &subcredential);
desc_no_ip = hs_helper_build_hs_desc_no_ip(&signing_kp_no_ip);
tt_assert(desc_no_ip);
tor_free(encoded);
@@ -262,8 +284,8 @@ test_decode_descriptor(void *arg)
tt_int_op(ret, OP_EQ, 0);
tt_assert(encoded);
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded);
- tt_int_op(ret, OP_EQ, 0);
+ ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
}
@@ -286,14 +308,14 @@ test_decode_descriptor(void *arg)
&auth_ephemeral_kp.pubkey, CURVE25519_PUBKEY_LEN);
hs_helper_get_subcred_from_identity_keypair(&signing_kp,
- subcredential);
+ &subcredential);
/* Build and add the auth client to the descriptor. */
clients = desc->superencrypted_data.clients;
if (!clients) {
clients = smartlist_new();
}
- hs_desc_build_authorized_client(subcredential,
+ hs_desc_build_authorized_client(&subcredential,
&client_kp.pubkey,
&auth_ephemeral_kp.seckey,
descriptor_cookie, client);
@@ -315,23 +337,23 @@ test_decode_descriptor(void *arg)
/* If we do not have the client secret key, the decoding must fail. */
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
NULL, &decoded);
- tt_int_op(ret, OP_LT, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
tt_assert(!decoded);
/* If we have an invalid client secret key, the decoding must fail. */
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
&invalid_client_kp.seckey, &decoded);
- tt_int_op(ret, OP_LT, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH);
tt_assert(!decoded);
/* If we have the client secret key, the decoding must succeed and the
* decoded descriptor must be correct. */
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
&client_kp.seckey, &decoded);
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
hs_helper_desc_equal(desc, decoded);
@@ -567,7 +589,7 @@ test_decode_bad_signature(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = hs_desc_decode_plaintext(HS_DESC_BAD_SIG, &desc_plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
expect_log_msg_containing("Malformed signature line. Rejecting.");
teardown_capture_of_logs();
@@ -607,14 +629,14 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, bad_value, "180", "42", "MESSAGE");
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Missing fields. */
{
const char *plaintext = "hs-descriptor 3\n";
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Max length. */
@@ -627,7 +649,7 @@ test_decode_plaintext(void *arg)
plaintext[big - 1] = '\0';
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Bad lifetime value. */
@@ -636,7 +658,7 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, "3", bad_value, "42", "MESSAGE");
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Huge lifetime value. */
@@ -645,7 +667,7 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, "3", "7181615", "42", "MESSAGE");
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Invalid encrypted section. */
@@ -654,7 +676,7 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, "3", "180", "42", bad_value);
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Invalid revision counter. */
@@ -663,7 +685,7 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, "3", "180", bad_value, "MESSAGE");
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
done:
@@ -762,7 +784,7 @@ test_build_authorized_client(void *arg)
"07d087f1d8c68393721f6e70316d3b29";
const char client_pubkey_b16[] =
"8c1298fa6050e372f8598f6deca32e27b0ad457741422c2629ebb132cf7fae37";
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *mem_op_hex_tmp=NULL;
(void) arg;
@@ -774,7 +796,7 @@ test_build_authorized_client(void *arg)
tt_int_op(ret, OP_EQ, 0);
curve25519_public_key_generate(&client_auth_pk, &client_auth_sk);
- memset(subcredential, 42, sizeof(subcredential));
+ memset(subcredential.subcred, 42, sizeof(subcredential));
desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t));
@@ -795,7 +817,7 @@ test_build_authorized_client(void *arg)
testing_enable_prefilled_rng("\x01", 1);
- hs_desc_build_authorized_client(subcredential,
+ hs_desc_build_authorized_client(&subcredential,
&client_auth_pk, &auth_ephemeral_sk,
descriptor_cookie, desc_client);
diff --git a/src/test/test_hs_dos.c b/src/test/test_hs_dos.c
index f68639e24a..642513efce 100644
--- a/src/test/test_hs_dos.c
+++ b/src/test/test_hs_dos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, 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 feb934d93c..e6b27d7a50 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -757,12 +757,15 @@ 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);
diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c
index 1c694e6040..7867740a1a 100644
--- a/src/test/test_hs_ntor.c
+++ b/src/test/test_hs_ntor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,7 +23,7 @@ test_hs_ntor(void *arg)
{
int retval;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
ed25519_keypair_t service_intro_auth_keypair;
curve25519_keypair_t service_intro_enc_keypair;
@@ -42,7 +42,7 @@ test_hs_ntor(void *arg)
/* Generate fake data for this unittest */
{
/* Generate fake subcredential */
- memset(subcredential, 'Z', DIGEST256_LEN);
+ memset(subcredential.subcred, 'Z', DIGEST256_LEN);
/* service */
curve25519_keypair_generate(&service_intro_enc_keypair, 0);
@@ -57,7 +57,7 @@ test_hs_ntor(void *arg)
hs_ntor_client_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
&service_intro_enc_keypair.pubkey,
&client_ephemeral_enc_keypair,
- subcredential,
+ &subcredential,
&client_hs_ntor_intro_cell_keys);
tt_int_op(retval, OP_EQ, 0);
@@ -66,7 +66,7 @@ test_hs_ntor(void *arg)
hs_ntor_service_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
&service_intro_enc_keypair,
&client_ephemeral_enc_keypair.pubkey,
- subcredential,
+ &subcredential,
&service_hs_ntor_intro_cell_keys);
tt_int_op(retval, OP_EQ, 0);
diff --git a/src/test/test_hs_ntor.sh b/src/test/test_hs_ntor.sh
index 8a0003d44a..ee7141cc9a 100755
--- a/src/test/test_hs_ntor.sh
+++ b/src/test/test_hs_ntor.sh
@@ -3,7 +3,7 @@
exitcode=0
-# Run the python integration test sand return the exitcode of the python
+# Run the python integration tests and return the exitcode of the python
# script. The python script might ask the testsuite to skip it if not all
# python dependencies are covered.
"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/hs_ntor_ref.py" || exitcode=$?
diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c
index 6341b96d84..3acd7ef0bc 100644
--- a/src/test/test_hs_ntor_cl.c
+++ b/src/test/test_hs_ntor_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** This is a wrapper over the little-t-tor HS ntor functions. The wrapper is
@@ -53,7 +53,7 @@ client1(int argc, char **argv)
curve25519_public_key_t intro_enc_pubkey;
ed25519_public_key_t intro_auth_pubkey;
curve25519_keypair_t client_ephemeral_enc_keypair;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys;
@@ -65,7 +65,7 @@ client1(int argc, char **argv)
BASE16(3, intro_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
BASE16(4, client_ephemeral_enc_keypair.seckey.secret_key,
CURVE25519_SECKEY_LEN);
- BASE16(5, subcredential, DIGEST256_LEN);
+ BASE16(5, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey,
@@ -74,7 +74,7 @@ client1(int argc, char **argv)
retval = hs_ntor_client_get_introduce1_keys(&intro_auth_pubkey,
&intro_enc_pubkey,
&client_ephemeral_enc_keypair,
- subcredential,
+ &subcredential,
&hs_ntor_intro_cell_keys);
if (retval < 0) {
goto done;
@@ -106,7 +106,7 @@ server1(int argc, char **argv)
curve25519_keypair_t intro_enc_keypair;
ed25519_public_key_t intro_auth_pubkey;
curve25519_public_key_t client_ephemeral_enc_pubkey;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys;
@@ -119,7 +119,7 @@ server1(int argc, char **argv)
BASE16(2, intro_auth_pubkey.pubkey, ED25519_PUBKEY_LEN);
BASE16(3, intro_enc_keypair.seckey.secret_key, CURVE25519_SECKEY_LEN);
BASE16(4, client_ephemeral_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
- BASE16(5, subcredential, DIGEST256_LEN);
+ BASE16(5, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&intro_enc_keypair.pubkey,
@@ -130,7 +130,7 @@ server1(int argc, char **argv)
retval = hs_ntor_service_get_introduce1_keys(&intro_auth_pubkey,
&intro_enc_keypair,
&client_ephemeral_enc_pubkey,
- subcredential,
+ &subcredential,
&hs_ntor_intro_cell_keys);
if (retval < 0) {
goto done;
@@ -188,7 +188,7 @@ client2(int argc, char **argv)
ed25519_public_key_t intro_auth_pubkey;
curve25519_keypair_t client_ephemeral_enc_keypair;
curve25519_public_key_t service_ephemeral_rend_pubkey;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_rend_cell_keys_t hs_ntor_rend_cell_keys;
@@ -201,7 +201,7 @@ client2(int argc, char **argv)
CURVE25519_SECKEY_LEN);
BASE16(4, intro_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
BASE16(5, service_ephemeral_rend_pubkey.public_key, CURVE25519_PUBKEY_LEN);
- BASE16(6, subcredential, DIGEST256_LEN);
+ BASE16(6, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey,
diff --git a/src/test/test_hs_ob.c b/src/test/test_hs_ob.c
new file mode 100644
index 0000000000..7f40187b5f
--- /dev/null
+++ b/src/test/test_hs_ob.c
@@ -0,0 +1,268 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_ob.c
+ * \brief Test hidden service onion balance functionality.
+ */
+
+#define CONFIG_PRIVATE
+#define HS_SERVICE_PRIVATE
+#define HS_OB_PRIVATE
+
+#include "test/test.h"
+#include "test/test_helpers.h"
+#include "test/log_test_helpers.h"
+
+#include "app/config/config.h"
+#include "feature/hs/hs_config.h"
+#include "feature/hs/hs_ob.h"
+#include "feature/hs/hs_service.h"
+#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/networkstatus_st.h"
+
+static ed25519_keypair_t onion_addr_kp_1;
+static char onion_addr_1[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+static ed25519_keypair_t onion_addr_kp_2;
+static char onion_addr_2[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+static bool config_is_good = true;
+
+static int
+helper_tor_config(const char *conf)
+{
+ int ret = -1;
+ or_options_t *options = helper_parse_options(conf);
+ tt_assert(options);
+ ret = hs_config_service_all(options, 0);
+ done:
+ or_options_free(options);
+ return ret;
+}
+
+static networkstatus_t mock_ns;
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void) now;
+ return &mock_ns;
+}
+
+static char *
+mock_read_file_to_str(const char *filename, int flags, struct stat *stat_out)
+{
+ char *ret = NULL;
+
+ (void) flags;
+ (void) stat_out;
+
+ if (!strcmp(filename, get_fname("hs3" PATH_SEPARATOR "ob_config"))) {
+ if (config_is_good) {
+ tor_asprintf(&ret, "MasterOnionAddress %s.onion\n"
+ "MasterOnionAddress %s.onion\n",
+ onion_addr_1, onion_addr_2);
+ } else {
+ tor_asprintf(&ret, "MasterOnionAddress JUNKJUNKJUNK.onion\n"
+ "UnknownOption BLAH\n");
+ }
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+static void
+test_parse_config_file(void *arg)
+{
+ int ret;
+ char *conf = NULL;
+ const ed25519_public_key_t *pkey;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(read_file_to_str, mock_read_file_to_str);
+
+#define fmt_conf \
+ "HiddenServiceDir %s\n" \
+ "HiddenServicePort 22\n" \
+ "HiddenServiceOnionBalanceInstance 1\n"
+ tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
+#undef fmt_conf
+
+ /* Build the OB frontend onion addresses. */
+ ed25519_keypair_generate(&onion_addr_kp_1, 0);
+ hs_build_address(&onion_addr_kp_1.pubkey, HS_VERSION_THREE, onion_addr_1);
+ ed25519_keypair_generate(&onion_addr_kp_2, 0);
+ hs_build_address(&onion_addr_kp_2.pubkey, HS_VERSION_THREE, onion_addr_2);
+
+ ret = helper_tor_config(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Load the keys for the service. After that, the v3 service should be
+ * registered in the global map and we'll be able to access it. */
+ tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
+ hs_service_load_all_keys();
+ tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+ const hs_service_t *s = get_first_service();
+ tt_assert(s);
+ tt_assert(s->config.ob_master_pubkeys);
+ tt_assert(hs_ob_service_is_instance(s));
+ tt_assert(smartlist_len(s->config.ob_master_pubkeys) == 2);
+
+ /* Test the public keys we've added. */
+ pkey = smartlist_get(s->config.ob_master_pubkeys, 0);
+ tt_mem_op(&onion_addr_kp_1.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
+ pkey = smartlist_get(s->config.ob_master_pubkeys, 1);
+ tt_mem_op(&onion_addr_kp_2.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
+
+ done:
+ hs_free_all();
+
+ UNMOCK(read_file_to_str);
+}
+
+static void
+test_parse_config_file_bad(void *arg)
+{
+ int ret;
+ char *conf = NULL;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(read_file_to_str, mock_read_file_to_str);
+
+ /* Indicate mock_read_file_to_str() to use the bad config. */
+ config_is_good = false;
+
+#define fmt_conf \
+ "HiddenServiceDir %s\n" \
+ "HiddenServicePort 22\n" \
+ "HiddenServiceOnionBalanceInstance 1\n"
+ tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
+#undef fmt_conf
+
+ setup_full_capture_of_logs(LOG_INFO);
+ ret = helper_tor_config(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("OnionBalance: MasterOnionAddress "
+ "JUNKJUNKJUNK.onion is invalid");
+ expect_log_msg_containing("Found unrecognized option \'UnknownOption\'; "
+ "saving it.");
+ teardown_capture_of_logs();
+
+ done:
+ hs_free_all();
+
+ UNMOCK(read_file_to_str);
+}
+
+static void
+test_get_subcredentials(void *arg)
+{
+ int ret;
+ hs_service_t *service = NULL;
+ hs_service_config_t config;
+ hs_subcredential_t *subcreds = NULL;
+
+ (void) arg;
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* Setup consensus with proper time so we can compute the time period. */
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+
+ config.ob_master_pubkeys = smartlist_new();
+ tt_assert(config.ob_master_pubkeys);
+
+ /* Set up an instance */
+ service = tor_malloc_zero(sizeof(hs_service_t));
+ service->config = config;
+ /* Setup the service descriptors */
+ service->desc_current = service_descriptor_new();
+ service->desc_next = service_descriptor_new();
+
+ /* First try to compute subcredentials but with no OB keys. Make sure that
+ * subcreds get NULLed. To do this check we first poison subcreds. */
+ subcreds = (void*)999;
+ tt_ptr_op(subcreds, OP_NE, NULL);
+ size_t num = compute_subcredentials(service, &subcreds);
+ tt_ptr_op(subcreds, OP_EQ, NULL);
+
+ /* Generate a keypair to add to the OB keys list. */
+ ed25519_keypair_generate(&onion_addr_kp_1, 0);
+ smartlist_add(config.ob_master_pubkeys, &onion_addr_kp_1.pubkey);
+
+ /* Set up the instance subcredentials */
+ char current_subcred[SUBCRED_LEN];
+ char next_subcred[SUBCRED_LEN];
+ memset(current_subcred, 'C', SUBCRED_LEN);
+ memset(next_subcred, 'N', SUBCRED_LEN);
+ memcpy(service->desc_current->desc->subcredential.subcred, current_subcred,
+ SUBCRED_LEN);
+ memcpy(service->desc_next->desc->subcredential.subcred, next_subcred,
+ SUBCRED_LEN);
+
+ /* See that subcreds are computed properly */
+ num = compute_subcredentials(service, &subcreds);
+ /* 5 subcredentials: 3 for the frontend, 2 for the instance */
+ tt_uint_op(num, OP_EQ, 5);
+ tt_ptr_op(subcreds, OP_NE, NULL);
+
+ /* Validate the subcredentials we just got. We'll build them oursevles with
+ * the right time period steps and compare. */
+ const uint64_t tp = hs_get_time_period_num(0);
+ const int steps[3] = {0, -1, 1};
+
+ unsigned int i;
+ for (i = 0; i < 3; i++) {
+ hs_subcredential_t subcredential;
+ ed25519_public_key_t blinded_pubkey;
+ hs_build_blinded_pubkey(&onion_addr_kp_1.pubkey, NULL, 0, tp + steps[i],
+ &blinded_pubkey);
+ hs_get_subcredential(&onion_addr_kp_1.pubkey, &blinded_pubkey,
+ &subcredential);
+ tt_mem_op(subcreds[i].subcred, OP_EQ, subcredential.subcred,
+ SUBCRED_LEN);
+ }
+
+ tt_mem_op(subcreds[i++].subcred, OP_EQ, current_subcred, SUBCRED_LEN);
+ tt_mem_op(subcreds[i++].subcred, OP_EQ, next_subcred, SUBCRED_LEN);
+
+ done:
+ tor_free(subcreds);
+
+ smartlist_free(config.ob_master_pubkeys);
+ if (service) {
+ memset(&service->config, 0, sizeof(hs_service_config_t));
+ hs_service_free(service);
+ }
+
+ UNMOCK(networkstatus_get_live_consensus);
+}
+
+struct testcase_t hs_ob_tests[] = {
+ { "parse_config_file", test_parse_config_file, TT_FORK,
+ NULL, NULL },
+ { "parse_config_file_bad", test_parse_config_file_bad, TT_FORK,
+ NULL, NULL },
+
+ { "get_subcredentials", test_get_subcredentials, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index 66194cee3d..80383baff8 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,7 +19,7 @@
#define MAINLOOP_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define STATEFILE_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define HS_CLIENT_PRIVATE
#define CRYPT_PATH_PRIVATE
@@ -44,13 +44,15 @@
#include "core/or/versions.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/shared_random_state.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/hs/hs_circuit.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_ident.h"
+#include "feature/hs/hs_ob.h"
+#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_intropoint.h"
#include "feature/hs/hs_service.h"
#include "feature/nodelist/networkstatus.h"
@@ -87,6 +89,13 @@ mock_networkstatus_get_live_consensus(time_t now)
return &mock_ns;
}
+static networkstatus_t *
+mock_networkstatus_get_live_consensus_null(time_t now)
+{
+ (void) now;
+ return NULL;
+}
+
static or_state_t *dummy_state = NULL;
/* Mock function to get fake or state (used for rev counters) */
@@ -109,6 +118,9 @@ mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
return;
}
+static size_t relay_payload_len;
+static char relay_payload[RELAY_PAYLOAD_SIZE];
+
static int
mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
uint8_t relay_command, const char *payload,
@@ -124,6 +136,24 @@ mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
(void) cpath_layer;
(void) filename;
(void) lineno;
+
+ memcpy(relay_payload, payload, payload_len);
+ relay_payload_len = payload_len;
+
+ return 0;
+}
+
+static unsigned int num_intro_points = 0;
+static unsigned int
+mock_count_desc_circuit_established(const hs_service_descriptor_t *desc)
+{
+ (void) desc;
+ return num_intro_points;
+}
+
+static int
+mock_router_have_minimum_dir_info_false(void)
+{
return 0;
}
@@ -183,9 +213,8 @@ test_e2e_rend_circuit_setup(void *arg)
/* Setup the circuit: do the ntor key exchange */
{
uint8_t ntor_key_seed[DIGEST256_LEN] = {2};
- retval = hs_circuit_setup_e2e_rend_circ(or_circ,
- ntor_key_seed, sizeof(ntor_key_seed),
- 1);
+ retval = hs_circuit_setup_e2e_rend_circ(or_circ, ntor_key_seed,
+ sizeof(ntor_key_seed), 1);
tt_int_op(retval, OP_EQ, 0);
}
@@ -194,11 +223,9 @@ test_e2e_rend_circuit_setup(void *arg)
tt_int_op(retval, OP_EQ, 1);
/* Check the digest algo */
- tt_int_op(
- crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_int_op(
- crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
OP_EQ, DIGEST_SHA3_256);
tt_assert(or_circ->cpath->pvt_crypto.f_crypto);
tt_assert(or_circ->cpath->pvt_crypto.b_crypto);
@@ -1013,7 +1040,6 @@ test_intro_established(void *arg)
/* Send an empty payload. INTRO_ESTABLISHED cells are basically zeroes. */
ret = hs_service_receive_intro_established(circ, payload, sizeof(payload));
tt_int_op(ret, OP_EQ, 0);
- tt_u64_op(ip->circuit_established, OP_EQ, 1);
tt_int_op(TO_CIRCUIT(circ)->purpose, OP_EQ, CIRCUIT_PURPOSE_S_INTRO);
done:
@@ -1164,7 +1190,7 @@ test_closing_intro_circs(void *arg)
/** Test sending and receiving introduce2 cells */
static void
-test_introduce2(void *arg)
+test_bad_introduce2(void *arg)
{
int ret;
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
@@ -1296,18 +1322,11 @@ test_service_event(void *arg)
* descriptor map so we can retry it. */
ip = helper_create_service_ip();
service_intro_point_add(service->desc_current->intro_points.map, ip);
- ip->circuit_established = 1; /* We'll test that, it MUST be 0 after. */
- run_housekeeping_event(now);
- tt_int_op(digest256map_size(service->desc_current->intro_points.map),
- OP_EQ, 1);
- /* No removal if we have an established circuit after retries. */
- ip->circuit_retries = MAX_INTRO_POINT_CIRCUIT_RETRIES + 1;
run_housekeeping_event(now);
tt_int_op(digest256map_size(service->desc_current->intro_points.map),
OP_EQ, 1);
/* Remove the IP object at once for the next test. */
ip->circuit_retries = MAX_INTRO_POINT_CIRCUIT_RETRIES + 1;
- ip->circuit_established = 0;
run_housekeeping_event(now);
tt_int_op(digest256map_size(service->desc_current->intro_points.map),
OP_EQ, 0);
@@ -1367,7 +1386,7 @@ test_rotate_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -1408,7 +1427,7 @@ test_rotate_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 27 Oct 1985 02:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -1476,7 +1495,7 @@ test_build_update_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
@@ -1707,7 +1726,7 @@ test_build_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
/* Generate a valid number of fake auth clients when a client authorization
* is disabled. */
@@ -1808,7 +1827,7 @@ test_upload_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -2180,6 +2199,490 @@ test_export_client_circuit_id(void *arg)
tor_free(cp2);
}
+static smartlist_t *
+mock_node_get_link_specifier_smartlist(const node_t *node, bool direct_conn)
+{
+ (void) node;
+ (void) direct_conn;
+
+ smartlist_t *lspecs = smartlist_new();
+ link_specifier_t *ls_legacy = link_specifier_new();
+ smartlist_add(lspecs, ls_legacy);
+
+ return lspecs;
+}
+
+static node_t *fake_node = NULL;
+
+static const node_t *
+mock_build_state_get_exit_node(cpath_build_state_t *state)
+{
+ (void) state;
+
+ if (!fake_node) {
+ curve25519_secret_key_t seckey;
+ curve25519_secret_key_generate(&seckey, 0);
+
+ fake_node = tor_malloc_zero(sizeof(node_t));
+ fake_node->ri = tor_malloc_zero(sizeof(routerinfo_t));
+ fake_node->ri->onion_curve25519_pkey =
+ tor_malloc_zero(sizeof(curve25519_public_key_t));
+ curve25519_public_key_generate(fake_node->ri->onion_curve25519_pkey,
+ &seckey);
+ }
+
+ return fake_node;
+}
+
+static void
+mock_launch_rendezvous_point_circuit(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ const hs_cell_introduce2_data_t *data)
+{
+ (void) service;
+ (void) ip;
+ (void) data;
+ return;
+}
+
+/**
+ * Test that INTRO2 cells are handled well by onion services in the normal
+ * case and also when onionbalance is enabled.
+ */
+static void
+test_intro2_handling(void *arg)
+{
+ (void)arg;
+
+ MOCK(build_state_get_exit_node, mock_build_state_get_exit_node);
+ MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
+ MOCK(node_get_link_specifier_smartlist,
+ mock_node_get_link_specifier_smartlist);
+ MOCK(launch_rendezvous_point_circuit, mock_launch_rendezvous_point_circuit);
+
+ memset(relay_payload, 0, sizeof(relay_payload));
+
+ int retval;
+ time_t now = 0101010101;
+ update_approx_time(now);
+
+ /** OK this is the play:
+ *
+ * In Act I, we have a standalone onion service X (without onionbalance
+ * enabled). We test that X can properly handle INTRO2 cells sent by a
+ * client Alice.
+ *
+ * In Act II, we create an onionbalance setup with frontend being Z which
+ * includes instances X and Y. We then setup onionbalance on X and test that
+ * Alice who addresses Z can communicate with X through INTRO2 cells.
+ *
+ * In Act III, we test that Alice can also communicate with X
+ * directly even tho onionbalance is enabled.
+ *
+ * And finally in Act IV, we check various cases where the INTRO2 cell
+ * should not go through because the subcredentials don't line up
+ * (e.g. Alice sends INTRO2 to X using Y's subcredential).
+ */
+
+ /** Let's start with some setup! Create the instances and the frontend
+ service, create Alice, etc: */
+
+ /* Create instance X */
+ hs_service_t x_service;
+ memset(&x_service, 0, sizeof(hs_service_t));
+ /* Disable onionbalance */
+ x_service.config.ob_master_pubkeys = NULL;
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0,0);
+
+ /* Create subcredential for x: */
+ ed25519_keypair_t x_identity_keypair;
+ hs_subcredential_t x_subcred;
+ ed25519_keypair_generate(&x_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&x_identity_keypair,
+ &x_subcred);
+
+ /* Create the x instance's intro point */
+ hs_service_intro_point_t *x_ip = NULL;
+ {
+ curve25519_secret_key_t seckey;
+ curve25519_public_key_t pkey;
+ curve25519_secret_key_generate(&seckey, 0);
+ curve25519_public_key_generate(&pkey, &seckey);
+
+ node_t intro_node;
+ memset(&intro_node, 0, sizeof(intro_node));
+ routerinfo_t ri;
+ memset(&ri, 0, sizeof(routerinfo_t));
+ ri.onion_curve25519_pkey = &pkey;
+ intro_node.ri = &ri;
+
+ x_ip = service_intro_point_new(&intro_node);
+ }
+
+ /* Create z frontend's subcredential */
+ ed25519_keypair_t z_identity_keypair;
+ hs_subcredential_t z_subcred;
+ ed25519_keypair_generate(&z_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&z_identity_keypair,
+ &z_subcred);
+
+ /* Create y instance's subcredential */
+ ed25519_keypair_t y_identity_keypair;
+ hs_subcredential_t y_subcred;
+ ed25519_keypair_generate(&y_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&y_identity_keypair,
+ &y_subcred);
+
+ /* Create Alice's intro point */
+ hs_desc_intro_point_t *alice_ip;
+ ed25519_keypair_t signing_kp;
+ ed25519_keypair_generate(&signing_kp, 0);
+ alice_ip = hs_helper_build_intro_point(&signing_kp, now, "1.2.3.4", 0,
+ &x_ip->auth_key_kp,
+ &x_ip->enc_key_kp);
+
+ /* Create Alice's intro and rend circuits */
+ origin_circuit_t *intro_circ = origin_circuit_new();
+ intro_circ->cpath = tor_malloc_zero(sizeof(crypt_path_t));
+ intro_circ->cpath->prev = intro_circ->cpath;
+ intro_circ->hs_ident = tor_malloc_zero(sizeof(*intro_circ->hs_ident));
+ origin_circuit_t rend_circ;
+ 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);
+
+ /* ************************************************************ */
+
+ /* Act I:
+ *
+ * Where Alice connects to X without onionbalance in the picture */
+
+ /* Create INTRODUCE1 */
+ tt_assert(fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &x_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Handle the cell */
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload,relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* ************************************************************ */
+
+ /* Act II:
+ *
+ * We now create an onionbalance setup with Z being the frontend and X and Y
+ * being the backend instances. Make sure that Alice can talk with the
+ * backend instance X even tho she thinks she is talking to the frontend Z.
+ */
+
+ /* Now configure the X instance to do onionbalance with Z as the frontend */
+ x_service.config.ob_master_pubkeys = smartlist_new();
+ smartlist_add(x_service.config.ob_master_pubkeys,
+ &z_identity_keypair.pubkey);
+
+ /* Create descriptors for x and load next descriptor with the x's
+ * subcredential so that it can accept connections for itself. */
+ x_service.desc_current = service_descriptor_new();
+ memset(x_service.desc_current->desc->subcredential.subcred, 'C',SUBCRED_LEN);
+ x_service.desc_next = service_descriptor_new();
+ memcpy(&x_service.desc_next->desc->subcredential, &x_subcred, SUBCRED_LEN);
+
+ /* Refresh OB keys */
+ hs_ob_refresh_keys(&x_service);
+
+ /* Create INTRODUCE1 from Alice to X through Z */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &z_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Deliver INTRODUCE1 to X even tho it carries Z's subcredential */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &z_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ /* ************************************************************ */
+
+ /* Act III:
+ *
+ * Now send a direct INTRODUCE cell from Alice to X using X's subcredential
+ * and check that it succeeds even with onionbalance enabled.
+ */
+
+ /* Refresh OB keys (just to check for memleaks) */
+ hs_ob_refresh_keys(&x_service);
+
+ /* Create INTRODUCE1 from Alice to X using X's subcred. */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &x_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Send INTRODUCE1 to X with X's subcredential (should succeed) */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* ************************************************************ */
+
+ /* Act IV:
+ *
+ * Test cases where the INTRO2 cell should not be able to decode.
+ */
+
+ /* Try sending the exact same INTRODUCE2 cell again and see that the intro
+ * point replay cache triggers: */
+ setup_full_capture_of_logs(LOG_WARN);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+ expect_log_msg_containing("with the same ENCRYPTED section");
+ teardown_capture_of_logs();
+
+ /* Now cleanup the intro point replay cache but not the service replay cache
+ and see that this one triggers this time. */
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+ expect_log_msg_containing("with same REND_COOKIE");
+ teardown_capture_of_logs();
+
+ /* Now just to make sure cleanup both replay caches and make sure that the
+ cell gets through */
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* As a final thing, create an INTRODUCE1 cell from Alice to X using Y's
+ * subcred (should fail since Y is just another instance and not the frontend
+ * service!) */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &y_subcred);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check that the payload was written successfully */
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &y_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ /* Start cleaning up X */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ smartlist_free(x_service.config.ob_master_pubkeys);
+ tor_free(x_service.state.ob_subcreds);
+ service_descriptor_free(x_service.desc_current);
+ service_descriptor_free(x_service.desc_next);
+ service_intro_point_free(x_ip);
+
+ /* Clean up Alice */
+ hs_desc_intro_point_free(alice_ip);
+ tor_free(rend_circ.hs_ident);
+
+ if (fake_node) {
+ tor_free(fake_node->ri->onion_curve25519_pkey);
+ tor_free(fake_node->ri);
+ tor_free(fake_node);
+ }
+
+ UNMOCK(build_state_get_exit_node);
+ UNMOCK(relay_send_command_from_edge_);
+ UNMOCK(node_get_link_specifier_smartlist);
+ UNMOCK(launch_rendezvous_point_circuit);
+}
+
+static void
+test_cannot_upload_descriptors(void *arg)
+{
+ int ret;
+ time_t now;
+ hs_service_t *service;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ dummy_state = or_state_new();
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
+
+ update_approx_time(mock_ns.valid_after + 1);
+ now = mock_ns.valid_after + 1;
+
+ /* Create a service with no descriptor. It's added to the global map. */
+ service = hs_service_new(get_options());
+ tt_assert(service);
+ service->config.version = HS_VERSION_THREE;
+ ed25519_secret_key_generate(&service->keys.identity_sk, 0);
+ ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk);
+ /* Register service to global map. */
+ ret = register_service(get_hs_service_map(), service);
+ tt_int_op(ret, OP_EQ, 0);
+ /* But first, build our descriptor. */
+ build_all_descriptors(now);
+
+ /* 1. Testing missing intro points reason. */
+ {
+ digest256map_t *cur = service->desc_current->intro_points.map;
+ digest256map_t *tmp = digest256map_new();
+ service->desc_current->intro_points.map = tmp;
+ service->desc_current->missing_intro_points = 1;
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ digest256map_free(tmp, tor_free_);
+ service->desc_current->intro_points.map = cur;
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Missing intro points");
+ teardown_capture_of_logs();
+ /* Reset. */
+ service->desc_current->missing_intro_points = 0;
+ }
+
+ /* 2. Testing non established intro points. */
+ {
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Intro circuits aren't yet all established (0/3).");
+ teardown_capture_of_logs();
+ }
+
+ /* We need to pass the established circuit tests and thus from now on, we
+ * MOCK this to return 3 intro points. */
+ MOCK(count_desc_circuit_established, mock_count_desc_circuit_established);
+ num_intro_points = 3;
+
+ /* 3. Testing non established intro points. */
+ {
+ service->desc_current->next_upload_time = now + 1000;
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Next upload time is");
+ teardown_capture_of_logs();
+ /* Reset. */
+ service->desc_current->next_upload_time = 0;
+ }
+
+ /* 4. Testing missing live consensus. */
+ {
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus_null);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "No live consensus");
+ teardown_capture_of_logs();
+ /* Reset. */
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+ }
+
+ /* 5. Test missing minimum directory information. */
+ {
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_false);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Not enough directory information");
+ teardown_capture_of_logs();
+
+ /* Running it again shouldn't trigger anything due to rate limitation. */
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_no_log_entry();
+ teardown_capture_of_logs();
+ UNMOCK(router_have_minimum_dir_info);
+ }
+
+ /* Increase time and redo test (5) in order to test the rate limiting. */
+ update_approx_time(mock_ns.valid_after + 61);
+ {
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_false);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Not enough directory information");
+ teardown_capture_of_logs();
+ UNMOCK(router_have_minimum_dir_info);
+ }
+
+ done:
+ hs_free_all();
+ UNMOCK(count_desc_circuit_established);
+ UNMOCK(networkstatus_get_live_consensus);
+ UNMOCK(get_or_state);
+}
+
struct testcase_t hs_service_tests[] = {
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
NULL, NULL },
@@ -2205,7 +2708,7 @@ struct testcase_t hs_service_tests[] = {
NULL, NULL },
{ "rdv_circuit_opened", test_rdv_circuit_opened, TT_FORK,
NULL, NULL },
- { "introduce2", test_introduce2, TT_FORK,
+ { "bad_introduce2", test_bad_introduce2, TT_FORK,
NULL, NULL },
{ "service_event", test_service_event, TT_FORK,
NULL, NULL },
@@ -2217,12 +2720,15 @@ struct testcase_t hs_service_tests[] = {
NULL, NULL },
{ "upload_descriptors", test_upload_descriptors, TT_FORK,
NULL, NULL },
+ { "cannot_upload_descriptors", test_cannot_upload_descriptors, TT_FORK,
+ NULL, NULL },
{ "rendezvous1_parsing", test_rendezvous1_parsing, TT_FORK,
NULL, NULL },
{ "authorized_client_config_equal", test_authorized_client_config_equal,
TT_FORK, NULL, NULL },
{ "export_client_circuit_id", test_export_client_circuit_id, TT_FORK,
NULL, NULL },
+ { "intro2_handling", test_intro2_handling, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
index 104e973b1f..0ae78496b2 100644
--- a/src/test/test_introduce.c
+++ b/src/test/test_introduce.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh
index 54abb4a2fa..2238f7aa78 100755
--- a/src/test/test_key_expiration.sh
+++ b/src/test/test_key_expiration.sh
@@ -6,6 +6,20 @@
umask 077
set -e
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then
if [ "$TESTING_TOR_BINARY" = "" ] ; then
echo "Usage: ${0} PATH_TO_TOR [case-number]"
@@ -21,11 +35,21 @@ if test "$UNAME_OS" = 'CYGWIN' || \
exit 77
fi
+# find the tor binary
if [ $# -ge 1 ]; then
TOR_BINARY="${1}"
shift
else
- TOR_BINARY="${TESTING_TOR_BINARY}"
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "$TOR_BINARY" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
fi
if [ $# -ge 1 ]; then
diff --git a/src/test/test_keygen.sh b/src/test/test_keygen.sh
index cbdfd1909c..6812f8883d 100755
--- a/src/test/test_keygen.sh
+++ b/src/test/test_keygen.sh
@@ -6,6 +6,20 @@
umask 077
set -e
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then
if [ "$TESTING_TOR_BINARY" = "" ] ; then
echo "Usage: ${0} PATH_TO_TOR [case-number]"
@@ -21,14 +35,22 @@ if test "$UNAME_OS" = 'CYGWIN' || \
exit 77
fi
+# find the tor binary
if [ $# -ge 1 ]; then
TOR_BINARY="${1}"
shift
else
- TOR_BINARY="${TESTING_TOR_BINARY}"
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
fi
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+if "$TOR_BINARY" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
+fi
if [ $# -ge 1 ]; then
dflt=0
diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c
index e7beef8609..ff6397f8c7 100644
--- a/src/test/test_keypin.c
+++ b/src/test/test_keypin.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, 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 5e78e1ce4d..1566b349ed 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -1,11 +1,11 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CHANNELTLS_PRIVATE
#define CONNECTION_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define TORTLS_PRIVATE
#include "core/or/or.h"
@@ -18,6 +18,7 @@
#include "feature/relay/routerkeys.h"
#include "core/or/scheduler.h"
#include "feature/nodelist/torcert.h"
+#include "feature/relay/relay_handshake.h"
#include "core/or/or_connection_st.h"
#include "core/or/or_handshake_certs_st.h"
@@ -325,7 +326,7 @@ test_link_handshake_certs_ok(void *arg)
crypto_pk_free(key2);
}
-typedef struct certs_data_s {
+typedef struct certs_data_t {
int is_ed;
int is_link_cert;
or_connection_t *c;
@@ -972,7 +973,7 @@ test_link_handshake_send_authchallenge(void *arg)
crypto_pk_free(rsa1);
}
-typedef struct authchallenge_data_s {
+typedef struct authchallenge_data_t {
or_connection_t *c;
channel_tls_t *chan;
var_cell_t *cell;
@@ -1171,7 +1172,7 @@ mock_set_circid_type(channel_t *chan,
(void) consider_identity;
}
-typedef struct authenticate_data_s {
+typedef struct authenticate_data_t {
int is_ed;
or_connection_t *c1, *c2;
channel_tls_t *chan2;
@@ -1492,6 +1493,7 @@ AUTHENTICATE_FAIL(missing_ed_auth,
"authentication certificate";
})
+#ifndef COCCI
#define TEST_RSA(name, flags) \
{ #name , test_link_handshake_ ## name, (flags), \
&passthrough_setup, (void*)"RSA" }
@@ -1527,6 +1529,7 @@ AUTHENTICATE_FAIL(missing_ed_auth,
#define TEST_AUTHENTICATE_ED(name) \
{ "authenticate/" #name "_ed25519" , test_link_handshake_auth_ ## name, \
TT_FORK, &setup_authenticate, (void*)3 }
+#endif /* !defined(COCCI) */
struct testcase_t link_handshake_tests[] = {
TEST_RSA(certs_ok, TT_FORK),
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 203ce64e32..e09f7a21cd 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, 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 ed6b8a9b66..c4e60d9da5 100644
--- a/src/test/test_mainloop.c
+++ b/src/test/test_mainloop.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,9 +13,13 @@
#include "test/test.h"
#include "test/log_test_helpers.h"
+#include "lib/confmgt/confmgt.h"
+
#include "core/or/or.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
+#include "core/mainloop/mainloop_state_st.h"
+#include "core/mainloop/mainloop_sys.h"
#include "core/mainloop/netstatus.h"
#include "feature/hs/hs_service.h"
@@ -24,6 +28,8 @@
#include "app/config/statefile.h"
#include "app/config/or_state_st.h"
+#include "app/main/subsysmgr.h"
+
static const uint64_t BILLION = 1000000000;
static void
@@ -287,7 +293,13 @@ static void
test_mainloop_dormant_load_state(void *arg)
{
(void)arg;
- or_state_t *state = or_state_new();
+ or_state_t *or_state = or_state_new();
+ mainloop_state_t *state;
+ {
+ int idx = subsystems_get_state_idx(&sys_mainloop);
+ tor_assert(idx >= 0);
+ state = config_mgr_get_obj_mutable(get_state_mgr(), or_state, idx);
+ }
const time_t start = 1543956575;
reset_user_activity(0);
@@ -326,14 +338,14 @@ test_mainloop_dormant_load_state(void *arg)
tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
done:
- or_state_free(state);
+ or_state_free(or_state);
}
static void
test_mainloop_dormant_save_state(void *arg)
{
(void)arg;
- or_state_t *state = or_state_new();
+ mainloop_state_t *state = tor_malloc_zero(sizeof(mainloop_state_t));
const time_t start = 1543956575;
// Can we save a non-dormant state correctly?
@@ -352,7 +364,7 @@ test_mainloop_dormant_save_state(void *arg)
tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 0);
done:
- or_state_free(state);
+ tor_free(state);
}
#define MAINLOOP_TEST(name) \
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 804e6c546a..f89025aa6c 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -491,7 +491,7 @@ test_md_generate(void *arg)
}
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-DISABLE_GCC_WARNING(overlength-strings)
+DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
* at large. */
#endif
@@ -686,7 +686,7 @@ static const char MD_PARSE_TEST_DATA[] =
"id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
;
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-ENABLE_GCC_WARNING(overlength-strings)
+ENABLE_GCC_WARNING("-Woverlength-strings")
#endif
/** More tests for parsing different kinds of microdescriptors, and getting
diff --git a/src/test/test_namemap.c b/src/test/test_namemap.c
index df77d4e2de..e93d3fbc3c 100644
--- a/src/test/test_namemap.c
+++ b/src/test/test_namemap.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 27d276d42f..93892978dc 100644
--- a/src/test/test_netinfo.c
+++ b/src/test/test_netinfo.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, 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 b8ca56bb81..fbbbf0a99f 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -7,6 +7,7 @@
**/
#define NODELIST_PRIVATE
+#define NETWORKSTATUS_PRIVATE
#include "core/or/or.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -17,6 +18,8 @@
#include "feature/nodelist/torcert.h"
#include "core/or/extend_info_st.h"
+#include "feature/dirauth/dirvote.h"
+#include "feature/nodelist/fmt_routerstatus.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/node_st.h"
@@ -1246,6 +1249,167 @@ test_nodelist_router_get_verbose_nickname(void *arg)
return;
}
+static void
+test_nodelist_routerstatus_has_visibly_changed(void *arg)
+{
+ (void)arg;
+ routerstatus_t rs_orig, rs;
+ char *fmt_orig = NULL, *fmt = NULL;
+ memset(&rs_orig, 0, sizeof(rs_orig));
+ strlcpy(rs_orig.nickname, "friendly", sizeof(rs_orig.nickname));
+ memcpy(rs_orig.identity_digest, "abcdefghijklmnopqrst", 20);
+ memcpy(rs_orig.descriptor_digest, "abcdefghijklmnopqrst", 20);
+ rs_orig.addr = 0x7f000001;
+ rs_orig.or_port = 3;
+ rs_orig.published_on = time(NULL);
+ rs_orig.has_bandwidth = 1;
+ rs_orig.bandwidth_kb = 20;
+
+#define COPY() memcpy(&rs, &rs_orig, sizeof(rs))
+#define FORMAT() \
+ STMT_BEGIN \
+ tor_free(fmt_orig); \
+ tor_free(fmt); \
+ fmt_orig = routerstatus_format_entry(&rs_orig, NULL, NULL, \
+ NS_CONTROL_PORT, \
+ NULL); \
+ fmt = routerstatus_format_entry(&rs, NULL, NULL, NS_CONTROL_PORT, \
+ NULL); \
+ tt_assert(fmt_orig); \
+ tt_assert(fmt); \
+ STMT_END
+#define ASSERT_SAME() \
+ STMT_BEGIN \
+ tt_assert(! routerstatus_has_visibly_changed(&rs_orig, &rs)); \
+ FORMAT(); \
+ tt_str_op(fmt_orig, OP_EQ, fmt); \
+ COPY(); \
+ STMT_END
+#define ASSERT_CHANGED() \
+ STMT_BEGIN \
+ tt_assert(routerstatus_has_visibly_changed(&rs_orig, &rs)); \
+ FORMAT(); \
+ tt_str_op(fmt_orig, OP_NE, fmt); \
+ COPY(); \
+ STMT_END
+#define ASSERT_CHANGED_NO_FORMAT() \
+ STMT_BEGIN \
+ tt_assert(routerstatus_has_visibly_changed(&rs_orig, &rs)); \
+ COPY(); \
+ STMT_END
+
+ COPY();
+ ASSERT_SAME();
+
+ rs.addr = 0x7f000002;
+ ASSERT_CHANGED();
+
+ strlcpy(rs.descriptor_digest, "hello world", sizeof(rs.descriptor_digest));
+ ASSERT_CHANGED();
+
+ strlcpy(rs.nickname, "fr1end1y", sizeof(rs.nickname));
+ ASSERT_CHANGED();
+
+ rs.published_on += 3600;
+ ASSERT_CHANGED();
+
+ rs.or_port = 55;
+ ASSERT_CHANGED();
+
+ rs.dir_port = 9999;
+ ASSERT_CHANGED();
+
+ tor_addr_parse(&rs.ipv6_addr, "1234::56");
+ ASSERT_CHANGED();
+
+ tor_addr_parse(&rs_orig.ipv6_addr, "1234::56");
+ rs_orig.ipv6_orport = 99;
+ COPY();
+ rs.ipv6_orport = 22;
+ ASSERT_CHANGED();
+
+ rs.is_authority = 1;
+ ASSERT_CHANGED();
+
+ rs.is_exit = 1;
+ ASSERT_CHANGED();
+
+ rs.is_stable = 1;
+ ASSERT_CHANGED();
+
+ rs.is_fast = 1;
+ ASSERT_CHANGED();
+
+ rs.is_flagged_running = 1;
+ ASSERT_CHANGED();
+
+ // This option is obsolete and not actually formatted.
+ rs.is_named = 1;
+ ASSERT_CHANGED_NO_FORMAT();
+
+ // This option is obsolete and not actually formatted.
+ rs.is_unnamed = 1;
+ ASSERT_CHANGED_NO_FORMAT();
+
+ rs.is_valid = 1;
+ ASSERT_CHANGED();
+
+ rs.is_possible_guard = 1;
+ ASSERT_CHANGED();
+
+ rs.is_bad_exit = 1;
+ ASSERT_CHANGED();
+
+ rs.is_hs_dir = 1;
+ ASSERT_CHANGED();
+
+ rs.is_v2_dir = 1;
+ ASSERT_CHANGED();
+
+ rs.is_staledesc = 1;
+ ASSERT_CHANGED();
+
+ // Setting this to zero crashes us with an assertion failure in
+ // routerstatus_format_entry() if we don't have a descriptor.
+ rs.has_bandwidth = 0;
+ ASSERT_CHANGED_NO_FORMAT();
+
+ // Does not actually matter; not visible to controller.
+ rs.has_exitsummary = 1;
+ ASSERT_SAME();
+
+ // Does not actually matter; not visible to the controller.
+ rs.bw_is_unmeasured = 1;
+ ASSERT_SAME();
+
+ rs.bandwidth_kb = 2000;
+ ASSERT_CHANGED();
+
+ // not visible to the controller.
+ rs.has_guardfraction = 1;
+ rs.guardfraction_percentage = 22;
+ ASSERT_SAME();
+
+ // not visible to the controller.
+ rs_orig.has_guardfraction = 1;
+ rs_orig.guardfraction_percentage = 20;
+ COPY();
+ rs.guardfraction_percentage = 25;
+ ASSERT_SAME();
+
+ // not visible to the controller.
+ rs.exitsummary = (char*)"accept 1-2";
+ ASSERT_SAME();
+
+ done:
+#undef COPY
+#undef ASSERT_SAME
+#undef ASSERT_CHANGED
+ tor_free(fmt_orig);
+ tor_free(fmt);
+ return;
+}
+
#define NODE(name, flags) \
{ #name, test_nodelist_##name, (flags), NULL, NULL }
@@ -1266,5 +1430,6 @@ struct testcase_t nodelist_tests[] = {
NODE(routerstatus_describe, 0),
NODE(extend_info_describe, 0),
NODE(router_get_verbose_nickname, 0),
+ NODE(routerstatus_has_visibly_changed, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c
index 68b6927f56..a1508d0afc 100644
--- a/src/test/test_ntor_cl.c
+++ b/src/test/test_ntor_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_oom.c b/src/test/test_oom.c
index da6b2ee14d..51c237ec2e 100644
--- a/src/test/test_oom.c
+++ b/src/test/test_oom.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, 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 815feda7ce..f8c712a6b6 100644
--- a/src/test/test_oos.c
+++ b/src/test/test_oos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, 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 a2641425fe..8e0d19f126 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -1,20 +1,29 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
+#define RELAY_CONFIG_PRIVATE
+#define LOG_PRIVATE
+#define ROUTERSET_PRIVATE
#include "core/or/or.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "app/config/config.h"
+#include "feature/dirauth/dirauth_config.h"
+#include "feature/dirauth/dirauth_options_st.h"
+#include "feature/dirauth/dirauth_sys.h"
+#include "feature/relay/relay_config.h"
#include "test/test.h"
#include "lib/geoip/geoip.h"
-#define ROUTERSET_PRIVATE
#include "feature/nodelist/routerset.h"
#include "core/mainloop/mainloop.h"
+#include "app/main/subsysmgr.h"
#include "test/log_test_helpers.h"
#include "test/resolve_test_helpers.h"
+#include "lib/crypt_ops/crypto_options_st.h"
+#include "lib/crypt_ops/crypto_sys.h"
#include "lib/sandbox/sandbox.h"
#include "lib/memarea/memarea.h"
@@ -22,14 +31,13 @@
#include "lib/encoding/confline.h"
#include "core/or/policies.h"
#include "test/test_helpers.h"
+#include "test/opts_test_helpers.h"
#include "lib/net/resolve.h"
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
-#define NS_MODULE test_options
-
typedef struct {
int severity;
log_domain_mask_t domain;
@@ -91,16 +99,57 @@ clear_log_messages(void)
messages = NULL;
}
-#define setup_options(opt,dflt) \
+#define setup_options(opt) \
do { \
opt = options_new(); \
opt->command = CMD_RUN_TOR; \
options_init(opt); \
- \
- dflt = config_dup(get_options_mgr(), opt); \
- clear_log_messages(); \
} while (0)
+#ifdef COCCI
+
+#define ENABLE_AUTHORITY_MIN ""
+#define ENABLE_AUTHORITY_V3_MIN ""
+#define ENABLE_AUTHORITY_BRIDGE_MIN ""
+#define AUTHORITY_OPT_REQ_ ""
+#define ENABLE_AUTHORITY ""
+#define ENABLE_AUTHORITY_V3 ""
+#define ENABLE_AUTHORITY_BRIDGE ""
+
+#else /* !defined(COCCI) */
+
+#define ENABLE_AUTHORITY_MIN \
+ "AuthoritativeDirectory 1\n"
+
+#define ENABLE_AUTHORITY_V3_MIN \
+ ENABLE_AUTHORITY_MIN \
+ "V3AuthoritativeDir 1\n"
+
+#define ENABLE_AUTHORITY_BRIDGE_MIN \
+ ENABLE_AUTHORITY_MIN \
+ "BridgeAuthoritativeDir 1\n"
+
+#define AUTHORITY_OPT_REQ_ \
+ "Address 192.0.2.111\n" \
+ "ContactInfo a@example.org\n" \
+ "DirPort 1025\n" \
+ "ORPort 1026\n"
+
+/* Not actually valid: requires v3 / bridge */
+#define ENABLE_AUTHORITY \
+ ENABLE_AUTHORITY_MIN \
+ AUTHORITY_OPT_REQ_
+
+#define ENABLE_AUTHORITY_V3 \
+ ENABLE_AUTHORITY_V3_MIN \
+ AUTHORITY_OPT_REQ_
+
+#define ENABLE_AUTHORITY_BRIDGE \
+ ENABLE_AUTHORITY_BRIDGE_MIN \
+ AUTHORITY_OPT_REQ_
+
+#endif /* defined(COCCI) */
+
#define VALID_DIR_AUTH "DirAuthority dizum orport=443 v3ident=E8A9C45" \
"EDE6D711294FADF8E7951F4DE6CA56B58 194.109.206.212:80 7EA6 EAD6 FD83" \
" 083C 538F 4403 8BBF A077 587D D755\n"
@@ -180,12 +229,11 @@ test_options_validate_impl(const char *configuration,
int phase)
{
or_options_t *opt=NULL;
- or_options_t *dflt;
config_line_t *cl=NULL;
char *msg=NULL;
int r;
- setup_options(opt, dflt);
+ setup_options(opt);
r = config_get_lines(configuration, &cl, 1);
if (phase == PH_GETLINES) {
@@ -208,7 +256,7 @@ test_options_validate_impl(const char *configuration,
if (r)
goto done;
- r = options_validate(NULL, opt, dflt, 0, &msg);
+ r = options_validate(NULL, opt, &msg);
if (phase == PH_VALIDATE) {
if (test_options_checkmsgs(configuration, expect_errmsg,
expect_log_severity,
@@ -222,7 +270,6 @@ test_options_validate_impl(const char *configuration,
policies_free_all();
config_free_lines(cl);
or_options_free(opt);
- or_options_free(dflt);
tor_free(msg);
clear_log_messages();
}
@@ -260,18 +307,10 @@ test_options_validate(void *arg)
WANT_ERR("BridgeRelay 1\nDirCache 0",
"We're a bridge but DirCache is disabled.", PH_VALIDATE);
- // XXXX We should replace this with a more full error message once #29211
- // XXXX is done. It is truncated for now because at the current stage
- // XXXX of refactoring, we can't give a full error message like before.
- WANT_ERR_LOG("HeartbeatPeriod 21 snarks",
- "malformed or out of bounds", LOG_WARN,
- "Unknown unit 'snarks'.",
- PH_ASSIGN);
- // XXXX As above.
- WANT_ERR_LOG("LogTimeGranularity 21 snarks",
- "malformed or out of bounds", LOG_WARN,
- "Unknown unit 'snarks'.",
- PH_ASSIGN);
+ WANT_ERR("HeartbeatPeriod 21 snarks",
+ "Unknown unit in 21 snarks", PH_ASSIGN);
+ WANT_ERR("LogTimeGranularity 21 snarks",
+ "Unknown unit in 21 snarks", PH_ASSIGN);
OK("HeartbeatPeriod 1 hour", PH_VALIDATE);
OK("LogTimeGranularity 100 milliseconds", PH_VALIDATE);
@@ -294,15 +333,13 @@ test_have_enough_mem_for_dircache(void *arg)
{
(void)arg;
or_options_t *opt=NULL;
- or_options_t *dflt=NULL;
config_line_t *cl=NULL;
char *msg=NULL;
int r;
const char *configuration = "ORPort 8080\nDirCache 1", *expect_errmsg;
- setup_options(opt, dflt);
+ setup_options(opt);
setup_log_callback();
- (void)dflt;
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
@@ -376,7 +413,6 @@ test_have_enough_mem_for_dircache(void *arg)
done:
if (msg)
tor_free(msg);
- or_options_free(dflt);
or_options_free(opt);
config_free_lines(cl);
return;
@@ -390,33 +426,8 @@ fixed_get_uname(void)
return fixed_get_uname_result;
}
-#define TEST_OPTIONS_OLD_VALUES "TestingV3AuthInitialVotingInterval 1800\n" \
- "ClientBootstrapConsensusMaxInProgressTries 3\n" \
- "TestingV3AuthInitialVoteDelay 300\n" \
- "TestingV3AuthInitialDistDelay 300\n" \
- "TestingClientMaxIntervalWithoutRequest 600\n" \
- "TestingDirConnectionMaxStall 600\n" \
-
-#define TEST_OPTIONS_DEFAULT_VALUES TEST_OPTIONS_OLD_VALUES \
- "MaxClientCircuitsPending 1\n" \
- "RendPostPeriod 1000\n" \
- "KeepAlivePeriod 1\n" \
- "ConnLimit 1\n" \
- "V3AuthVotingInterval 300\n" \
- "V3AuthVoteDelay 20\n" \
- "V3AuthDistDelay 20\n" \
- "V3AuthNIntervalsValid 3\n" \
- "ClientUseIPv4 1\n" \
- "VirtualAddrNetworkIPv4 127.192.0.0/10\n" \
- "VirtualAddrNetworkIPv6 [FE80::]/10\n" \
- "UseEntryGuards 1\n" \
- "Schedulers Vanilla\n" \
- "ClientDNSRejectInternalAddresses 1\n"
-
typedef struct {
- or_options_t *old_opt;
or_options_t *opt;
- or_options_t *def_opt;
} options_test_data_t;
static void free_options_test_data(options_test_data_t *td);
@@ -429,15 +440,8 @@ get_options_test_data(const char *conf)
config_line_t *cl=NULL;
options_test_data_t *result = tor_malloc(sizeof(options_test_data_t));
result->opt = options_new();
- result->old_opt = options_new();
- result->def_opt = options_new();
- // XXX: Really, all of these options should be set to defaults
- // with options_init(), but about a dozen tests break when I do that.
- // Being kinda lame and just fixing the immedate breakage for now..
- result->opt->ConnectionPadding = -1; // default must be "auto"
- result->opt->DormantClientTimeout = 1800; // must be over 600.
- result->opt->CircuitPadding = 1; // default must be "1"
+ options_init(result->opt);
rv = config_get_lines(conf, &cl, 1);
tt_int_op(rv, OP_EQ, 0);
@@ -450,13 +454,7 @@ get_options_test_data(const char *conf)
config_free_lines(cl);
result->opt->LogTimeGranularity = 1;
result->opt->TokenBucketRefillInterval = 1;
- rv = config_get_lines(TEST_OPTIONS_OLD_VALUES, &cl, 1);
- tt_int_op(rv, OP_EQ, 0);
- rv = config_assign(get_options_mgr(), result->def_opt, cl, 0, &msg);
- if (msg) {
- /* Display the parse error message by comparing it with an empty string */
- tt_str_op(msg, OP_EQ, "");
- }
+ rv = config_get_lines("", &cl, 1);
tt_int_op(rv, OP_EQ, 0);
done:
@@ -475,9 +473,7 @@ static void
free_options_test_data(options_test_data_t *td)
{
if (!td) return;
- or_options_free(td->old_opt);
or_options_free(td->opt);
- or_options_free(td->def_opt);
tor_free(td);
}
@@ -500,7 +496,7 @@ test_options_validate__uname_for_server(void *ignored)
MOCK(get_uname, fixed_get_uname);
fixed_get_uname_result = "Windows 95";
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Tor is running as a server, but you"
" are running Windows 95; this probably won't work. See https://www"
".torproject.org/docs/faq.html#BestOSForRelay for details.\n");
@@ -508,7 +504,7 @@ test_options_validate__uname_for_server(void *ignored)
fixed_get_uname_result = "Windows 98";
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Tor is running as a server, but you"
" are running Windows 98; this probably won't work. See https://www"
".torproject.org/docs/faq.html#BestOSForRelay for details.\n");
@@ -516,7 +512,7 @@ test_options_validate__uname_for_server(void *ignored)
fixed_get_uname_result = "Windows Me";
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Tor is running as a server, but you"
" are running Windows Me; this probably won't work. See https://www"
".torproject.org/docs/faq.html#BestOSForRelay for details.\n");
@@ -524,8 +520,8 @@ test_options_validate__uname_for_server(void *ignored)
fixed_get_uname_result = "Windows 2000";
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- expect_no_log_entry();
+ options_validate(NULL, tdata->opt, &msg);
+ expect_no_log_msg("Tor is running as a server, but you ");
tor_free(msg);
done:
@@ -548,7 +544,7 @@ test_options_validate__outbound_addresses(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"OutboundBindAddress xxyy!!!sdfaf");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Multiple outbound bind addresses configured: "
"xxyy!!!sdfaf");
@@ -585,7 +581,7 @@ test_options_validate__data_directory(void *ignored)
"ONGLONGlongreallylongLONG"
"LONG"); // 440 characters
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Invalid DataDirectory");
@@ -603,7 +599,7 @@ test_options_validate__nickname(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"Nickname ThisNickNameIsABitTooLong");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Nickname 'ThisNickNameIsABitTooLong', nicknames must be between "
@@ -613,16 +609,14 @@ test_options_validate__nickname(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("Nickname AMoreValidNick");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("DataDirectory /tmp/somewhere");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
done:
free_options_test_data(tdata);
@@ -640,8 +634,8 @@ test_options_validate__contactinfo(void *ignored)
setup_capture_of_logs(LOG_DEBUG);
tdata->opt->ContactInfo = NULL;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"Your ContactInfo config option is not set. Please strongly "
"consider setting it, so we can contact you if your relay is "
@@ -654,8 +648,8 @@ test_options_validate__contactinfo(void *ignored)
tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"ContactInfo hella@example.org");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"Your ContactInfo config option is not set. Please strongly "
"consider setting it, so we can contact you if your relay is "
@@ -682,50 +676,53 @@ test_options_validate__logs(void *ignored)
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 0;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(tdata->opt->Logs->key, OP_EQ, "Log");
- tt_str_op(tdata->opt->Logs->value, OP_EQ, "notice stdout");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_assert(!tdata->opt->Logs);
tor_free(msg);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, 0);
free_options_test_data(tdata);
tdata = get_options_test_data("");
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 0;
quiet_level = 1;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(tdata->opt->Logs->key, OP_EQ, "Log");
- tt_str_op(tdata->opt->Logs->value, OP_EQ, "warn stdout");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_assert(!tdata->opt->Logs);
tor_free(msg);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, 0);
free_options_test_data(tdata);
tdata = get_options_test_data("");
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 0;
quiet_level = 2;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, 0);
free_options_test_data(tdata);
tdata = get_options_test_data("");
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 0;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 1, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, 0);
free_options_test_data(tdata);
tdata = get_options_test_data("");
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 1;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
+#ifdef _WIN32
+ /* Can't RunAsDaemon on Windows. */
tt_int_op(ret, OP_EQ, -1);
+#else
+ tt_int_op(ret, OP_EQ, 0);
+#endif /* defined(_WIN32) */
free_options_test_data(tdata);
tdata = get_options_test_data("");
@@ -733,7 +730,7 @@ test_options_validate__logs(void *ignored)
config_line_t *cl=NULL;
config_get_lines("Log foo", &cl, 1);
tdata->opt->Logs = cl;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op((intptr_t)tdata->opt->Logs, OP_EQ, (intptr_t)cl);
tt_int_op(ret, OP_EQ, -1);
@@ -761,13 +758,14 @@ test_options_validate__authdir(void *ignored)
char *msg;
setup_capture_of_logs(LOG_INFO);
options_test_data_t *tdata = get_options_test_data(
- "AuthoritativeDirectory 1\n"
+ ENABLE_AUTHORITY_V3_MIN
"Address this.should.not!exist!.example.org");
+ const dirauth_options_t *da_opt;
sandbox_disable_getaddrinfo_cache();
MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
UNMOCK(tor_addr_lookup);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Failed to resolve/guess local address. See logs for"
@@ -777,246 +775,217 @@ test_options_validate__authdir(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3_MIN
"Address 100.200.10.1");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Authoritative directory servers must set "
"ContactInfo");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3_MIN
"Address 100.200.10.1\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Authoritative directory servers must set ContactInfo");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_MIN
"Address 100.200.10.1\n"
"TestingTorNetwork 1\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
"AuthoritativeDir is set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
"AuthoritativeDir is set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "RecommendedVersions 1.2, 3.14\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "RecommendedVersions 1.2, 3.14\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(tdata->opt->RecommendedClientVersions->value, OP_EQ, "1.2, 3.14");
- tt_str_op(tdata->opt->RecommendedServerVersions->value, OP_EQ, "1.2, 3.14");
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
+ tt_str_op(da_opt->RecommendedClientVersions->value, OP_EQ, "1.2, 3.14");
+ tt_str_op(da_opt->RecommendedServerVersions->value, OP_EQ, "1.2, 3.14");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"RecommendedVersions 1.2, 3.14\n"
"RecommendedClientVersions 25\n"
- "RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n");
+ "RecommendedServerVersions 4.18\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(tdata->opt->RecommendedClientVersions->value, OP_EQ, "25");
- tt_str_op(tdata->opt->RecommendedServerVersions->value, OP_EQ, "4.18");
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
+ tt_str_op(da_opt->RecommendedClientVersions->value, OP_EQ, "25");
+ tt_str_op(da_opt->RecommendedServerVersions->value, OP_EQ, "4.18");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY
"VersioningAuthoritativeDirectory 1\n"
"RecommendedVersions 1.2, 3.14\n"
"RecommendedClientVersions 25\n"
- "RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n");
+ "RecommendedServerVersions 4.18\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
"AuthoritativeDir is set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"VersioningAuthoritativeDirectory 1\n"
- "RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n");
+ "RecommendedServerVersions 4.18\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
tt_str_op(msg, OP_EQ, "Versioning authoritative dir servers must set "
"Recommended*Versions.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"VersioningAuthoritativeDirectory 1\n"
- "RecommendedClientVersions 4.18\n"
- "ContactInfo hello@hello.com\n");
+ "RecommendedClientVersions 4.18\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
tt_str_op(msg, OP_EQ, "Versioning authoritative dir servers must set "
"Recommended*Versions.");
tor_free(msg);
+ da_opt = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "UseEntryGuards 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "UseEntryGuards 1\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Authoritative directory servers "
"can't set UseEntryGuards. Disabling.\n");
tt_int_op(tdata->opt->UseEntryGuards, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "V3AuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "DownloadExtraInfo 0\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Authoritative directories always try"
" to download extra-info documents. Setting DownloadExtraInfo.\n");
tt_int_op(tdata->opt->DownloadExtraInfo, OP_EQ, 1);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "DownloadExtraInfo 1\n"
- "V3AuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "V3BandwidthsFile non-existent-file\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- expect_no_log_msg("Authoritative directories always try"
- " to download extra-info documents. Setting DownloadExtraInfo.\n");
- tt_int_op(tdata->opt->DownloadExtraInfo, OP_EQ, 1);
+ options_validate(NULL, tdata->opt, &msg);
+ expect_log_msg("Can't open bandwidth file at configured location: "
+ "non-existent-file\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "GuardfractionFile non-existent-file\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
- "AuthoritativeDir is set.");
+ options_validate(NULL, tdata->opt, &msg);
+ expect_log_msg("Cannot open guardfraction file 'non-existent-file'. "
+ "Failing.\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3_MIN
"Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "V3BandwidthsFile non-existent-file\n");
+ "ORPort 2000\n"
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Running as authoritative directory, but no DirPort set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_BRIDGE_MIN
"Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "V3BandwidthsFile non-existent-file\n");
+ "ORPort 2000\n"
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
- options_validate(NULL, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Running as authoritative directory, but no DirPort set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3_MIN
"Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "GuardfractionFile non-existent-file\n");
+ "DirPort 999\n"
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
- "Running as authoritative directory, but no DirPort set.");
+ "Running as authoritative directory, but no ORPort set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_BRIDGE_MIN
"Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "GuardfractionFile non-existent-file\n");
+ "DirPort 999\n"
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
- options_validate(NULL, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
- "Running as authoritative directory, but no DirPort set.");
+ "Running as authoritative directory, but no ORPort set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "ClientOnly 1\n");
+ /* We have to call the dirauth-specific function, and fake port parsing,
+ * to hit this case */
+ tdata->opt->DirPort_set = 1;
+ tdata->opt->ORPort_set = 1;
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate_dirauth_mode(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ,
- "Running as authoritative directory, but no DirPort set.");
+ tt_str_op(msg, OP_EQ, "Running as authoritative directory, "
+ "but ClientOnly also set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "DirPort 999\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_BRIDGE
+ "ClientOnly 1\n");
+ /* We have to call the dirauth-specific function, and fake port parsing,
+ * to hit this case */
+ tdata->opt->DirPort_set = 1;
+ tdata->opt->ORPort_set = 1;
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate_dirauth_mode(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ,
- "Running as authoritative directory, but no ORPort set.");
+ tt_str_op(msg, OP_EQ, "Running as authoritative directory, "
+ "but ClientOnly also set.");
tor_free(msg);
- // TODO: This case can't be reached, since clientonly is used to
- // check when parsing port lines as well.
- /* free_options_test_data(tdata); */
- /* tdata = get_options_test_data("AuthoritativeDirectory 1\n" */
- /* "Address 100.200.10.1\n" */
- /* "DirPort 999\n" */
- /* "ORPort 888\n" */
- /* "ClientOnly 1\n" */
- /* "BridgeAuthoritativeDir 1\n" */
- /* "ContactInfo hello@hello.com\n" ); */
- /* mock_clean_saved_logs(); */
- /* ret = options_validate(tdata->old_opt, tdata->opt, */
- /* tdata->def_opt, 0, &msg); */
- /* tt_int_op(ret, OP_EQ, -1); */
- /* tt_str_op(msg, OP_EQ, "Running as authoritative directory, " */
- /* "but ClientOnly also set."); */
-
done:
teardown_capture_of_logs();
// sandbox_free_getaddrinfo_cache();
@@ -1029,6 +998,7 @@ test_options_validate__relay_with_hidden_services(void *ignored)
{
(void)ignored;
char *msg;
+ int ret;
setup_capture_of_logs(LOG_DEBUG);
options_test_data_t *tdata = get_options_test_data(
"ORPort 127.0.0.1:5555\n"
@@ -1037,7 +1007,8 @@ test_options_validate__relay_with_hidden_services(void *ignored)
"HiddenServicePort 80 127.0.0.1:8080\n"
);
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"Tor is currently configured as a relay and a hidden service. "
"That's not very secure: you should probably run your hidden servi"
@@ -1050,27 +1021,25 @@ test_options_validate__relay_with_hidden_services(void *ignored)
tor_free(msg);
}
-// TODO: it doesn't seem possible to hit the case of having no port lines at
-// all, since there will be a default created for SocksPort
-/* static void */
-/* test_options_validate__ports(void *ignored) */
-/* { */
-/* (void)ignored; */
-/* int ret; */
-/* char *msg; */
-/* setup_capture_of_logs(LOG_WARN); */
-/* options_test_data_t *tdata = get_options_test_data(""); */
-/* ret = options_validate(tdata->old_opt, tdata->opt, */
-/* tdata->def_opt, 0, &msg); */
-/* expect_log_msg("SocksPort, TransPort, NATDPort, DNSPort, and ORPort " */
-/* "are all undefined, and there aren't any hidden services " */
-/* "configured. " */
-/* " Tor will still run, but probably won't do anything.\n"); */
-/* done: */
-/* teardown_capture_of_logs(); */
-/* free_options_test_data(tdata); */
-/* tor_free(msg); */
-/* } */
+static void
+test_options_validate__listen_ports(void *ignored)
+{
+ (void)ignored;
+ int ret;
+ char *msg;
+ setup_capture_of_logs(LOG_WARN);
+ options_test_data_t *tdata = get_options_test_data("SOCKSPort 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ expect_log_msg("SocksPort, TransPort, NATDPort, DNSPort, and ORPort "
+ "are all undefined, and there aren't any hidden services "
+ "configured. "
+ " Tor will still run, but probably won't do anything.\n");
+ done:
+ teardown_capture_of_logs();
+ free_options_test_data(tdata);
+ tor_free(msg);
+}
static void
test_options_validate__transproxy(void *ignored)
@@ -1084,31 +1053,31 @@ test_options_validate__transproxy(void *ignored)
// Test default trans proxy
tdata = get_options_test_data("TransProxyType default\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->TransProxyType_parsed, OP_EQ, TPT_DEFAULT);
tor_free(msg);
// Test pf-divert trans proxy
free_options_test_data(tdata);
tdata = get_options_test_data("TransProxyType pf-divert\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
-#if !defined(OpenBSD) && !defined( DARWIN )
+#if !defined(OpenBSD) && !defined(DARWIN)
tt_str_op(msg, OP_EQ,
"pf-divert is a OpenBSD-specific and OS X/Darwin-specific feature.");
#else
tt_int_op(tdata->opt->TransProxyType_parsed, OP_EQ, TPT_PF_DIVERT);
tt_str_op(msg, OP_EQ, "Cannot use TransProxyType without "
"any valid TransPort.");
-#endif /* !defined(OpenBSD) && !defined( DARWIN ) */
+#endif /* !defined(OpenBSD) && !defined(DARWIN) */
tor_free(msg);
// Test tproxy trans proxy
free_options_test_data(tdata);
tdata = get_options_test_data("TransProxyType tproxy\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
#if !defined(__linux__)
@@ -1123,7 +1092,7 @@ test_options_validate__transproxy(void *ignored)
// Test ipfw trans proxy
free_options_test_data(tdata);
tdata = get_options_test_data("TransProxyType ipfw\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
#ifndef KERNEL_MAY_SUPPORT_IPFW
@@ -1139,7 +1108,7 @@ test_options_validate__transproxy(void *ignored)
// Test unknown trans proxy
free_options_test_data(tdata);
tdata = get_options_test_data("TransProxyType non-existent\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Unrecognized value for TransProxyType");
tor_free(msg);
@@ -1151,29 +1120,25 @@ test_options_validate__transproxy(void *ignored)
#if defined(__linux__)
tdata = get_options_test_data("TransProxyType tproxy\n"
"TransPort 127.0.0.1:123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
#elif defined(KERNEL_MAY_SUPPORT_IPFW)
tdata = get_options_test_data("TransProxyType ipfw\n"
"TransPort 127.0.0.1:123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
#elif defined(OpenBSD)
tdata = get_options_test_data("TransProxyType pf-divert\n"
"TransPort 127.0.0.1:123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
#elif defined(__NetBSD__)
tdata = get_options_test_data("TransProxyType default\n"
"TransPort 127.0.0.1:123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
#endif /* defined(__linux__) || ... */
@@ -1183,7 +1148,7 @@ test_options_validate__transproxy(void *ignored)
#else /* !defined(USE_TRANSPARENT) */
tdata = get_options_test_data("TransPort 127.0.0.1:555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TransPort is disabled in this build.");
tor_free(msg);
@@ -1194,13 +1159,14 @@ test_options_validate__transproxy(void *ignored)
tor_free(msg);
}
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static country_t opt_tests_geoip_get_country(const char *country);
+ATTR_UNUSED static int opt_tests_geoip_get_country_called = 0;
static country_t
-NS(geoip_get_country)(const char *countrycode)
+opt_tests_geoip_get_country(const char *countrycode)
{
(void)countrycode;
- CALLED(geoip_get_country)++;
+ opt_tests_geoip_get_country_called++;
return 1;
}
@@ -1210,7 +1176,8 @@ test_options_validate__exclude_nodes(void *ignored)
{
(void)ignored;
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_get_country,
+ opt_tests_geoip_get_country);
int ret;
char *msg;
@@ -1218,8 +1185,8 @@ test_options_validate__exclude_nodes(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"ExcludeExitNodes {us}\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(tdata->opt->ExcludeExitNodesUnion_->list), OP_EQ, 1);
tt_str_op((char *)
(smartlist_get(tdata->opt->ExcludeExitNodesUnion_->list, 0)),
@@ -1228,8 +1195,8 @@ test_options_validate__exclude_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ExcludeNodes {cn}\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(tdata->opt->ExcludeExitNodesUnion_->list), OP_EQ, 1);
tt_str_op((char *)
(smartlist_get(tdata->opt->ExcludeExitNodesUnion_->list, 0)),
@@ -1239,8 +1206,8 @@ test_options_validate__exclude_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ExcludeNodes {cn}\n"
"ExcludeExitNodes {us} {cn}\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(tdata->opt->ExcludeExitNodesUnion_->list), OP_EQ, 2);
tt_str_op((char *)
(smartlist_get(tdata->opt->ExcludeExitNodesUnion_->list, 0)),
@@ -1254,8 +1221,8 @@ test_options_validate__exclude_nodes(void *ignored)
tdata = get_options_test_data("ExcludeNodes {cn}\n"
"StrictNodes 1\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"You have asked to exclude certain relays from all positions "
"in your circuits. Expect hidden services and other Tor "
@@ -1265,8 +1232,8 @@ test_options_validate__exclude_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ExcludeNodes {cn}\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"You have asked to exclude certain relays from all positions "
"in your circuits. Expect hidden services and other Tor "
@@ -1274,7 +1241,7 @@ test_options_validate__exclude_nodes(void *ignored)
tor_free(msg);
done:
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_get_country);
teardown_capture_of_logs();
free_options_test_data(tdata);
tor_free(msg);
@@ -1290,8 +1257,8 @@ test_options_validate__node_families(void *ignored)
"NodeFamily flux, flax\n"
"NodeFamily somewhere\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(tdata->opt->NodeFamilySets);
tt_int_op(smartlist_len(tdata->opt->NodeFamilySets), OP_EQ, 2);
tt_str_op((char *)(smartlist_get(
@@ -1308,15 +1275,15 @@ test_options_validate__node_families(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(!tdata->opt->NodeFamilySets);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("NodeFamily !flux\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_assert(tdata->opt->NodeFamilySets);
tt_int_op(smartlist_len(tdata->opt->NodeFamilySets), OP_EQ, 0);
@@ -1336,14 +1303,14 @@ test_options_validate__token_bucket(void *ignored)
options_test_data_t *tdata = get_options_test_data("");
tdata->opt->TokenBucketRefillInterval = 0;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
tor_free(msg);
tdata->opt->TokenBucketRefillInterval = 1001;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
@@ -1364,7 +1331,7 @@ test_options_validate__fetch_dir(void *ignored)
"FetchDirInfoExtraEarly 1\n"
"FetchDirInfoEarly 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "FetchDirInfoExtraEarly requires that you"
" also set FetchDirInfoEarly");
@@ -1374,10 +1341,8 @@ test_options_validate__fetch_dir(void *ignored)
tdata = get_options_test_data("FetchDirInfoExtraEarly 1\n"
"FetchDirInfoEarly 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_NE, "FetchDirInfoExtraEarly requires that you"
- " also set FetchDirInfoEarly");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
@@ -1394,7 +1359,7 @@ test_options_validate__conn_limit(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"ConnLimit 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
tor_free(msg);
@@ -1402,10 +1367,8 @@ test_options_validate__conn_limit(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ConnLimit 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "MaxClientCircuitsPending must be between 1 and 1024, "
- "but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
@@ -1428,11 +1391,10 @@ test_options_validate__paths_needed(void *ignored)
setup_capture_of_logs(LOG_WARN);
options_test_data_t *tdata = get_options_test_data(
- "PathsNeededToBuildCircuits 0.1\n"
- "ConnLimit 1\n");
+ "PathsNeededToBuildCircuits 0.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(tdata->opt->PathsNeededToBuildCircuits > 0.24 &&
tdata->opt->PathsNeededToBuildCircuits < 0.26);
expect_log_msg("PathsNeededToBuildCircuits is too low. "
@@ -1441,11 +1403,10 @@ test_options_validate__paths_needed(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data("PathsNeededToBuildCircuits 0.99\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("PathsNeededToBuildCircuits 0.99\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(tdata->opt->PathsNeededToBuildCircuits > 0.94 &&
tdata->opt->PathsNeededToBuildCircuits < 0.96);
expect_log_msg("PathsNeededToBuildCircuits is "
@@ -1454,14 +1415,13 @@ test_options_validate__paths_needed(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data("PathsNeededToBuildCircuits 0.91\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("PathsNeededToBuildCircuits 0.91\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(tdata->opt->PathsNeededToBuildCircuits > 0.90 &&
tdata->opt->PathsNeededToBuildCircuits < 0.92);
- expect_no_log_entry();
+ expect_no_log_msg_containing("PathsNeededToBuildCircuits");
tor_free(msg);
done:
@@ -1481,32 +1441,28 @@ test_options_validate__max_client_circuits(void *ignored)
int ret;
char *msg;
options_test_data_t *tdata = get_options_test_data(
- "MaxClientCircuitsPending 0\n"
- "ConnLimit 1\n");
+ "MaxClientCircuitsPending 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "MaxClientCircuitsPending must be between 1 and 1024,"
" but was set to 0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("MaxClientCircuitsPending 1025\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("MaxClientCircuitsPending 1025\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "MaxClientCircuitsPending must be between 1 and 1024,"
" but was set to 1025");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("MaxClientCircuitsPending 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "KeepalivePeriod option must be positive.");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
@@ -1520,23 +1476,18 @@ test_options_validate__ports(void *ignored)
(void)ignored;
int ret;
char *msg;
- options_test_data_t *tdata = get_options_test_data(
- "FirewallPorts 65537\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ options_test_data_t *tdata = get_options_test_data("FirewallPorts 65537\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Port '65537' out of range in FirewallPorts");
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("FirewallPorts 1\n"
- "LongLivedPorts 124444\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "LongLivedPorts 124444\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Port '124444' out of range in LongLivedPorts");
tor_free(msg);
@@ -1544,11 +1495,9 @@ test_options_validate__ports(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("FirewallPorts 1\n"
"LongLivedPorts 2\n"
- "RejectPlaintextPorts 112233\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "RejectPlaintextPorts 112233\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Port '112233' out of range in RejectPlaintextPorts");
tor_free(msg);
@@ -1557,11 +1506,9 @@ test_options_validate__ports(void *ignored)
tdata = get_options_test_data("FirewallPorts 1\n"
"LongLivedPorts 2\n"
"RejectPlaintextPorts 3\n"
- "WarnPlaintextPorts 65536\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "WarnPlaintextPorts 65536\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Port '65536' out of range in WarnPlaintextPorts");
tor_free(msg);
@@ -1570,13 +1517,10 @@ test_options_validate__ports(void *ignored)
tdata = get_options_test_data("FirewallPorts 1\n"
"LongLivedPorts 2\n"
"RejectPlaintextPorts 3\n"
- "WarnPlaintextPorts 4\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "WarnPlaintextPorts 4\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "KeepalivePeriod option must be positive.");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
@@ -1591,13 +1535,10 @@ test_options_validate__reachable_addresses(void *ignored)
int ret;
char *msg;
setup_capture_of_logs(LOG_NOTICE);
- options_test_data_t *tdata = get_options_test_data(
- "FascistFirewall 1\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ options_test_data_t *tdata = get_options_test_data("FascistFirewall 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg("Converting FascistFirewall config "
"option to new format: \"ReachableDirAddresses *:80\"\n");
tt_str_op(tdata->opt->ReachableDirAddresses->value, OP_EQ, "*:80");
@@ -1610,13 +1551,17 @@ test_options_validate__reachable_addresses(void *ignored)
mock_clean_saved_logs();
tdata = get_options_test_data("FascistFirewall 1\n"
"ReachableDirAddresses *:81\n"
- "ReachableORAddresses *:444\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
- tdata->opt->FirewallPorts = smartlist_new();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ "ReachableORAddresses *:444\n");
+ tt_assert(tdata->opt->FirewallPorts);
+ SMARTLIST_FOREACH(tdata->opt->FirewallPorts, char *, cp, tor_free(cp));
+ smartlist_clear(tdata->opt->FirewallPorts);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+#if 0
+ /* This does not actually produce any logs, and did not produce any relevant
+ * logs before. */
expect_log_entry();
+#endif
tt_str_op(tdata->opt->ReachableDirAddresses->value, OP_EQ, "*:81");
tt_str_op(tdata->opt->ReachableORAddresses->value, OP_EQ, "*:444");
tor_free(msg);
@@ -1624,12 +1569,10 @@ test_options_validate__reachable_addresses(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
tdata = get_options_test_data("FascistFirewall 1\n"
- "FirewallPort 123\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "FirewallPort 123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg("Converting FascistFirewall and "
"FirewallPorts config options to new format: "
"\"ReachableAddresses *:123\"\n");
@@ -1641,25 +1584,25 @@ test_options_validate__reachable_addresses(void *ignored)
tdata = get_options_test_data("FascistFirewall 1\n"
"ReachableAddresses *:82\n"
"ReachableAddresses *:83\n"
- "ReachableAddresses reject *:*\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ReachableAddresses reject *:*\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+#if 0
+ /* This does not actually produce any logs, and did not produce any relevant
+ * logs before. */
expect_log_entry();
+#endif
tt_str_op(tdata->opt->ReachableAddresses->value, OP_EQ, "*:82");
tor_free(msg);
free_options_test_data(tdata);
mock_clean_saved_logs();
tdata = get_options_test_data("FascistFirewall 1\n"
- "ReachableAddresses *:82\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ReachableAddresses *:82\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(tdata->opt->ReachableAddresses->next, OP_EQ, NULL);
tor_free(msg);
@@ -1669,44 +1612,36 @@ test_options_validate__reachable_addresses(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableAddresses *:82\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, SERVERS_REACHABLE_MSG);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableORAddresses *:82\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, SERVERS_REACHABLE_MSG);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableDirAddresses *:82\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, SERVERS_REACHABLE_MSG);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("ClientUseIPv4 0\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, SERVERS_REACHABLE_MSG);
tor_free(msg);
@@ -1714,74 +1649,68 @@ test_options_validate__reachable_addresses(void *ignored)
/* Test IPv4-only clients setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv4 1\n"
+ tdata = get_options_test_data("ClientUseIPv4 1\n"
"ClientUseIPv6 0\n"
"UseBridges 0\n"
"ClientPreferIPv6ORPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv4 1\n"
+ tdata = get_options_test_data("ClientUseIPv4 1\n"
"ClientUseIPv6 0\n"
"UseBridges 0\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
/* Now test an IPv4/IPv6 client setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv4 1\n"
+ tdata = get_options_test_data("ClientUseIPv4 1\n"
"ClientUseIPv6 1\n"
"ClientPreferIPv6ORPort 1\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
/* Now test an IPv6 client setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv6 1\n"
+ tdata = get_options_test_data("ClientUseIPv6 1\n"
"ClientPreferIPv6ORPort 1\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
/* And an implicit (IPv4 disabled) IPv6 client setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv4 0\n"
+ tdata = get_options_test_data("ClientUseIPv4 0\n"
"ClientPreferIPv6ORPort 1\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
/* And an implicit (bridge) client setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "UseBridges 1\n"
+ tdata = get_options_test_data("UseBridges 1\n"
"Bridge 127.0.0.1:12345\n"
"ClientPreferIPv6ORPort 1\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
@@ -1800,76 +1729,68 @@ test_options_validate__use_bridges(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"UseBridges 1\n"
"ClientUseIPv4 1\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Servers must be able to freely connect to the rest of"
" the Internet, so they must not set UseBridges.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("UseBridges 1\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("UseBridges 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_NE, "Servers must be able to freely connect to the rest of"
" the Internet, so they must not set UseBridges.");
tor_free(msg);
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_get_country,
+ opt_tests_geoip_get_country);
free_options_test_data(tdata);
tdata = get_options_test_data("UseBridges 1\n"
- "EntryNodes {cn}\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "EntryNodes {cn}\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "You cannot set both UseBridges and EntryNodes.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "UseBridges 1\n");
+ tdata = get_options_test_data("UseBridges 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"If you set UseBridges, you must specify at least one bridge.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "UseBridges 1\n"
+ tdata = get_options_test_data("UseBridges 1\n"
"Bridge 10.0.0.1\n"
"UseEntryGuards 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Setting UseBridges requires also setting UseEntryGuards.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "UseBridges 1\n"
+ tdata = get_options_test_data("UseBridges 1\n"
"Bridge 10.0.0.1\n"
"Bridge !!!\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bridge line did not parse. See logs for details.");
tor_free(msg);
done:
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_get_country);
policies_free_all();
free_options_test_data(tdata);
tor_free(msg);
@@ -1881,14 +1802,13 @@ test_options_validate__entry_nodes(void *ignored)
(void)ignored;
int ret;
char *msg;
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_get_country,
+ opt_tests_geoip_get_country);
options_test_data_t *tdata = get_options_test_data(
"EntryNodes {cn}\n"
- "UseEntryGuards 0\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "UseEntryGuards 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"If EntryNodes is set, UseEntryGuards must be enabled.");
@@ -1896,17 +1816,14 @@ test_options_validate__entry_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("EntryNodes {cn}\n"
- "UseEntryGuards 1\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "UseEntryGuards 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "KeepalivePeriod option must be positive.");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_get_country);
free_options_test_data(tdata);
tor_free(msg);
}
@@ -1917,51 +1834,41 @@ test_options_validate__safe_logging(void *ignored)
(void)ignored;
int ret;
char *msg;
- options_test_data_t *tdata = get_options_test_data(
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ options_test_data_t *tdata = get_options_test_data("SafeLogging 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->SafeLogging_, OP_EQ, SAFELOG_SCRUB_NONE);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SafeLogging 0\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("SafeLogging 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->SafeLogging_, OP_EQ, SAFELOG_SCRUB_NONE);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SafeLogging Relay\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("SafeLogging Relay\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->SafeLogging_, OP_EQ, SAFELOG_SCRUB_RELAY);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SafeLogging 1\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("SafeLogging 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->SafeLogging_, OP_EQ, SAFELOG_SCRUB_ALL);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SafeLogging stuffy\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("SafeLogging stuffy\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Unrecognized value '\"stuffy\"' in SafeLogging");
tor_free(msg);
@@ -1980,27 +1887,24 @@ test_options_validate__publish_server_descriptor(void *ignored)
char *msg;
setup_capture_of_logs(LOG_WARN);
options_test_data_t *tdata = get_options_test_data(
- "PublishServerDescriptor bridge\n" TEST_OPTIONS_DEFAULT_VALUES
- );
+ "PublishServerDescriptor bridge\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("PublishServerDescriptor humma\n"
- TEST_OPTIONS_DEFAULT_VALUES);
+ tdata = get_options_test_data("PublishServerDescriptor humma\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Unrecognized value in PublishServerDescriptor");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("PublishServerDescriptor bridge, v3\n"
- TEST_OPTIONS_DEFAULT_VALUES);
+ tdata = get_options_test_data("PublishServerDescriptor bridge, v3\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bridges are not supposed to publish router "
"descriptors to the directory authorities. Please correct your "
@@ -2009,10 +1913,9 @@ test_options_validate__publish_server_descriptor(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("BridgeRelay 1\n"
- "PublishServerDescriptor v3\n"
- TEST_OPTIONS_DEFAULT_VALUES);
+ "PublishServerDescriptor v3\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bridges are not supposed to publish router "
"descriptors to the directory authorities. Please correct your "
@@ -2020,9 +1923,9 @@ test_options_validate__publish_server_descriptor(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("BridgeRelay 1\n" TEST_OPTIONS_DEFAULT_VALUES);
+ tdata = get_options_test_data("BridgeRelay 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_NE, "Bridges are not supposed to publish router "
"descriptors to the directory authorities. Please correct your "
@@ -2031,10 +1934,10 @@ test_options_validate__publish_server_descriptor(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("BridgeRelay 1\n"
- "DirPort 999\n" TEST_OPTIONS_DEFAULT_VALUES);
+ "DirPort 999\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ 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");
@@ -2059,21 +1962,19 @@ test_options_validate__testing(void *ignored)
#define ENSURE_DEFAULT(varname, varval) \
STMT_BEGIN \
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
- #varname " " #varval "\n"); \
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ tdata = get_options_test_data(#varname " " #varval "\n"); \
+ ret = options_validate(NULL, tdata->opt, &msg); \
tt_str_op(msg, OP_EQ, \
#varname " may only be changed in testing Tor networks!"); \
tt_int_op(ret, OP_EQ, -1); \
tor_free(msg); \
\
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
- #varname " " #varval "\n" \
+ tdata = get_options_test_data(#varname " " #varval "\n" \
VALID_DIR_AUTH \
"TestingTorNetwork 1\n"); \
\
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ ret = options_validate(NULL, tdata->opt, &msg); \
if (msg) { \
tt_str_op(msg, OP_NE, \
#varname " may only be changed in testing Tor networks!"); \
@@ -2081,11 +1982,10 @@ test_options_validate__testing(void *ignored)
} \
\
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
- #varname " " #varval "\n" \
+ tdata = get_options_test_data(#varname " " #varval "\n" \
"___UsingTestNetworkDefaults 1\n"); \
\
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ ret = options_validate(NULL, tdata->opt, &msg);\
if (msg) { \
tt_str_op(msg, OP_NE, \
#varname " may only be changed in testing Tor networks!"); \
@@ -2098,7 +1998,6 @@ test_options_validate__testing(void *ignored)
ENSURE_DEFAULT(TestingV3AuthInitialDistDelay, 3000);
ENSURE_DEFAULT(TestingV3AuthVotingStartOffset, 3000);
ENSURE_DEFAULT(TestingAuthDirTimeToLearnReachability, 3000);
- ENSURE_DEFAULT(TestingEstimatedDescriptorPropagationTime, 3000);
ENSURE_DEFAULT(TestingServerDownloadInitialDelay, 3000);
ENSURE_DEFAULT(TestingClientDownloadInitialDelay, 3000);
ENSURE_DEFAULT(TestingServerConsensusDownloadInitialDelay, 3000);
@@ -2128,21 +2027,12 @@ test_options_validate__hidserv(void *ignored)
char *msg;
setup_capture_of_logs(LOG_WARN);
- options_test_data_t *tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES);
- tdata->opt->MinUptimeHidServDirectoryV2 = -1;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, 0);
- expect_log_msg("MinUptimeHidServDirectoryV2 "
- "option must be at least 0 seconds. Changing to 0.\n");
- tt_int_op(tdata->opt->MinUptimeHidServDirectoryV2, OP_EQ, 0);
- tor_free(msg);
+ options_test_data_t *tdata = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RendPostPeriod 1\n" );
+ tdata = get_options_test_data("RendPostPeriod 1\n" );
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("RendPostPeriod option is too short;"
" raising to 600 seconds.\n");
@@ -2150,10 +2040,9 @@ test_options_validate__hidserv(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RendPostPeriod 302401\n" );
+ tdata = get_options_test_data("RendPostPeriod 302401\n" );
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("RendPostPeriod is too large; "
"clipping to 302400s.\n");
@@ -2175,45 +2064,40 @@ test_options_validate__path_bias(void *ignored)
char *msg;
options_test_data_t *tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"PathBiasNoticeRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasNoticeRate is too high. It must be between 0 and 1.0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PathBiasWarnRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("PathBiasWarnRate 1.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasWarnRate is too high. It must be between 0 and 1.0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PathBiasExtremeRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("PathBiasExtremeRate 1.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasExtremeRate is too high. It must be between 0 and 1.0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PathBiasNoticeUseRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("PathBiasNoticeUseRate 1.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasNoticeUseRate is too high. It must be between 0 and 1.0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PathBiasExtremeUseRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("PathBiasExtremeUseRate 1.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasExtremeUseRate is too high. It must be between 0 and 1.0");
@@ -2232,130 +2116,141 @@ test_options_validate__bandwidth(void *ignored)
char *msg;
options_test_data_t *tdata = NULL;
-#define ENSURE_BANDWIDTH_PARAM(p) \
- STMT_BEGIN \
+#define ENSURE_BANDWIDTH_PARAM(p, EXTRA_OPT_STR) \
+ STMT_BEGIN \
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES #p " 3Gb\n"); \
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ tdata = get_options_test_data(EXTRA_OPT_STR \
+ #p " 3Gb\n"); \
+ ret = options_validate(NULL, tdata->opt, &msg); \
tt_int_op(ret, OP_EQ, -1); \
tt_mem_op(msg, OP_EQ, #p " (3221225471) must be at most 2147483647", 40); \
tor_free(msg); \
STMT_END
- ENSURE_BANDWIDTH_PARAM(BandwidthRate);
- ENSURE_BANDWIDTH_PARAM(BandwidthBurst);
- ENSURE_BANDWIDTH_PARAM(MaxAdvertisedBandwidth);
- ENSURE_BANDWIDTH_PARAM(RelayBandwidthRate);
- ENSURE_BANDWIDTH_PARAM(RelayBandwidthBurst);
- ENSURE_BANDWIDTH_PARAM(PerConnBWRate);
- ENSURE_BANDWIDTH_PARAM(PerConnBWBurst);
- ENSURE_BANDWIDTH_PARAM(AuthDirFastGuarantee);
- ENSURE_BANDWIDTH_PARAM(AuthDirGuardBWGuarantee);
+ ENSURE_BANDWIDTH_PARAM(BandwidthRate, "");
+ ENSURE_BANDWIDTH_PARAM(BandwidthBurst, "");
+
+ ENSURE_BANDWIDTH_PARAM(BandwidthRate, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(BandwidthBurst, ENABLE_AUTHORITY_V3);
+
+ ENSURE_BANDWIDTH_PARAM(BandwidthRate, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(BandwidthBurst, ENABLE_AUTHORITY_BRIDGE);
+
+ ENSURE_BANDWIDTH_PARAM(MaxAdvertisedBandwidth, "");
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthRate, "");
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthBurst, "");
+ ENSURE_BANDWIDTH_PARAM(PerConnBWRate, "");
+ ENSURE_BANDWIDTH_PARAM(PerConnBWBurst, "");
+
+ ENSURE_BANDWIDTH_PARAM(MaxAdvertisedBandwidth, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthRate, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthBurst, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(PerConnBWRate, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(PerConnBWBurst, ENABLE_AUTHORITY_V3);
+
+ ENSURE_BANDWIDTH_PARAM(MaxAdvertisedBandwidth, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthRate, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthBurst, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(PerConnBWRate, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(PerConnBWBurst, ENABLE_AUTHORITY_BRIDGE);
+
+ ENSURE_BANDWIDTH_PARAM(AuthDirFastGuarantee, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(AuthDirGuardBWGuarantee, ENABLE_AUTHORITY_V3);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthRate 1000\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("RelayBandwidthRate 1000\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_u64_op(tdata->opt->RelayBandwidthBurst, OP_EQ, 1000);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthBurst 1001\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("RelayBandwidthBurst 1001\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_u64_op(tdata->opt->RelayBandwidthRate, OP_EQ, 1001);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthRate 1001\n"
+ tdata = get_options_test_data("RelayBandwidthRate 1001\n"
"RelayBandwidthBurst 1000\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "RelayBandwidthBurst must be at least equal to "
"RelayBandwidthRate.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "BandwidthRate 1001\n"
+ tdata = get_options_test_data("BandwidthRate 1001\n"
"BandwidthBurst 1000\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"BandwidthBurst must be at least equal to BandwidthRate.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthRate 1001\n"
+ tdata = get_options_test_data("RelayBandwidthRate 1001\n"
"BandwidthRate 1000\n"
"BandwidthBurst 1000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_u64_op(tdata->opt->BandwidthRate, OP_EQ, 1001);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthRate 1001\n"
+ tdata = get_options_test_data("RelayBandwidthRate 1001\n"
"BandwidthRate 1000\n"
"RelayBandwidthBurst 1001\n"
"BandwidthBurst 1000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_u64_op(tdata->opt->BandwidthBurst, OP_EQ, 1001);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORPort 127.0.0.1:5555\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"BandwidthRate 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "BandwidthRate is set to 1 bytes/second. For servers,"
" it must be at least 76800.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORPort 127.0.0.1:5555\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"MaxAdvertisedBandwidth 30000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "MaxAdvertisedBandwidth is set to 30000 bytes/second."
" For servers, it must be at least 38400.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORPort 127.0.0.1:5555\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"RelayBandwidthRate 1\n"
"MaxAdvertisedBandwidth 38400\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "RelayBandwidthRate is set to 1 bytes/second. For "
"servers, it must be at least 76800.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORPort 127.0.0.1:5555\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"BandwidthBurst 76800\n"
"RelayBandwidthRate 76800\n"
"MaxAdvertisedBandwidth 38400\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
@@ -2374,9 +2269,8 @@ test_options_validate__circuits(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "MaxCircuitDirtiness 2592001\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("MaxCircuitDirtiness 2592001\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("MaxCircuitDirtiness option is too "
"high; setting to 30 days.\n");
tt_int_op(tdata->opt->MaxCircuitDirtiness, OP_EQ, 2592000);
@@ -2384,9 +2278,8 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CircuitStreamTimeout 1\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("CircuitStreamTimeout 1\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("CircuitStreamTimeout option is too"
" short; raising to 10 seconds.\n");
tt_int_op(tdata->opt->CircuitStreamTimeout, OP_EQ, 10);
@@ -2394,9 +2287,8 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CircuitStreamTimeout 111\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("CircuitStreamTimeout 111\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_no_log_msg("CircuitStreamTimeout option is too"
" short; raising to 10 seconds.\n");
tt_int_op(tdata->opt->CircuitStreamTimeout, OP_EQ, 111);
@@ -2404,9 +2296,8 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HeartbeatPeriod 1\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HeartbeatPeriod 1\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("HeartbeatPeriod option is too short;"
" raising to 1800 seconds.\n");
tt_int_op(tdata->opt->HeartbeatPeriod, OP_EQ, 1800);
@@ -2414,9 +2305,8 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HeartbeatPeriod 1982\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HeartbeatPeriod 1982\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_no_log_msg("HeartbeatPeriod option is too short;"
" raising to 1800 seconds.\n");
tt_int_op(tdata->opt->HeartbeatPeriod, OP_EQ, 1982);
@@ -2424,10 +2314,10 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data("LearnCircuitBuildTimeout 0\n"
"CircuitBuildTimeout 1\n"
);
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("CircuitBuildTimeout is shorter (1"
" seconds) than the recommended minimum (10 seconds), and "
"LearnCircuitBuildTimeout is disabled. If tor isn't working, "
@@ -2436,10 +2326,9 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CircuitBuildTimeout 11\n"
+ tdata = get_options_test_data("CircuitBuildTimeout 11\n"
);
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_no_log_msg("CircuitBuildTimeout is shorter (1 "
"seconds) than the recommended minimum (10 seconds), and "
"LearnCircuitBuildTimeout is disabled. If tor isn't working, "
@@ -2463,51 +2352,46 @@ test_options_validate__rend(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"UseEntryGuards 0\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("UseEntryGuards is disabled, but you"
" have configured one or more hidden services on this Tor "
"instance. Your hidden services will be very easy to locate using"
- " a well-known attack -- see http://freehaven.net/anonbib/#hs-"
+ " a well-known attack -- see https://freehaven.net/anonbib/#hs-"
"attack06 for details.\n");
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"UseEntryGuards 1\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("UseEntryGuards is disabled, but you"
" have configured one or more hidden services on this Tor "
"instance. Your hidden services will be very easy to locate using"
- " a well-known attack -- see http://freehaven.net/anonbib/#hs-"
+ " a well-known attack -- see https://freehaven.net/anonbib/#hs-"
"attack06 for details.\n");
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HiddenServicePort 80 127.0.0.1:8080\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HiddenServicePort 80 127.0.0.1:8080\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Failed to configure rendezvous options. See logs for details.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HidServAuth failed\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ 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.");
@@ -2531,11 +2415,10 @@ test_options_validate__single_onion(void *ignored)
/* Test that HiddenServiceSingleHopMode must come with
* HiddenServiceNonAnonymousMode */
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 0\n"
+ tdata = get_options_test_data("SOCKSPort 0\n"
"HiddenServiceSingleHopMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceSingleHopMode does not provide any "
"server anonymity. It must be used with "
@@ -2543,12 +2426,11 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 0\n"
+ tdata = get_options_test_data("SOCKSPort 0\n"
"HiddenServiceSingleHopMode 1\n"
"HiddenServiceNonAnonymousMode 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceSingleHopMode does not provide any "
"server anonymity. It must be used with "
@@ -2556,23 +2438,21 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 0\n"
+ tdata = get_options_test_data("SOCKSPort 0\n"
"HiddenServiceSingleHopMode 1\n"
"HiddenServiceNonAnonymousMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
free_options_test_data(tdata);
/* Test that SOCKSPort if HiddenServiceSingleHopMode is 1 */
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 5000\n"
+ tdata = get_options_test_data("SOCKSPort 5000\n"
"HiddenServiceSingleHopMode 1\n"
"HiddenServiceNonAnonymousMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode is incompatible with "
"using Tor as an anonymous client. Please set "
@@ -2581,32 +2461,30 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 0\n"
+ tdata = get_options_test_data("SOCKSPort 0\n"
"HiddenServiceSingleHopMode 1\n"
"HiddenServiceNonAnonymousMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 5000\n"
+ tdata = get_options_test_data("SOCKSPort 5000\n"
"HiddenServiceSingleHopMode 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
free_options_test_data(tdata);
/* Test that a hidden service can't be run in non anonymous mode. */
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"HiddenServiceNonAnonymousMode 1\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode does not provide any "
"server anonymity. It must be used with "
@@ -2614,10 +2492,10 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"HiddenServiceNonAnonymousMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode does not provide any "
"server anonymity. It must be used with "
@@ -2625,23 +2503,23 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"HiddenServiceNonAnonymousMode 1\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
"HiddenServiceSingleHopMode 1\n"
"SOCKSPort 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
@@ -2662,53 +2540,56 @@ test_options_validate__accounting(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingRule something_bad\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingRule something_bad\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "AccountingRule must be 'sum', 'max', 'in', or 'out'");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingRule sum\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingRule sum\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->AccountingRule, OP_EQ, ACCT_SUM);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingRule max\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingRule max\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->AccountingRule, OP_EQ, ACCT_MAX);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingStart fail\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingRule in\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(tdata->opt->AccountingRule, OP_EQ, ACCT_IN);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data("AccountingRule out\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(tdata->opt->AccountingRule, OP_EQ, ACCT_OUT);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data("AccountingStart fail\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Failed to parse accounting options. See logs for details.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingMax 10\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingMax 10\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"BandwidthBurst 76800\n"
@@ -2718,7 +2599,7 @@ test_options_validate__accounting(void *ignored)
"AccountingMax 10\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("Using accounting with a hidden "
"service and an ORPort is risky: your hidden service(s) and "
@@ -2729,13 +2610,12 @@ test_options_validate__accounting(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
"AccountingMax 10\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("Using accounting with a hidden "
"service and an ORPort is risky: your hidden service(s) and "
@@ -2746,7 +2626,6 @@ test_options_validate__accounting(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service2/\n"
@@ -2754,7 +2633,7 @@ test_options_validate__accounting(void *ignored)
"AccountingMax 10\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("Using accounting with multiple "
"hidden services is risky: they will all turn off at the same"
@@ -2781,36 +2660,29 @@ test_options_validate__proxy(void *ignored)
MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 127.0.42.1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpProxy 127.0.42.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->HTTPProxyPort, OP_EQ, 80);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 127.0.42.1:444\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpProxy 127.0.42.1:444\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->HTTPProxyPort, OP_EQ, 444);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy not_so_valid!\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpProxy not_so_valid!\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HTTPProxy failed to parse or resolve. Please fix.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxyAuthenticator "
+ tdata = get_options_test_data("HttpProxyAuthenticator "
"onetwothreonetwothreonetwothreonetwothreonetw"
"othreonetwothreonetwothreonetwothreonetwothre"
"onetwothreonetwothreonetwothreonetwothreonetw"
@@ -2823,52 +2695,41 @@ test_options_validate__proxy(void *ignored)
"othreonetwothreonetwothreonetwothreonetwothre"
"onetwothreonetwothreonetwothreonetwothreonetw"
"othreonetwothreeonetwothreeonetwothree"
-
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HTTPProxyAuthenticator is too long (>= 512 chars).");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxyAuthenticator validauth\n"
-
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpProxyAuthenticator validauth\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxy 127.0.42.1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpsProxy 127.0.42.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->HTTPSProxyPort, OP_EQ, 443);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxy 127.0.42.1:444\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpsProxy 127.0.42.1:444\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->HTTPSProxyPort, OP_EQ, 444);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxy not_so_valid!\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpsProxy not_so_valid!\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HTTPSProxy failed to parse or resolve. Please fix.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxyAuthenticator "
+ tdata = get_options_test_data("HttpsProxyAuthenticator "
"onetwothreonetwothreonetwothreonetwothreonetw"
"othreonetwothreonetwothreonetwothreonetwothre"
"onetwothreonetwothreonetwothreonetwothreonetw"
@@ -2883,103 +2744,86 @@ test_options_validate__proxy(void *ignored)
"othreonetwothreeonetwothreeonetwothree"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HTTPSProxyAuthenticator is too long (>= 512 chars).");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxyAuthenticator validauth\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpsProxyAuthenticator validauth\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks4Proxy 127.0.42.1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks4Proxy 127.0.42.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->Socks4ProxyPort, OP_EQ, 1080);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks4Proxy 127.0.42.1:444\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks4Proxy 127.0.42.1:444\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->Socks4ProxyPort, OP_EQ, 444);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks4Proxy not_so_valid!\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks4Proxy not_so_valid!\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Socks4Proxy failed to parse or resolve. Please fix.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5Proxy 127.0.42.1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5Proxy 127.0.42.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->Socks5ProxyPort, OP_EQ, 1080);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5Proxy 127.0.42.1:444\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5Proxy 127.0.42.1:444\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->Socks5ProxyPort, OP_EQ, 444);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5Proxy not_so_valid!\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5Proxy not_so_valid!\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Socks5Proxy failed to parse or resolve. Please fix.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks4Proxy 215.1.1.1\n"
+ tdata = get_options_test_data("Socks4Proxy 215.1.1.1\n"
"Socks5Proxy 215.1.1.2\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "You have configured more than one proxy type. "
- "(Socks4Proxy|Socks5Proxy|HTTPSProxy)");
+ "(Socks4Proxy|Socks5Proxy|HTTPSProxy|TCPProxy)");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 215.1.1.1\n"
- );
+ tdata = get_options_test_data("HttpProxy 215.1.1.1\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg("HTTPProxy configured, but no SOCKS "
- "proxy or HTTPS proxy configured. Watch out: this configuration "
- "will proxy unencrypted directory connections only.\n");
+ expect_log_msg("HTTPProxy configured, but no SOCKS proxy, "
+ "HTTPS proxy, or any other TCP proxy configured. Watch out: "
+ "this configuration will proxy unencrypted directory "
+ "connections only.\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 215.1.1.1\n"
+ tdata = get_options_test_data("HttpProxy 215.1.1.1\n"
"Socks4Proxy 215.1.1.1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("HTTPProxy configured, but no SOCKS "
"proxy or HTTPS proxy configured. Watch out: this configuration "
@@ -2987,12 +2831,11 @@ test_options_validate__proxy(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 215.1.1.1\n"
+ tdata = get_options_test_data("HttpProxy 215.1.1.1\n"
"Socks5Proxy 215.1.1.1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("HTTPProxy configured, but no SOCKS "
"proxy or HTTPS proxy configured. Watch out: this configuration "
@@ -3000,12 +2843,11 @@ test_options_validate__proxy(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 215.1.1.1\n"
+ tdata = get_options_test_data("HttpProxy 215.1.1.1\n"
"HttpsProxy 215.1.1.1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"HTTPProxy configured, but no SOCKS proxy or HTTPS proxy "
@@ -3014,81 +2856,69 @@ test_options_validate__proxy(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- );
+ tdata = get_options_test_data("");
tdata->opt->Socks5ProxyUsername = tor_strdup("");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Socks5ProxyUsername must be between 1 and 255 characters.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- );
+ tdata = get_options_test_data("");
tdata->opt->Socks5ProxyUsername =
tor_strdup("ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789AB"
"CDEABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCD"
"EABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEA"
"BCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEABC"
"DE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Socks5ProxyUsername must be between 1 and 255 characters.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyUsername hello_world\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5ProxyUsername hello_world\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Socks5ProxyPassword must be included with "
"Socks5ProxyUsername.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyUsername hello_world\n"
- );
+ tdata = get_options_test_data("Socks5ProxyUsername hello_world\n");
tdata->opt->Socks5ProxyPassword = tor_strdup("");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Socks5ProxyPassword must be between 1 and 255 characters.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyUsername hello_world\n"
- );
+ tdata = get_options_test_data("Socks5ProxyUsername hello_world\n");
tdata->opt->Socks5ProxyPassword =
tor_strdup("ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789AB"
"CDEABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCD"
"EABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEA"
"BCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEABC"
"DE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Socks5ProxyPassword must be between 1 and 255 characters.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyUsername hello_world\n"
- "Socks5ProxyPassword world_hello\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5ProxyUsername hello_world\n"
+ "Socks5ProxyPassword world_hello\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyPassword hello_world\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5ProxyPassword hello_world\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Socks5ProxyPassword must be included with "
"Socks5ProxyUsername.");
@@ -3113,69 +2943,62 @@ test_options_validate__control(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HashedControlPassword something_incorrect\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data(
+ "HashedControlPassword something_incorrect\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Bad HashedControlPassword: wrong length or bad encoding");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HashedControlPassword 16:872860B76453A77D60CA"
+ tdata = get_options_test_data("HashedControlPassword 16:872860B76453A77D60CA"
"2BB8C1A7042072093276A3D701AD684053EC4C\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"__HashedControlSessionPassword something_incorrect\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bad HashedControlSessionPassword: wrong length or "
"bad encoding");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "__HashedControlSessionPassword 16:872860B7645"
+ tdata = get_options_test_data("__HashedControlSessionPassword 16:872860B7645"
"3A77D60CA2BB8C1A7042072093276A3D701AD684053EC"
"4C\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"__OwningControllerProcess something_incorrect\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bad OwningControllerProcess: invalid PID");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "__OwningControllerProcess 123\n"
+ tdata = get_options_test_data("__OwningControllerProcess 123\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlPort 127.0.0.1:1234\n"
+ tdata = get_options_test_data("ControlPort 127.0.0.1:1234\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"ControlPort is open, but no authentication method has been "
@@ -3185,13 +3008,12 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlPort 127.0.0.1:1234\n"
+ tdata = get_options_test_data("ControlPort 127.0.0.1:1234\n"
"HashedControlPassword 16:872860B76453A77D60CA"
"2BB8C1A7042072093276A3D701AD684053EC4C\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlPort is open, but no authentication method has been "
@@ -3201,14 +3023,13 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlPort 127.0.0.1:1234\n"
+ tdata = get_options_test_data("ControlPort 127.0.0.1:1234\n"
"__HashedControlSessionPassword 16:872860B7645"
"3A77D60CA2BB8C1A7042072093276A3D701AD684053EC"
"4C\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlPort is open, but no authentication method has been "
@@ -3218,12 +3039,11 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlPort 127.0.0.1:1234\n"
+ tdata = get_options_test_data("ControlPort 127.0.0.1:1234\n"
"CookieAuthentication 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlPort is open, but no authentication method has been "
@@ -3234,11 +3054,9 @@ test_options_validate__control(void *ignored)
#ifdef HAVE_SYS_UN_H
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlSocket unix:/tmp WorldWritable\n"
- );
+ tdata = get_options_test_data("ControlSocket unix:/tmp WorldWritable\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"ControlSocket is world writable, but no authentication method has"
@@ -3248,13 +3066,12 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlSocket unix:/tmp WorldWritable\n"
+ tdata = get_options_test_data("ControlSocket unix:/tmp WorldWritable\n"
"HashedControlPassword 16:872860B76453A77D60CA"
"2BB8C1A7042072093276A3D701AD684053EC4C\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlSocket is world writable, but no authentication method has"
@@ -3264,14 +3081,13 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlSocket unix:/tmp WorldWritable\n"
+ tdata = get_options_test_data("ControlSocket unix:/tmp WorldWritable\n"
"__HashedControlSessionPassword 16:872860B7645"
"3A77D60CA2BB8C1A7042072093276A3D701AD684053EC"
"4C\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlSocket is world writable, but no authentication method has"
@@ -3281,12 +3097,11 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlSocket unix:/tmp WorldWritable\n"
+ tdata = get_options_test_data("ControlSocket unix:/tmp WorldWritable\n"
"CookieAuthentication 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlSocket is world writable, but no authentication method has"
@@ -3297,11 +3112,10 @@ test_options_validate__control(void *ignored)
#endif /* defined(HAVE_SYS_UN_H) */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CookieAuthFileGroupReadable 1\n"
+ tdata = get_options_test_data("CookieAuthFileGroupReadable 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"CookieAuthFileGroupReadable is set, but will have no effect: you "
@@ -3310,12 +3124,11 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CookieAuthFileGroupReadable 1\n"
+ tdata = get_options_test_data("CookieAuthFileGroupReadable 1\n"
"CookieAuthFile /tmp/somewhere\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"CookieAuthFileGroupReadable is set, but will have no effect: you "
@@ -3340,8 +3153,7 @@ test_options_validate__families(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "MyFamily home\n"
+ tdata = get_options_test_data("MyFamily home\n"
"BridgeRelay 1\n"
"ORPort 127.0.0.1:5555\n"
"BandwidthRate 51300\n"
@@ -3350,7 +3162,7 @@ test_options_validate__families(void *ignored)
"DirCache 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"Listing a family for a bridge relay is not supported: it can "
@@ -3360,11 +3172,9 @@ test_options_validate__families(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "MyFamily home\n"
- );
+ tdata = get_options_test_data("MyFamily home\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"Listing a family for a bridge relay is not supported: it can "
@@ -3374,22 +3184,18 @@ test_options_validate__families(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "MyFamily !\n"
- );
+ tdata = get_options_test_data("MyFamily !\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Invalid nickname '!' in MyFamily line");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "NodeFamily foo\n"
- "NodeFamily !\n"
- );
+ tdata = get_options_test_data("NodeFamily foo\n"
+ "NodeFamily !\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_assert(!msg);
tor_free(msg);
@@ -3410,11 +3216,10 @@ test_options_validate__addr_policies(void *ignored)
options_test_data_t *tdata = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ExitPolicy !!!\n"
+ tdata = get_options_test_data("ExitPolicy !!!\n"
"ExitRelay 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Error in ExitPolicy entry.");
tor_free(msg);
@@ -3435,12 +3240,11 @@ test_options_validate__dir_auth(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- VALID_DIR_AUTH
+ tdata = get_options_test_data(VALID_DIR_AUTH
VALID_ALT_DIR_AUTH
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Directory authority/fallback line did not parse. See logs for "
@@ -3450,10 +3254,8 @@ test_options_validate__dir_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingTorNetwork 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("TestingTorNetwork 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TestingTorNetwork may only be configured in combination with a "
@@ -3462,20 +3264,18 @@ test_options_validate__dir_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- VALID_DIR_AUTH
+ tdata = get_options_test_data(VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingTorNetwork 1\n"
+ tdata = get_options_test_data("TestingTorNetwork 1\n"
VALID_ALT_DIR_AUTH
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TestingTorNetwork may only be configured in combination with a "
@@ -3484,11 +3284,10 @@ test_options_validate__dir_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingTorNetwork 1\n"
+ tdata = get_options_test_data("TestingTorNetwork 1\n"
VALID_ALT_BRIDGE_AUTH
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingTorNetwork may only be configured in "
"combination with a non-default set of DirAuthority or both of "
@@ -3496,12 +3295,11 @@ test_options_validate__dir_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- VALID_ALT_DIR_AUTH
+ tdata = get_options_test_data(VALID_ALT_DIR_AUTH
VALID_ALT_BRIDGE_AUTH
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
@@ -3522,11 +3320,10 @@ test_options_validate__transport(void *ignored)
setup_capture_of_logs(LOG_NOTICE);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientTransportPlugin !!\n"
+ tdata = get_options_test_data("ClientTransportPlugin !!\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Invalid client transport line. See logs for details.");
@@ -3535,20 +3332,17 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientTransportPlugin foo exec bar\n"
+ tdata = get_options_test_data("ClientTransportPlugin foo exec bar\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportPlugin !!\n"
- );
+ tdata = get_options_test_data("ServerTransportPlugin !!\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Invalid server transport line. See logs for details.");
@@ -3557,11 +3351,9 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportPlugin foo exec bar\n"
- );
+ tdata = get_options_test_data("ServerTransportPlugin foo exec bar\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"Tor is not configured as a relay but you specified a "
@@ -3570,15 +3362,14 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportPlugin foo exec bar\n"
+ tdata = get_options_test_data("ServerTransportPlugin foo exec bar\n"
"ORPort 127.0.0.1:5555\n"
"BandwidthRate 76900\n"
"BandwidthBurst 76900\n"
"MaxAdvertisedBandwidth 38500\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"Tor is not configured as a relay but you specified a "
@@ -3587,22 +3378,19 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportListenAddr foo 127.0.0.42:55\n"
- "ServerTransportListenAddr !\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("ServerTransportListenAddr foo 127.0.0.42:55\n"
+ "ServerTransportListenAddr !\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"ServerTransportListenAddr did not parse. See logs for details.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportListenAddr foo 127.0.0.42:55\n"
+ tdata = get_options_test_data("ServerTransportListenAddr foo 127.0.0.42:55\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"You need at least a single managed-proxy to specify a transport "
@@ -3611,8 +3399,7 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportListenAddr foo 127.0.0.42:55\n"
+ tdata = get_options_test_data("ServerTransportListenAddr foo 127.0.0.42:55\n"
"ServerTransportPlugin foo exec bar\n"
"ORPort 127.0.0.1:5555\n"
"BandwidthRate 76900\n"
@@ -3620,7 +3407,7 @@ test_options_validate__transport(void *ignored)
"MaxAdvertisedBandwidth 38500\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"You need at least a single managed-proxy to specify a transport "
@@ -3645,50 +3432,46 @@ test_options_validate__constrained_sockets(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 0\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "ConstrainedSockSize is invalid. Must be a value "
"between 2048 and 262144 in 1024 byte increments.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 263168\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "ConstrainedSockSize is invalid. Must be a value "
"between 2048 and 262144 in 1024 byte increments.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 2047\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "ConstrainedSockSize is invalid. Must be a value "
"between 2048 and 262144 in 1024 byte increments.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 2048\n"
"DirPort 999\n"
"DirCache 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ 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."
@@ -3697,12 +3480,11 @@ test_options_validate__constrained_sockets(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 2048\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ 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"
@@ -3728,12 +3510,12 @@ test_options_validate__v3_auth(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 1000\n"
"V3AuthDistDelay 1000\n"
"V3AuthVotingInterval 1000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
@@ -3741,20 +3523,18 @@ test_options_validate__v3_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "V3AuthVoteDelay 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "V3AuthVoteDelay 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthVoteDelay is way too low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 1\n"
- "TestingTorNetwork 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ "TestingTorNetwork 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthVoteDelay is way too low.");
tor_free(msg);
@@ -3764,87 +3544,127 @@ test_options_validate__v3_auth(void *ignored)
// since they are the same
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "V3AuthDistDelay 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "V3AuthDistDelay 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthDistDelay is way too low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthDistDelay 1\n"
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthDistDelay is way too low.");
tor_free(msg);
- // TODO: we can't reach the case of v3authdistdelay lower than
+ // We can't reach the case of v3authdistdelay lower than
// MIN_DIST_SECONDS but not lower than MIN_DIST_SECONDS_TESTING,
// since they are the same
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthNIntervalsValid 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthNIntervalsValid must be at least 2.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 200\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthVotingInterval is insanely low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "V3AuthVoteDelay 49\n"
+ "V3AuthDistDelay 49\n"
+ "V3AuthVotingInterval 200\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "V3AuthVoteDelay 2\n"
+ "V3AuthDistDelay 2\n"
+ "V3AuthVotingInterval 9\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ,
+ "V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
+ "V3AuthVotingInterval");
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "V3AuthVoteDelay 2\n"
+ "V3AuthDistDelay 2\n"
+ "V3AuthVotingInterval 10\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 200000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthVotingInterval is insanely high.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 1441\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("V3AuthVotingInterval does not divide"
" evenly into 24 hours.\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 1440\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("V3AuthVotingInterval does not divide"
" evenly into 24 hours.\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 299\n"
@@ -3852,84 +3672,125 @@ test_options_validate__v3_auth(void *ignored)
"TestingTorNetwork 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("V3AuthVotingInterval is very low. "
"This may lead to failure to synchronise for a consensus.\n");
tor_free(msg);
- // TODO: It is impossible to reach the case of testingtor network, with
- // v3authvotinginterval too low
- /* free_options_test_data(tdata); */
- /* tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES */
- /* "V3AuthVoteDelay 1\n" */
- /* "V3AuthDistDelay 1\n" */
- /* "V3AuthVotingInterval 9\n" */
- /* VALID_DIR_AUTH */
- /* "TestingTorNetwork 1\n" */
- /* ); */
- /* ret = options_validate(tdata->old_opt, tdata->opt, */
- /* tdata->def_opt, 0, &msg); */
- /* tt_int_op(ret, OP_EQ, -1); */
- /* tt_str_op(msg, OP_EQ, "V3AuthVotingInterval is insanely low."); */
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "V3AuthVoteDelay 1\n"
+ "V3AuthDistDelay 1\n"
+ "V3AuthVotingInterval 9\n"
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ );
+ /* We have to call the dirauth-specific function to reach this case */
+ ret = options_validate_dirauth_schedule(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ, "V3AuthVoteDelay is way too low.");
+ tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"TestingV3AuthInitialVoteDelay 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingV3AuthInitialVoteDelay is way too low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"TestingV3AuthInitialDistDelay 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingV3AuthInitialDistDelay is way too low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
tdata->opt->TestingV3AuthVotingStartOffset = 100000;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingV3AuthVotingStartOffset is higher than the "
"voting interval.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
tdata->opt->TestingV3AuthVotingStartOffset = -1;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TestingV3AuthVotingStartOffset must be non-negative.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"TestingV3AuthInitialVotingInterval 4\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingV3AuthInitialVotingInterval is insanely low.");
tor_free(msg);
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "TestingV3AuthInitialVoteDelay 2\n"
+ "TestingV3AuthInitialDistDelay 2\n"
+ "TestingV3AuthInitialVotingInterval 5\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "TestingV3AuthInitialVotingInterval 7\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ,
+ "TestingV3AuthInitialVotingInterval does not divide evenly into "
+ "30 minutes.");
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "TestingV3AuthInitialVoteDelay 3\n"
+ "TestingV3AuthInitialDistDelay 3\n"
+ "TestingV3AuthInitialVotingInterval 5\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ,
+ "TestingV3AuthInitialVoteDelay plus "
+ "TestingV3AuthInitialDistDelay must be less than "
+ "TestingV3AuthInitialVotingInterval");
+ tor_free(msg);
+
done:
policies_free_all();
teardown_capture_of_logs();
@@ -3946,19 +3807,16 @@ test_options_validate__virtual_addr(void *ignored)
options_test_data_t *tdata = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "VirtualAddrNetworkIPv4 !!"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("VirtualAddrNetworkIPv4 !!");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Error parsing VirtualAddressNetwork !!");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "VirtualAddrNetworkIPv6 !!"
+ tdata = get_options_test_data("VirtualAddrNetworkIPv6 !!"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Error parsing VirtualAddressNetworkIPv6 !!");
tor_free(msg);
@@ -3979,135 +3837,133 @@ test_options_validate__testing_options(void *ignored)
options_test_data_t *tdata = NULL;
setup_capture_of_logs(LOG_WARN);
-#define TEST_TESTING_OPTION(name, low_val, high_val, err_low) \
+#define TEST_TESTING_OPTION(name, accessor, \
+ low_val, high_val, err_low, EXTRA_OPT_STR) \
STMT_BEGIN \
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
+ tdata = get_options_test_data(EXTRA_OPT_STR \
VALID_DIR_AUTH \
"TestingTorNetwork 1\n" \
); \
- tdata->opt-> name = low_val; \
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ accessor(tdata->opt)->name = low_val; \
+ ret = options_validate(NULL, tdata->opt, &msg); \
tt_int_op(ret, OP_EQ, -1); \
tt_str_op(msg, OP_EQ, #name " " err_low); \
tor_free(msg); \
\
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
+ tdata = get_options_test_data(EXTRA_OPT_STR \
VALID_DIR_AUTH \
"TestingTorNetwork 1\n" \
); \
- tdata->opt-> name = high_val; \
+ accessor(tdata->opt)->name = high_val; \
mock_clean_saved_logs(); \
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ ret = options_validate(NULL, tdata->opt, &msg); \
tt_int_op(ret, OP_EQ, 0); \
+ tt_ptr_op(msg, OP_EQ, NULL); \
expect_log_msg( #name " is insanely high.\n"); \
tor_free(msg); \
STMT_END
- TEST_TESTING_OPTION(TestingAuthDirTimeToLearnReachability, -1, 8000,
- "must be non-negative.");
- TEST_TESTING_OPTION(TestingEstimatedDescriptorPropagationTime, -1, 3601,
- "must be non-negative.");
- TEST_TESTING_OPTION(TestingClientMaxIntervalWithoutRequest, -1, 3601,
- "is way too low.");
- TEST_TESTING_OPTION(TestingDirConnectionMaxStall, 1, 3601,
- "is way too low.");
+ TEST_TESTING_OPTION(TestingClientMaxIntervalWithoutRequest, , -1, 3601,
+ "is way too low.", "");
+ TEST_TESTING_OPTION(TestingDirConnectionMaxStall, , 1, 3601,
+ "is way too low.", "");
+
+ TEST_TESTING_OPTION(TestingClientMaxIntervalWithoutRequest, , -1, 3601,
+ "is way too low.", ENABLE_AUTHORITY_V3);
+ TEST_TESTING_OPTION(TestingDirConnectionMaxStall, , 1, 3601,
+ "is way too low.", ENABLE_AUTHORITY_V3);
+
+ TEST_TESTING_OPTION(TestingClientMaxIntervalWithoutRequest, , -1, 3601,
+ "is way too low.", ENABLE_AUTHORITY_BRIDGE);
+ TEST_TESTING_OPTION(TestingDirConnectionMaxStall, , 1, 3601,
+ "is way too low.", ENABLE_AUTHORITY_BRIDGE);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableConnBwEvent 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("TestingEnableConnBwEvent 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingEnableConnBwEvent may only be changed in "
"testing Tor networks!");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableConnBwEvent 1\n"
+ tdata = get_options_test_data("TestingEnableConnBwEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"___UsingTestNetworkDefaults 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableConnBwEvent 1\n"
+ tdata = get_options_test_data("TestingEnableConnBwEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 0\n"
"___UsingTestNetworkDefaults 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableCellStatsEvent 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("TestingEnableCellStatsEvent 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingEnableCellStatsEvent may only be changed in "
"testing Tor networks!");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableCellStatsEvent 1\n"
+ tdata = get_options_test_data("TestingEnableCellStatsEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"___UsingTestNetworkDefaults 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableCellStatsEvent 1\n"
+ tdata = get_options_test_data("TestingEnableCellStatsEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 0\n"
"___UsingTestNetworkDefaults 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableTbEmptyEvent 1\n"
+ tdata = get_options_test_data("TestingEnableTbEmptyEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"___UsingTestNetworkDefaults 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableTbEmptyEvent 1\n"
+ tdata = get_options_test_data("TestingEnableTbEmptyEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 0\n"
"___UsingTestNetworkDefaults 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
@@ -4128,40 +3984,32 @@ test_options_validate__accel(void *ignored)
options_test_data_t *tdata = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccelName foo\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccelName foo\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
- tt_int_op(tdata->opt->HardwareAccel, OP_EQ, 1);
+ tt_int_op(get_crypto_options(tdata->opt)->HardwareAccel, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccelName foo\n"
- );
- tdata->opt->HardwareAccel = 2;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccelName foo\n");
+ get_crypto_options(tdata->opt)->HardwareAccel = 2;
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
- tt_int_op(tdata->opt->HardwareAccel, OP_EQ, 2);
+ tt_int_op(get_crypto_options(tdata->opt)->HardwareAccel, OP_EQ, 2);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccelDir 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccelDir 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Can't use hardware crypto accelerator dir without engine name.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccelDir 1\n"
- "AccelName something\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccelDir 1\n"
+ "AccelName something\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
@@ -4171,8 +4019,280 @@ test_options_validate__accel(void *ignored)
tor_free(msg);
}
+static int mocked_granularity;
+
+static void
+mock_set_log_time_granularity(int g)
+{
+ mocked_granularity = g;
+}
+
+static void
+test_options_init_logs_granularity(void *arg)
+{
+ options_test_data_t *tdata = get_options_test_data("");
+ int rv;
+ (void) arg;
+
+ MOCK(set_log_time_granularity, mock_set_log_time_granularity);
+
+ /* Reasonable value. */
+ tdata->opt->LogTimeGranularity = 100;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 100);
+
+ /* Doesn't divide 1000. */
+ tdata->opt->LogTimeGranularity = 249;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 250);
+
+ /* Doesn't divide 1000. */
+ tdata->opt->LogTimeGranularity = 3;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 4);
+
+ /* Not a multiple of 1000. */
+ tdata->opt->LogTimeGranularity = 1500;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 2000);
+
+ /* Reasonable value. */
+ tdata->opt->LogTimeGranularity = 3000;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 3000);
+
+ /* Negative. (Shouldn't be allowed by rest of config parsing.) */
+ tdata->opt->LogTimeGranularity = -1;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, -1);
+
+ /* Very big */
+ tdata->opt->LogTimeGranularity = 3600 * 1000;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 3600 * 1000);
+
+ done:
+ free_options_test_data(tdata);
+ UNMOCK(set_log_time_granularity);
+}
+
+typedef struct {
+ char *name;
+ log_severity_list_t sev;
+ int fd;
+ bool stream;
+} added_log_t;
+
+static smartlist_t *added_logs = NULL;
+
+static void
+mock_add_stream_log_impl(const log_severity_list_t *sev, const char *name,
+ int fd)
+{
+ added_log_t *a = tor_malloc_zero(sizeof(added_log_t));
+ a->name = tor_strdup(name);
+ memcpy(&a->sev, sev, sizeof(log_severity_list_t));
+ a->fd = fd;
+ a->stream = true;
+ smartlist_add(added_logs, a);
+}
+
+static int
+mock_add_file_log(const log_severity_list_t *sev, const char *name, int fd)
+{
+ added_log_t *a = tor_malloc_zero(sizeof(added_log_t));
+ a->name = tor_strdup(name);
+ memcpy(&a->sev, sev, sizeof(log_severity_list_t));
+ a->fd = fd;
+ smartlist_add(added_logs, a);
+ return 0;
+}
+
+static void
+clear_added_logs(void)
+{
+ SMARTLIST_FOREACH(added_logs, added_log_t *, a,
+ { tor_free(a->name); tor_free(a); });
+ smartlist_clear(added_logs);
+}
+
+static void
+test_options_init_logs_quiet(void *arg)
+{
+ (void)arg;
+ char *cfg = NULL;
+ options_test_data_t *tdata = get_options_test_data("");
+ char *fn1 = tor_strdup(get_fname_rnd("log"));
+ const added_log_t *a;
+ int rv;
+ tdata->opt->RunAsDaemon = 0;
+
+ added_logs = smartlist_new();
+ MOCK(add_stream_log_impl, mock_add_stream_log_impl);
+ MOCK(add_file_log, mock_add_file_log);
+
+ tt_ptr_op(tdata->opt->Logs, OP_EQ, NULL);
+
+ /* First, try with no configured logs, and make sure that our configured
+ logs match the quiet level. */
+ quiet_level = QUIET_SILENT;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(smartlist_len(added_logs), OP_EQ, 0);
+
+ quiet_level = QUIET_HUSH;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(smartlist_len(added_logs), OP_EQ, 1);
+ a = smartlist_get(added_logs, 0);
+ tt_assert(a);
+ tt_assert(a->stream);
+ tt_int_op(a->fd, OP_EQ, fileno(stdout));
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_INFO)], OP_EQ, 0);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_NOTICE)], OP_EQ, 0);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_WARN)], OP_EQ, LD_ALL_DOMAINS);
+ clear_added_logs();
+
+ quiet_level = QUIET_NONE;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(smartlist_len(added_logs), OP_EQ, 1);
+ a = smartlist_get(added_logs, 0);
+ tt_assert(a);
+ tt_assert(a->stream);
+ tt_int_op(a->fd, OP_EQ, fileno(stdout));
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_INFO)], OP_EQ, 0);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_NOTICE)], OP_EQ,
+ LD_ALL_DOMAINS);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_WARN)], OP_EQ, LD_ALL_DOMAINS);
+ clear_added_logs();
+
+ /* Make sure that adding a configured log makes the default logs go away. */
+ tor_asprintf(&cfg, "Log info file %s\n", fn1);
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(cfg);
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(smartlist_len(added_logs), OP_EQ, 1);
+ a = smartlist_get(added_logs, 0);
+ tt_assert(a);
+ tt_assert(! a->stream);
+ tt_int_op(a->fd, OP_NE, fileno(stdout));
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_INFO)], OP_EQ, LD_ALL_DOMAINS);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_NOTICE)], OP_EQ,
+ LD_ALL_DOMAINS);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_WARN)], OP_EQ, LD_ALL_DOMAINS);
+
+ done:
+ free_options_test_data(tdata);
+ tor_free(fn1);
+ tor_free(cfg);
+ clear_added_logs();
+ smartlist_free(added_logs);
+ UNMOCK(add_stream_log_impl);
+ UNMOCK(add_file_log);
+}
+
+static int mock_options_act_status = 0;
+static int
+mock_options_act(const or_options_t *old_options)
+{
+ (void)old_options;
+ return mock_options_act_status;
+}
+static int
+mock_options_act_reversible(const or_options_t *old_options, char **msg_out)
+{
+ (void)old_options;
+ (void)msg_out;
+ return 0;
+}
+
+static void
+test_options_trial_assign(void *arg)
+{
+ (void)arg;
+ setopt_err_t v;
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+ int r;
+
+ // replace options_act*() so that we don't actually launch tor here.
+ MOCK(options_act, mock_options_act);
+ MOCK(options_act_reversible, mock_options_act_reversible);
+
+ // Try assigning nothing; that should work.
+ v = options_trial_assign(lines, 0, &msg);
+ if (msg)
+ puts(msg);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(v, OP_EQ, SETOPT_OK);
+
+ // Assigning a nickname is okay
+ r = config_get_lines("Nickname Hemiramphinae", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ v = options_trial_assign(lines, 0, &msg);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(v, OP_EQ, SETOPT_OK);
+ tt_str_op(get_options()->Nickname, OP_EQ, "Hemiramphinae");
+ config_free_lines(lines);
+
+ // We can't change the User; that's a transition error.
+ r = config_get_lines("User Heraclitus", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ v = options_trial_assign(lines, 0, &msg);
+ tt_int_op(v, OP_EQ, SETOPT_ERR_TRANSITION);
+ tt_str_op(msg, OP_EQ, "While Tor is running, changing User is not allowed");
+ tor_free(msg);
+ config_free_lines(lines);
+
+ // We can't set the ORPort to nonsense: that's a validation error.
+ r = config_get_lines("ORPort fractabling planished", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ v = options_trial_assign(lines, 0, &msg);
+ tt_int_op(v, OP_EQ, SETOPT_ERR_PARSE); // (same error code for now)
+ tt_str_op(msg, OP_EQ, "Invalid ORPort configuration");
+ tor_free(msg);
+ config_free_lines(lines);
+
+ // We can't set UseBridges to a non-boolean: that's a parse error.
+ r = config_get_lines("UseBridges ambidextrous", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ v = options_trial_assign(lines, 0, &msg);
+ tt_int_op(v, OP_EQ, SETOPT_ERR_PARSE);
+ tt_str_op(msg, OP_EQ,
+ "Could not parse UseBridges: Unrecognized value ambidextrous. "
+ "Allowed values are 0 and 1.");
+ tor_free(msg);
+ config_free_lines(lines);
+
+ // this didn't change.
+ tt_str_op(get_options()->Nickname, OP_EQ, "Hemiramphinae");
+
+ done:
+ config_free_lines(lines);
+ tor_free(msg);
+ UNMOCK(options_act);
+ UNMOCK(options_act_reversible);
+}
+
+#ifndef COCCI
#define LOCAL_VALIDATE_TEST(name) \
{ "validate__" #name, test_options_validate__ ## name, TT_FORK, NULL, NULL }
+#endif
struct testcase_t options_tests[] = {
{ "validate", test_options_validate, TT_FORK, NULL, NULL },
@@ -4185,6 +4305,7 @@ struct testcase_t options_tests[] = {
LOCAL_VALIDATE_TEST(logs),
LOCAL_VALIDATE_TEST(authdir),
LOCAL_VALIDATE_TEST(relay_with_hidden_services),
+ LOCAL_VALIDATE_TEST(listen_ports),
LOCAL_VALIDATE_TEST(transproxy),
LOCAL_VALIDATE_TEST(exclude_nodes),
LOCAL_VALIDATE_TEST(node_families),
@@ -4218,5 +4339,10 @@ struct testcase_t options_tests[] = {
LOCAL_VALIDATE_TEST(virtual_addr),
LOCAL_VALIDATE_TEST(testing_options),
LOCAL_VALIDATE_TEST(accel),
+ { "init_logs/granularity", test_options_init_logs_granularity, TT_FORK,
+ NULL, NULL },
+ { "init_logs/quiet", test_options_init_logs_quiet, TT_FORK,
+ NULL, NULL },
+ { "trial_assign", test_options_trial_assign, TT_FORK, NULL, NULL },
END_OF_TESTCASES /* */
};
diff --git a/src/test/test_options_act.c b/src/test/test_options_act.c
new file mode 100644
index 0000000000..942584bffd
--- /dev/null
+++ b/src/test/test_options_act.c
@@ -0,0 +1,272 @@
+/* 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 */
+
+#define CONFIG_PRIVATE
+#include "core/or/or.h"
+#include "app/config/config.h"
+#include "lib/encoding/confline.h"
+
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+#include "test/test_helpers.h"
+
+#ifndef _WIN32
+#include <sys/stat.h>
+
+/**
+ * Check whether fname is readable. On success set
+ * *<b>is_group_readable_out</b> to as appropriate and return 0. On failure
+ * return -1.
+ */
+static int
+get_file_mode(const char *fname, unsigned *permissions_out)
+{
+ struct stat st;
+ int r = stat(fname, &st);
+ if (r < 0)
+ return -1;
+ *permissions_out = (unsigned) st.st_mode;
+ return 0;
+}
+#define assert_mode(fn,mask,expected) STMT_BEGIN \
+ unsigned mode_; \
+ int tmp_ = get_file_mode((fn), &mode_); \
+ if (tmp_ < 0) { \
+ TT_DIE(("Couldn't stat %s: %s", (fn), strerror(errno))); \
+ } \
+ if ((mode_ & (mask)) != (expected)) { \
+ TT_DIE(("Bad mode %o on %s", mode_, (fn))); \
+ } \
+ STMT_END
+#else /* defined(_WIN32) */
+/* "group-readable" isn't meaningful on windows */
+#define assert_mode(fn,mask,expected) STMT_NIL
+#endif /* !defined(_WIN32) */
+
+static or_options_t *mock_opts;
+static const or_options_t *
+mock_get_options(void)
+{
+ return mock_opts;
+}
+
+static void
+test_options_act_create_dirs(void *arg)
+{
+ (void)arg;
+ MOCK(get_options, mock_get_options);
+ char *msg = NULL;
+ or_options_t *opts = mock_opts = options_new();
+
+ /* We're testing options_create_directories(), which assumes that
+ validate_data_directories() has already been called, and all of
+ KeyDirectory, DataDirectory, and CacheDirectory are set. */
+
+ /* Success case 1: all directories are the default */
+ char *fn;
+ fn = tor_strdup(get_fname_rnd("ddir"));
+ opts->DataDirectory = tor_strdup(fn);
+ opts->CacheDirectory = tor_strdup(fn);
+ tor_asprintf(&opts->KeyDirectory, "%s/keys", fn);
+ opts->DataDirectoryGroupReadable = 1;
+ opts->CacheDirectoryGroupReadable = -1; /* default. */
+ int r = options_create_directories(&msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
+ assert_mode(opts->DataDirectory, 0777, 0750);
+ assert_mode(opts->KeyDirectory, 0777, 0700);
+ tor_free(fn);
+ tor_free(opts->KeyDirectory);
+ or_options_free(opts);
+
+ /* Success case 2: all directories are different. */
+ opts = mock_opts = options_new();
+ opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
+ opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
+ opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
+ opts->CacheDirectoryGroupReadable = 1; // cache directory group readable
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
+ assert_mode(opts->DataDirectory, 0777, 0700);
+ assert_mode(opts->KeyDirectory, 0777, 0700);
+ assert_mode(opts->CacheDirectory, 0777, 0750);
+ tor_free(fn);
+ or_options_free(opts);
+
+ /* Success case 3: all directories are the same. */
+ opts = mock_opts = options_new();
+ fn = tor_strdup(get_fname_rnd("ddir"));
+ opts->DataDirectory = tor_strdup(fn);
+ opts->CacheDirectory = tor_strdup(fn);
+ opts->KeyDirectory = tor_strdup(fn);
+ opts->DataDirectoryGroupReadable = 1;
+ opts->CacheDirectoryGroupReadable = -1; /* default. */
+ opts->KeyDirectoryGroupReadable = -1; /* default */
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
+ assert_mode(opts->DataDirectory, 0777, 0750);
+ assert_mode(opts->KeyDirectory, 0777, 0750);
+ assert_mode(opts->CacheDirectory, 0777, 0750);
+ tor_free(fn);
+ or_options_free(opts);
+
+ /* Failure case 1: Can't make datadir. */
+ opts = mock_opts = options_new();
+ opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
+ opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
+ opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
+ write_str_to_file(opts->DataDirectory, "foo", 0);
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
+ or_options_free(opts);
+ tor_free(msg);
+
+ /* Failure case 2: Can't make keydir. */
+ opts = mock_opts = options_new();
+ opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
+ opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
+ opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
+ write_str_to_file(opts->KeyDirectory, "foo", 0);
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
+ or_options_free(opts);
+ tor_free(msg);
+
+ /* Failure case 3: Can't make cachedir. */
+ opts = mock_opts = options_new();
+ opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
+ opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
+ opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
+ write_str_to_file(opts->CacheDirectory, "foo", 0);
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
+ tor_free(fn);
+ or_options_free(opts);
+ tor_free(msg);
+
+ done:
+ UNMOCK(get_options);
+ or_options_free(opts);
+ mock_opts = NULL;
+ tor_free(fn);
+ tor_free(msg);
+}
+
+static void
+test_options_act_log_transition(void *arg)
+{
+ (void)arg;
+ or_options_t *opts = mock_opts = options_new();
+ or_options_t *old_opts = NULL;
+ opts->LogTimeGranularity = 1000;
+ opts->SafeLogging_ = SAFELOG_SCRUB_ALL;
+ struct log_transaction_t *lt = NULL;
+ char *msg = NULL;
+ MOCK(get_options, mock_get_options);
+
+ tt_ptr_op(opts->Logs, OP_EQ, NULL);
+ config_line_append(&opts->Logs, "Log", "notice stdout");
+ lt = options_start_log_transaction(NULL, &msg);
+ tt_assert(lt);
+ tt_assert(!msg);
+
+ // commit, see that there is a change.
+ options_commit_log_transaction(lt);
+ lt=NULL;
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_NOTICE);
+
+ // Now drop to debug.
+ old_opts = opts;
+ opts = mock_opts = options_new();
+ opts->LogTimeGranularity = 1000;
+ opts->SafeLogging_ = SAFELOG_SCRUB_ALL;
+ config_line_append(&opts->Logs, "Log", "debug stdout");
+ lt = options_start_log_transaction(old_opts, &msg);
+ tt_assert(lt);
+ tt_assert(!msg);
+
+ setup_full_capture_of_logs(LOG_NOTICE);
+ options_commit_log_transaction(lt);
+ lt=NULL;
+ expect_single_log_msg_containing("may contain sensitive information");
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
+
+ // Turn off SafeLogging
+ or_options_free(old_opts);
+ mock_clean_saved_logs();
+ old_opts = opts;
+ opts = mock_opts = options_new();
+ opts->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ opts->LogTimeGranularity = 1000;
+ config_line_append(&opts->Logs, "Log", "debug stdout");
+ lt = options_start_log_transaction(old_opts, &msg);
+ tt_assert(lt);
+ tt_assert(!msg);
+ options_commit_log_transaction(lt);
+ lt=NULL;
+ expect_single_log_msg_containing("may contain sensitive information");
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
+
+ // Try rolling back.
+ or_options_free(old_opts);
+ mock_clean_saved_logs();
+ old_opts = opts;
+ opts = mock_opts = options_new();
+ opts->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ opts->LogTimeGranularity = 1000;
+ config_line_append(&opts->Logs, "Log", "notice stdout");
+ lt = options_start_log_transaction(old_opts, &msg);
+ tt_assert(lt);
+ tt_assert(!msg);
+ options_rollback_log_transaction(lt);
+ expect_no_log_entry();
+ lt = NULL;
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
+
+ // Now try some bad options.
+ or_options_free(opts);
+ mock_clean_saved_logs();
+ opts = mock_opts = options_new();
+ opts->LogTimeGranularity = 1000;
+ config_line_append(&opts->Logs, "Log", "warn blaznert");
+ lt = options_start_log_transaction(old_opts, &msg);
+ tt_assert(!lt);
+ tt_str_op(msg, OP_EQ, "Failed to init Log options. See logs for details.");
+ expect_single_log_msg_containing("Couldn't parse");
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
+
+ done:
+ UNMOCK(get_options);
+ or_options_free(opts);
+ or_options_free(old_opts);
+ tor_free(msg);
+ if (lt)
+ options_rollback_log_transaction(lt);
+ teardown_capture_of_logs();
+}
+
+#ifndef COCCI
+#define T(name) { #name, test_options_act_##name, TT_FORK, NULL, NULL }
+#endif
+
+struct testcase_t options_act_tests[] = {
+ T(create_dirs),
+ T(log_transition),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_parsecommon.c b/src/test/test_parsecommon.c
index 0c8f467a45..9c22266da1 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_parseconf.sh b/src/test/test_parseconf.sh
index eeb80cdfa7..4fe27d9f5d 100755
--- a/src/test/test_parseconf.sh
+++ b/src/test/test_parseconf.sh
@@ -8,15 +8,22 @@
# Valid configurations are tested with --dump-config, which parses and
# validates the configuration before writing it out. We then make sure that
# the result is what we expect, before parsing and dumping it again to make
-# sure that there is no change.
+# sure that there is no change. Optionally, we can also test the log messages
+# with --verify-config.
#
# Invalid configurations are tested with --verify-config, which parses
# and validates the configuration. We capture its output and make sure that
# it contains the error message we expect.
+#
+# When tor is compiled with different libraries or modules, some
+# configurations may have different results. We can specify these result
+# variants using additional result files.
# This script looks for its test cases as individual directories in
# src/test/conf_examples/. Each test may have these files:
#
+# Configuration Files
+#
# torrc -- Usually needed. This file is passed to Tor on the command line
# with the "-f" flag. (If you omit it, you'll test Tor's behavior when
# it receives a nonexistent configuration file.)
@@ -28,22 +35,79 @@
# cmdline -- Optional. If present, it contains command-line arguments that
# will be passed to Tor.
#
+# (included torrc files or directories) -- Optional. Additional files can be
+# included in configuration, using the "%include" directive. Files or
+# directories can be included in any of the config files listed above.
+# Include paths should be specified relative to the test case directory.
+#
+# Result Files
+#
# expected -- If this file is present, then it should be the expected result
# of "--dump-config short" for this test case. Exactly one of
# "expected" or "error" must be present, or the test will fail.
#
+# expected_log -- Optional. If this file is present, then it contains a regex
+# that must be matched by some line in the output of "--verify-config",
+# which must succeed. Only used if "expected" is also present.
+#
# error -- If this file is present, then it contains a regex that must be
# matched by some line in the output of "--verify-config", which must
# fail. Exactly one of "expected" or "error" must be present, or the
# test will fail.
+#
+# {expected,expected_log,error}_${TOR_LIBS_ENABLED}* -- If this file is
+# present, then the outcome is different when some optional libraries are
+# enabled. If there is no result file matching the exact list of enabled
+# libraries, the script searches for result files with one or more of
+# those libraries disabled. The search terminates at the standard result
+# file. If expected* is present, the script also searches for
+# expected_log*.
+#
+# For example:
+# A test that succeeds, regardless of any enabled libraries:
+# - expected
+# A test that has a different result if the nss library is enabled
+# (but the same result if any other library is enabled). We also check
+# the log output in this test:
+# - expected
+# - expected_log
+# - expected_nss
+# - expected_log_nss
+# A test that fails if the lzma and zstd modules are *not* enabled:
+# - error
+# - expected_lzma_zstd
+#
+# {expected,expected_log,error}*_no_${TOR_MODULES_DISABLED} -- If this file is
+# present, then the outcome is different when some modules are disabled.
+# If there is no result file matching the exact list of disabled modules,
+# the standard result file is used. If expected* is present, the script
+# also searches for expected_log*.
+#
+# For example:
+# A test that succeeds, regardless of any disabled modules:
+# - expected
+# A test that has a different result if the relay module is disabled
+# (but the same result if just the dirauth module is disabled):
+# - expected
+# - expected_no_relay_dirauth
+# A test that fails if the dirauth module is disabled:
+# - expected
+# - error_no_dirauth
+# - error_no_relay_dirauth
+# (Disabling the relay module also disables dirauth module. But we don't
+# want to encode that knowledge in this test script, so we supply a
+# separate result file for every combination of disabled modules that
+# has a different result.)
umask 077
set -e
+MYNAME="$0"
+
# emulate realpath(), in case coreutils or equivalent is not installed.
abspath() {
f="$*"
- if [ -d "$f" ]; then
+ if test -d "$f"; then
dir="$f"
base=""
else
@@ -55,8 +119,8 @@ abspath() {
}
# find the tor binary
-if [ $# -ge 1 ]; then
- TOR_BINARY="${1}"
+if test $# -ge 1; then
+ TOR_BINARY="$1"
shift
else
TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
@@ -64,6 +128,8 @@ fi
TOR_BINARY="$(abspath "$TOR_BINARY")"
+echo "Using Tor binary '$TOR_BINARY'."
+
# make a safe space for temporary files
DATA_DIR=$(mktemp -d -t tor_parseconf_tests.XXXXXX)
trap 'rm -rf "$DATA_DIR"' 0
@@ -90,7 +156,31 @@ else
EXITCODE=1
fi
-die() { echo "$1" >&2 ; exit "$EXITCODE"; }
+FINAL_EXIT=0
+NEXT_TEST=
+
+# Log a failure message to stderr, using $@ as a printf string and arguments
+# Set NEXT_TEST to "yes" and FINAL_EXIT to $EXITCODE.
+fail_printf()
+{
+ printf "FAIL: " >&2
+ # The first argument is a printf string, so this warning is spurious
+ # shellcheck disable=SC2059
+ printf "$@" >&2
+ NEXT_TEST="yes"
+ FINAL_EXIT=$EXITCODE
+}
+
+# Log a failure message to stderr, using $@ as a printf string and arguments
+# Exit with status $EXITCODE.
+die_printf()
+{
+ printf "FAIL: CRITICAL error in '%s':" "$MYNAME" >&2
+ # The first argument is a printf string, so this warning is spurious
+ # shellcheck disable=SC2059
+ printf "$@" >&2
+ exit $EXITCODE
+}
if test "$WINDOWS" = 1; then
FILTER="dos2unix"
@@ -98,20 +188,353 @@ else
FILTER="cat"
fi
-touch "${DATA_DIR}/EMPTY" || die "Couldn't create empty file."
+EMPTY="${DATA_DIR}/EMPTY"
+touch "$EMPTY" || die_printf "Couldn't create empty file '%s'.\\n" \
+ "$EMPTY"
+NON_EMPTY="${DATA_DIR}/NON_EMPTY"
+echo "This pattern should not match any log messages" \
+ > "$NON_EMPTY" || die_printf "Couldn't create non-empty file '%s'.\\n" \
+ "$NON_EMPTY"
+
+STANDARD_LIBS="libevent\\|openssl\\|zlib"
+# Lib names are restricted to [a-z0-9]* at the moment
+# We don't actually want to support foreign accents here
+# shellcheck disable=SC2018,SC2019
+TOR_LIBS_ENABLED="$("$TOR_BINARY" --verify-config \
+ -f "$EMPTY" --defaults-torrc "$EMPTY" \
+ | sed -n 's/.* Tor .* running on .* with\(.*\)\./\1/p' \
+ | tr 'A-Z' 'a-z' | tr ',' '\n' \
+ | grep -v "$STANDARD_LIBS" | grep -v "n/a" \
+ | sed 's/\( and\)* \(lib\)*\([a-z0-9]*\) .*/\3/' \
+ | sort | tr '\n' '_')"
+# Remove the last underscore, if there is one
+TOR_LIBS_ENABLED=${TOR_LIBS_ENABLED%_}
+
+# If we ever have more than 3 optional libraries, we'll need more code here
+TOR_LIBS_ENABLED_COUNT="$(echo "$TOR_LIBS_ENABLED_SEARCH" \
+ | tr ' ' '\n' | wc -l)"
+if test "$TOR_LIBS_ENABLED_COUNT" -gt 3; then
+ die_printf "Can not handle more than 3 optional libraries.\\n"
+fi
+# Brute-force the combinations of libraries
+TOR_LIBS_ENABLED_SEARCH_3="$(echo "$TOR_LIBS_ENABLED" \
+ | sed -n \
+ 's/^\([^_]*\)_\([^_]*\)_\([^_]*\)$/_\1_\2 _\1_\3 _\2_\3 _\1 _\2 _\3/p')"
+TOR_LIBS_ENABLED_SEARCH_2="$(echo "$TOR_LIBS_ENABLED" \
+ | sed -n 's/^\([^_]*\)_\([^_]*\)$/_\1 _\2/p')"
+TOR_LIBS_ENABLED_SEARCH="_$TOR_LIBS_ENABLED \
+ $TOR_LIBS_ENABLED_SEARCH_3 \
+ $TOR_LIBS_ENABLED_SEARCH_2"
+TOR_LIBS_ENABLED_SEARCH="$(echo "$TOR_LIBS_ENABLED_SEARCH" | tr ' ' '\n' \
+ | grep -v '^_*$' | tr '\n' ' ')"
+
+TOR_MODULES_DISABLED="$("$TOR_BINARY" --list-modules | grep ': no' \
+ | cut -d ':' -f1 | sort | tr '\n' '_')"
+# Remove the last underscore, if there is one
+TOR_MODULES_DISABLED=${TOR_MODULES_DISABLED%_}
+
+echo "Tor is configured with:"
+echo "Optional Libraries: ${TOR_LIBS_ENABLED:-(None)}"
+if test "$TOR_LIBS_ENABLED"; then
+ echo "Optional Library Search List: $TOR_LIBS_ENABLED_SEARCH"
+fi
+echo "Disabled Modules: ${TOR_MODULES_DISABLED:-(None)}"
+
+# Yes, unix uses "0" for a successful command
+TRUE=0
+FALSE=1
+
+# Run tor --verify-config on the torrc $1, and defaults torrc $2, which may
+# be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted.
+# Send tor's standard output to stderr.
+log_verify_config()
+{
+ # show the command we're about to execute
+ # log_verify_config() is only called when we've failed
+ printf "Tor --verify-config said:\\n" >&2
+ printf "$ %s %s %s %s %s %s %s\\n" \
+ "$TOR_BINARY" --verify-config \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ "$3" \
+ >&2
+ # We need cmdline unquoted
+ # shellcheck disable=SC2086
+ "$TOR_BINARY" --verify-config \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ $3 \
+ >&2 \
+ || true
+}
+
+# Run "tor --dump-config short" on the torrc $1, and defaults torrc $2, which
+# may be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted. Send tor's standard output to $4.
+#
+# Set $FULL_TOR_CMD to the tor command line that was executed.
+#
+# If tor fails, fail_printf() using the file name $5, and context $6,
+# which may be an empty string. Then run log_verify_config().
+dump_config()
+{
+ if test "$6"; then
+ CONTEXT=" $6"
+ else
+ CONTEXT=""
+ fi
+
+ # keep the command we're about to execute, and show if it we fail
+ FULL_TOR_CMD=$(printf "$ %s %s %s %s %s %s %s %s" \
+ "$TOR_BINARY" --dump-config short \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ "$3"
+ )
+ # We need cmdline unquoted
+ # shellcheck disable=SC2086
+ if ! "$TOR_BINARY" --dump-config short \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ $3 \
+ > "$4"; then
+ fail_printf "'%s': Tor --dump-config reported an error%s:\\n%s\\n" \
+ "$5" \
+ "$CONTEXT" \
+ "$FULL_TOR_CMD"
+ log_verify_config "$1" \
+ "$2" \
+ "$3"
+ fi
+}
+
+# Run "$FILTER" on the input $1.
+# Send the standard output to $2.
+# If tor fails, log a failure message using the file name $3, and context $4,
+# which may be an empty string.
+filter()
+{
+ if test "$4"; then
+ CONTEXT=" $4"
+ else
+ CONTEXT=""
+ fi
+
+ "$FILTER" "$1" \
+ > "$2" \
+ || fail_printf "'%s': Filter '%s' reported an error%s.\\n" \
+ "$3" \
+ "$FILTER" \
+ "$CONTEXT"
+}
+
+# Compare the expected file $1, and output file $2.
+#
+# If they are different, fail. Log the differences between the files.
+# Run log_verify_config() with torrc $3, defaults torrc $4, and command
+# line $5, to log Tor's error messages.
+#
+# If the file contents are identical, returns true. Otherwise, return false.
+#
+# Log failure messages using fail_printf(), with the expected file name,
+# context $6, which may be an empty string, and the tor command line $7.
+check_diff()
+{
+ if test "$6"; then
+ CONTEXT=" $6"
+ else
+ CONTEXT=""
+ fi
+
+ if cmp "$1" "$2" > /dev/null; then
+ return "$TRUE"
+ else
+ fail_printf "'%s': Tor --dump-config said%s:\\n%s\\n" \
+ "$1" \
+ "$CONTEXT" \
+ "$7"
+ diff -u "$1" "$2" >&2 \
+ || true
+ log_verify_config "$3" \
+ "$4" \
+ "$5"
+ return "$FALSE"
+ fi
+}
+
+# Run "tor --dump-config short" on the torrc $1, and defaults torrc $2, which
+# may be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted. Send tor's standard output to $4, after running $FILTER
+# on it.
+#
+# If tor fails, run log_verify_config().
+#
+# Compare the expected file $5, and output file. If they are different, fail.
+# If this is the first step that failed in this test, run log_verify_config().
+#
+# If the file contents are identical, returns true. Otherwise, return false,
+# and log the differences between the files.
+#
+# Log failure messages using fail_printf(), with the expected file name, and
+# context $6, which may be an empty string.
+check_dump_config()
+{
+ OUTPUT="$4"
+ OUTPUT_RAW="${OUTPUT}_raw"
+
+ FULL_TOR_CMD=
+ dump_config "$1" \
+ "$2" \
+ "$3" \
+ "$OUTPUT_RAW" \
+ "$5" \
+ "$6"
+
+ filter "$OUTPUT_RAW" \
+ "$OUTPUT" \
+ "$5" \
+ "$6"
+
+ if check_diff "$5" \
+ "$OUTPUT" \
+ "$1" \
+ "$2" \
+ "$3" \
+ "$6" \
+ "$FULL_TOR_CMD"; then
+ return "$TRUE"
+ else
+ return "$FALSE"
+ fi
+}
+
+# Check if $1 is an empty file.
+# If it is, fail_printf() using $2 as the type of file.
+# Returns true if the file is empty, false otherwise.
+check_empty_pattern()
+{
+ if ! test -s "$1"; then
+ fail_printf "%s file '%s' is empty, and will match any output.\\n" \
+ "$2" \
+ "$1"
+ return "$TRUE"
+ else
+ return "$FALSE"
+ fi
+}
+
+# Run tor --verify-config on the torrc $1, and defaults torrc $2, which may
+# be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted. Send tor's standard output to $4.
+#
+# Set $FULL_TOR_CMD to the tor command line that was executed.
+#
+# If tor's exit status does not match the boolean $5, fail_printf()
+# using the file name $6, and context $7, which is required.
+verify_config()
+{
+ RESULT=$TRUE
+
+ # keep the command we're about to execute, and show if it we fail
+ FULL_TOR_CMD=$(printf "$ %s %s %s %s %s %s %s" \
+ "$TOR_BINARY" --verify-config \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ "$3"
+ )
+ # We need cmdline unquoted
+ # shellcheck disable=SC2086
+ "$TOR_BINARY" --verify-config \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ $3 \
+ > "$4" || RESULT=$FALSE
+
+ # Convert the actual and expected results to boolean, and compare
+ if test $((! (! RESULT))) -ne $((! (! $5))); then
+ fail_printf "'%s': Tor --verify-config did not %s:\\n%s\\n" \
+ "$6" \
+ "$7" \
+ "$FULL_TOR_CMD"
+ cat "$4" >&2
+ fi
+}
+
+# Check for the patterns in the match file $1, in the output file $2.
+# Uses grep with the entire contents of the match file as the pattern.
+# (Not "grep -f".)
+#
+# If the pattern does not match any lines in the output file, fail.
+# Log the pattern, and the entire contents of the output file.
+#
+# Log failure messages using fail_printf(), with the match file name,
+# context $3, and tor command line $4, which are required.
+check_pattern()
+{
+ expect_log="$(cat "$1")"
+ if ! grep "$expect_log" "$2" > /dev/null; then
+ fail_printf "Expected %s '%s':\\n%s\\n" \
+ "$3" \
+ "$1" \
+ "$expect_log"
+ printf "Tor --verify-config said:\\n%s\\n" \
+ "$4" >&2
+ cat "$2" >&2
+ fi
+}
+
+# Run tor --verify-config on the torrc $1, and defaults torrc $2, which may
+# be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted. Send tor's standard output to $4.
+#
+# If tor's exit status does not match the boolean $5, fail.
+#
+# Check for the patterns in the match file $6, in the output file.
+# Uses grep with the entire contents of the match file as the pattern.
+# (Not "grep -f".) The match file must not be empty.
+#
+# If the pattern does not match any lines in the output file, fail.
+# Log the pattern, and the entire contents of the output file.
+#
+# Log failure messages using fail_printf(), with the match file name,
+# and context $7, which is required.
+check_verify_config()
+{
+ if check_empty_pattern "$6" "$7"; then
+ return
+ fi
+
+ FULL_TOR_CMD=
+ verify_config "$1" \
+ "$2" \
+ "$3" \
+ "$4" \
+ "$5" \
+ "$6" \
+ "$7"
+
+ check_pattern "$6" \
+ "$4" \
+ "$7" \
+ "$FULL_TOR_CMD"
+}
for dir in "${EXAMPLEDIR}"/*; do
- if ! test -d "${dir}"; then
+ NEXT_TEST=
+
+ if ! test -d "$dir"; then
# Only count directories.
continue
fi
testname="$(basename "${dir}")"
# We use printf since "echo -n" is not standard
- printf "%s: " "$testname"
+ printf "%s: " \
+ "$testname"
PREV_DIR="$(pwd)"
- cd "${dir}"
+ cd "$dir"
if test -f "./torrc.defaults"; then
DEFAULTS="./torrc.defaults"
@@ -125,80 +548,108 @@ for dir in "${EXAMPLEDIR}"/*; do
CMDLINE=""
fi
- if test -f "./expected"; then
- if test -f "./error"; then
- echo "FAIL: Found both ${dir}/expected and ${dir}/error."
- echo "(Only one of these files should exist.)"
- exit $EXITCODE
- fi
+ EXPECTED=
+ EXPECTED_LOG=
+ ERROR=
+ # Search for a custom result file for any combination of enabled optional
+ # libraries
+ # The libs in the list are [A-Za-z0-9_]* and space-separated.
+ # shellcheck disable=SC2086
+ for lib_suffix in $TOR_LIBS_ENABLED_SEARCH ""; do
+ # Search for a custom result file for any disabled modules
+ for mod_suffix in "_no_${TOR_MODULES_DISABLED}" ""; do
+ suffix="${lib_suffix}${mod_suffix}"
- # This case should succeed: run dump-config and see if it does.
+ if test -f "./expected${suffix}"; then
- "${TOR_BINARY}" -f "./torrc" \
- --defaults-torrc "${DEFAULTS}" \
- --dump-config short \
- ${CMDLINE} \
- | "${FILTER}" > "${DATA_DIR}/output.${testname}" \
- || die "Failure: Tor exited."
+ # Check for broken configs
+ if test -f "./error${suffix}"; then
+ fail_printf "Found both '%s' and '%s'.%s\\n" \
+ "${dir}/expected${suffix}" \
+ "${dir}/error${suffix}" \
+ "(Only one of these files should exist.)"
+ break
+ fi
- if cmp "./expected" "${DATA_DIR}/output.${testname}">/dev/null ; then
- # Check round-trip.
- "${TOR_BINARY}" -f "${DATA_DIR}/output.${testname}" \
- --defaults-torrc "${DATA_DIR}/empty" \
- --dump-config short \
- | "${FILTER}" \
- > "${DATA_DIR}/output_2.${testname}" \
- || die "Failure: Tor exited on round-trip."
-
- if ! cmp "${DATA_DIR}/output.${testname}" \
- "${DATA_DIR}/output_2.${testname}"; then
- echo "Failure: did not match on round-trip."
- exit $EXITCODE
- fi
+ EXPECTED="./expected${suffix}"
+ if test -f "./expected_log${suffix}"; then
+ EXPECTED_LOG="./expected_log${suffix}"
+ fi
+ break
- echo "OK"
- else
- echo "FAIL"
- if test "$(wc -c < "${DATA_DIR}/output.${testname}")" = 0; then
- # There was no output -- probably we failed.
- "${TOR_BINARY}" -f "./torrc" \
- --defaults-torrc "${DEFAULTS}" \
- --verify-config \
- ${CMDLINE} || true
+ elif test -f "./error${suffix}"; then
+ ERROR="./error${suffix}"
+ break
fi
- diff -u "./expected" "${DATA_DIR}/output.${testname}" || /bin/true
- exit $EXITCODE
+ done
+
+ # Exit as soon as the inner loop finds a file, or fails
+ if test -f "$EXPECTED" || test -f "$ERROR" || test "$NEXT_TEST"; then
+ break
fi
+ done
- elif test -f "./error"; then
- # This case should fail: run verify-config and see if it does.
+ if test "$NEXT_TEST"; then
+ # The test failed inside the file search loop: go to the next test
+ continue
+ elif test -f "$EXPECTED"; then
+ # This case should succeed: run dump-config and see if it does.
+
+ if check_dump_config "./torrc" \
+ "$DEFAULTS" \
+ "$CMDLINE" \
+ "${DATA_DIR}/output.${testname}" \
+ "$EXPECTED" \
+ ""; then
+ # Check round-trip.
+ check_dump_config "${DATA_DIR}/output.${testname}" \
+ "$EMPTY" \
+ "" \
+ "${DATA_DIR}/output_2.${testname}" \
+ "$EXPECTED" \
+ "on round-trip" || true
+ fi
- "${TOR_BINARY}" --verify-config \
- -f ./torrc \
- --defaults-torrc "${DEFAULTS}" \
- ${CMDLINE} \
- > "${DATA_DIR}/output.${testname}" \
- && die "Failure: Tor did not report an error."
+ if test -f "$EXPECTED_LOG"; then
+ # This case should succeed: run verify-config and see if it does.
- expect_err="$(cat ./error)"
- if grep "${expect_err}" "${DATA_DIR}/output.${testname}" >/dev/null; then
- echo "OK"
+ check_verify_config "./torrc" \
+ "$DEFAULTS" \
+ "$CMDLINE" \
+ "${DATA_DIR}/output_log.${testname}" \
+ "$TRUE" \
+ "$EXPECTED_LOG" \
+ "log success"
else
- echo "FAIL"
- echo "Expected error: ${expect_err}"
- echo "Tor said:"
- cat "${DATA_DIR}/output.${testname}"
- exit $EXITCODE
+ printf "\\nNOTICE: Missing '%s_log' file:\\n" \
+ "$EXPECTED" >&2
+ log_verify_config "./torrc" \
+ "$DEFAULTS" \
+ "$CMDLINE"
fi
+ elif test -f "$ERROR"; then
+ # This case should fail: run verify-config and see if it does.
+
+ check_verify_config "./torrc" \
+ "$DEFAULTS" \
+ "$CMDLINE" \
+ "${DATA_DIR}/output.${testname}" \
+ "$FALSE" \
+ "$ERROR" \
+ "log error"
else
# This case is not actually configured with a success or a failure.
# call that an error.
+ fail_printf "Did not find ${dir}/*expected or ${dir}/*error.\\n"
+ fi
- echo "FAIL: Did not find ${dir}/expected or ${dir}/error."
- exit $EXITCODE
+ if test -z "$NEXT_TEST"; then
+ echo "OK"
fi
- cd "${PREV_DIR}"
+ cd "$PREV_DIR"
done
+
+exit "$FINAL_EXIT"
diff --git a/src/test/test_pem.c b/src/test/test_pem.c
index 9eb99181e2..9772be124b 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 267156a908..b7f1785805 100644
--- a/src/test/test_periodic_event.c
+++ b/src/test/test_periodic_event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index e58bb3d174..7949e90e9e 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
@@ -62,8 +62,8 @@ test_policy_summary_helper_family_flags(const char *policy_str,
short_policy_t *short_policy = NULL;
int success = 0;
- line.key = (char*)"foo";
- line.value = (char *)policy_str;
+ line.key = (char *) "foo";
+ line.value = (char *) policy_str;
line.next = NULL;
r = policies_parse_exit_policy(&line, &policy,
@@ -2124,20 +2124,6 @@ test_policies_fascist_firewall_allows_address(void *arg)
teardown_capture_of_logs(); \
STMT_END
-/** Mock the preferred address function to return zero (prefer IPv4). */
-static int
-mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4(void)
-{
- return 0;
-}
-
-/** Mock the preferred address function to return one (prefer IPv6). */
-static int
-mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv6(void)
-{
- return 1;
-}
-
/** Run unit tests for fascist_firewall_choose_address */
static void
test_policies_fascist_firewall_choose_address(void *arg)
@@ -2536,42 +2522,6 @@ test_policies_fascist_firewall_choose_address(void *arg)
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
ipv4_dir_ap);
- /* Test ClientAutoIPv6ORPort and pretend we prefer IPv4. */
- memset(&mock_options, 0, sizeof(or_options_t));
- mock_options.ClientAutoIPv6ORPort = 1;
- mock_options.ClientUseIPv4 = 1;
- mock_options.ClientUseIPv6 = 1;
- MOCK(fascist_firewall_rand_prefer_ipv6_addr,
- mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4);
- /* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
- &mock_options);
-
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
- ipv4_or_ap);
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
- ipv4_or_ap);
-
- UNMOCK(fascist_firewall_rand_prefer_ipv6_addr);
-
- /* Test ClientAutoIPv6ORPort and pretend we prefer IPv6. */
- memset(&mock_options, 0, sizeof(or_options_t));
- mock_options.ClientAutoIPv6ORPort = 1;
- mock_options.ClientUseIPv4 = 1;
- mock_options.ClientUseIPv6 = 1;
- MOCK(fascist_firewall_rand_prefer_ipv6_addr,
- mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv6);
- /* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
- &mock_options);
-
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
- ipv6_or_ap);
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
- ipv6_or_ap);
-
- UNMOCK(fascist_firewall_rand_prefer_ipv6_addr);
-
/* Test firewall_choose_address_ls(). To do this, we make a fake link
* specifier. */
smartlist_t *lspecs = smartlist_new(),
diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c
index 0ecbf65f41..541a81df3a 100644
--- a/src/test/test_prob_distr.c
+++ b/src/test/test_prob_distr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -893,7 +893,7 @@ test_uniform_interval(void *arg)
*
* NIST/SEMATECH e-Handbook of Statistical Methods, Section
* 1.3.6.7.4 `Critical Values of the Chi-Square Distribution',
- * <http://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>,
+ * <https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>,
* retrieved 2018-10-28.
*/
@@ -946,7 +946,7 @@ psi_test(const size_t C[PSI_DF], const double logP[PSI_DF], size_t N)
static bool
test_stochastic_geometric_impl(double p)
{
- const struct geometric geometric = {
+ const struct geometric_t geometric = {
.base = GEOMETRIC(geometric),
.p = p,
};
@@ -1012,7 +1012,8 @@ test_stochastic_geometric_impl(double p)
* +inf, and x_i = i*(hi - lo)/(n - 2).
*/
static void
-bin_cdfs(const struct dist *dist, double lo, double hi, double *logP, size_t n)
+bin_cdfs(const struct dist_t *dist, double lo, double hi, double *logP,
+ size_t n)
{
#define CDF(x) dist_cdf(dist, x)
#define SF(x) dist_sf(dist, x)
@@ -1059,7 +1060,8 @@ bin_cdfs(const struct dist *dist, double lo, double hi, double *logP, size_t n)
* +inf, and x_i = i*(hi - lo)/(n - 2).
*/
static void
-bin_samples(const struct dist *dist, double lo, double hi, size_t *C, size_t n)
+bin_samples(const struct dist_t *dist, double lo, double hi, size_t *C,
+ size_t n)
{
const double w = (hi - lo)/(n - 2);
size_t i;
@@ -1088,7 +1090,7 @@ bin_samples(const struct dist *dist, double lo, double hi, size_t *C, size_t n)
* 0.01^2 = 0.0001.
*/
static bool
-test_psi_dist_sample(const struct dist *dist)
+test_psi_dist_sample(const struct dist_t *dist)
{
double logP[PSI_DF] = {0};
unsigned ntry = NTRIALS, npass = 0;
@@ -1134,32 +1136,32 @@ test_stochastic_uniform(void *arg)
{
(void) arg;
- const struct uniform uniform01 = {
+ const struct uniform_t uniform01 = {
.base = UNIFORM(uniform01),
.a = 0,
.b = 1,
};
- const struct uniform uniform_pos = {
+ const struct uniform_t uniform_pos = {
.base = UNIFORM(uniform_pos),
.a = 1.23,
.b = 4.56,
};
- const struct uniform uniform_neg = {
+ const struct uniform_t uniform_neg = {
.base = UNIFORM(uniform_neg),
.a = -10,
.b = -1,
};
- const struct uniform uniform_cross = {
+ const struct uniform_t uniform_cross = {
.base = UNIFORM(uniform_cross),
.a = -1.23,
.b = 4.56,
};
- const struct uniform uniform_subnormal = {
+ const struct uniform_t uniform_subnormal = {
.base = UNIFORM(uniform_subnormal),
.a = 4e-324,
.b = 4e-310,
};
- const struct uniform uniform_subnormal_cross = {
+ const struct uniform_t uniform_subnormal_cross = {
.base = UNIFORM(uniform_subnormal_cross),
.a = -4e-324,
.b = 4e-310,
@@ -1189,7 +1191,7 @@ test_stochastic_uniform(void *arg)
static bool
test_stochastic_logistic_impl(double mu, double sigma)
{
- const struct logistic dist = {
+ const struct logistic_t dist = {
.base = LOGISTIC(dist),
.mu = mu,
.sigma = sigma,
@@ -1202,7 +1204,7 @@ test_stochastic_logistic_impl(double mu, double sigma)
static bool
test_stochastic_log_logistic_impl(double alpha, double beta)
{
- const struct log_logistic dist = {
+ const struct log_logistic_t dist = {
.base = LOG_LOGISTIC(dist),
.alpha = alpha,
.beta = beta,
@@ -1215,27 +1217,29 @@ test_stochastic_log_logistic_impl(double alpha, double beta)
static bool
test_stochastic_weibull_impl(double lambda, double k)
{
- const struct weibull dist = {
+ const struct weibull_t dist = {
.base = WEIBULL(dist),
.lambda = lambda,
.k = k,
};
+// clang-format off
/*
* XXX Consider applying a Tiku-Singh test:
*
* M.L. Tiku and M. Singh, `Testing the two-parameter
* Weibull distribution', Communications in Statistics --
* Theory and Methods A10(9), 1981, 907--918.
- *https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true
+https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true
*/
+// clang-format on
return test_psi_dist_sample(&dist.base);
}
static bool
test_stochastic_genpareto_impl(double mu, double sigma, double xi)
{
- const struct genpareto dist = {
+ const struct genpareto_t dist = {
.base = GENPARETO(dist),
.mu = mu,
.sigma = sigma,
diff --git a/src/test/test_process.c b/src/test/test_process.c
index 7836312761..c1da6db278 100644
--- a/src/test/test_process.c
+++ b/src/test/test_process.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 7dc9abde31..14865cff13 100644
--- a/src/test/test_process_descs.c
+++ b/src/test/test_process_descs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019, The Tor Project, Inc. */
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -20,13 +20,10 @@ test_process_descs_versions(void *arg)
{ "Tor 0.1.2.3-alpha", true },
// a non-tor program: don't reject.
{ "Wombat 0.1.2.3-alpha", false },
- // a slightly old version: reject
- { "Tor 0.2.9.4-alpha", true },
- // a slightly old version: just new enough to support.
- { "Tor 0.2.9.5-alpha", false },
- // a newer 0.2.9 version: supported.
- { "Tor 0.2.9.100", false },
// some unsupported versions: reject.
+ { "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 },
@@ -37,11 +34,17 @@ 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.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 },
// new enough to be supported
{ "Tor 0.3.5.7", false },
{ "Tor 0.3.5.8", false },
- { "Tor 0.4.0.1-alpha", false },
{ "Tor 0.4.1.5", false },
+ { "Tor 0.4.2.1-alpha", false },
+ { "Tor 0.4.2.4-rc", false },
+ { "Tor 0.4.3.0-alpha-dev", 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 f311e8b293..f74d4adc9a 100644
--- a/src/test/test_process_slow.c
+++ b/src/test/test_process_slow.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_procmon.c b/src/test/test_procmon.c
index e23578f4fd..1752008f63 100644
--- a/src/test/test_procmon.c
+++ b/src/test/test_procmon.c
@@ -1,7 +1,6 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define PROCMON_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
#include "test/test.h"
@@ -10,8 +9,6 @@
#include "test/log_test_helpers.h"
-#define NS_MODULE procmon
-
struct event_base;
static void
diff --git a/src/test/test_proto_haproxy.c b/src/test/test_proto_haproxy.c
new file mode 100644
index 0000000000..040354ec1f
--- /dev/null
+++ b/src/test/test_proto_haproxy.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_proto_haproxy.c
+ * \brief Tests for our HAProxy protocol parser code
+ */
+
+#define PROTO_HAPROXY_PRIVATE
+
+#include "test/test.h"
+#include "core/proto/proto_haproxy.h"
+#include "test/log_test_helpers.h"
+
+static void
+test_format_proxy_header_line(void *arg)
+{
+ tor_addr_t addr;
+ tor_addr_port_t *addr_port = NULL;
+ char *output = NULL;
+
+ (void) arg;
+
+ /* IPv4 address. */
+ tor_addr_parse(&addr, "192.168.1.2");
+ addr_port = tor_addr_port_new(&addr, 8000);
+ output = haproxy_format_proxy_header_line(addr_port);
+
+ tt_str_op(output, OP_EQ, "PROXY TCP4 0.0.0.0 192.168.1.2 0 8000\r\n");
+
+ tor_free(addr_port);
+ tor_free(output);
+
+ /* IPv6 address. */
+ tor_addr_parse(&addr, "123:45:6789::5005:11");
+ addr_port = tor_addr_port_new(&addr, 8000);
+ output = haproxy_format_proxy_header_line(addr_port);
+
+ tt_str_op(output, OP_EQ, "PROXY TCP6 :: 123:45:6789::5005:11 0 8000\r\n");
+
+ tor_free(addr_port);
+ tor_free(output);
+
+ /* UNIX socket address. */
+ memset(&addr, 0, sizeof(addr));
+ addr.family = AF_UNIX;
+ addr_port = tor_addr_port_new(&addr, 8000);
+ output = haproxy_format_proxy_header_line(addr_port);
+
+ /* If it's not an IPv4 or IPv6 address, haproxy_format_proxy_header_line
+ * must return NULL. */
+ tt_ptr_op(output, OP_EQ, NULL);
+
+ tor_free(addr_port);
+ tor_free(output);
+
+ done:
+ tor_free(addr_port);
+ tor_free(output);
+}
+
+struct testcase_t proto_haproxy_tests[] = {
+ { "format_proxy_header_line", test_format_proxy_header_line, 0, NULL, NULL },
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_proto_http.c b/src/test/test_proto_http.c
index f9339e8dd3..481d78b2c1 100644
--- a/src/test/test_proto_http.c
+++ b/src/test/test_proto_http.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, 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 18669a7772..64bf5c4993 100644
--- a/src/test/test_proto_misc.c
+++ b/src/test/test_proto_misc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index 0254501165..8fccae1a45 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -1,7 +1,8 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define PROTOVER_PRIVATE
+#define DIRVOTE_PRIVATE
#include "orconfig.h"
#include "test/test.h"
@@ -12,6 +13,8 @@
#include "core/or/connection_or.h"
#include "lib/tls/tortls.h"
+#include "feature/dirauth/dirvote.h"
+
static void
test_protover_parse(void *arg)
{
@@ -314,6 +317,7 @@ test_protover_all_supported(void *arg)
tt_assert(protover_all_supported("Fribble=", &msg));
tt_ptr_op(msg, OP_EQ, NULL);
+#ifndef ALL_BUGS_ARE_FATAL
/* If we get a completely unparseable list, protover_all_supported should
* hit a fatal assertion for BUG(entries == NULL). */
tor_capture_bugs_(1);
@@ -325,9 +329,10 @@ test_protover_all_supported(void *arg)
tor_capture_bugs_(1);
tt_assert(protover_all_supported("Sleen=1-4294967295", &msg));
tor_end_capture_bugs_();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Protocol name too long */
-#ifndef HAVE_RUST // XXXXXX ?????
+#if !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL)
tor_capture_bugs_(1);
tt_assert(protover_all_supported(
"DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@@ -335,7 +340,7 @@ test_protover_all_supported(void *arg)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaa=1-65536", &msg));
tor_end_capture_bugs_();
-#endif /* !defined(HAVE_RUST) */
+#endif /* !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) */
done:
tor_end_capture_bugs_();
@@ -634,6 +639,43 @@ test_protover_vote_roundtrip(void *args)
tor_free(result);
}
+static void
+test_protover_vote_roundtrip_ours(void *args)
+{
+ (void) args;
+ const char *examples[] = {
+ protover_get_supported_protocols(),
+ DIRVOTE_RECOMMEND_RELAY_PROTO,
+ DIRVOTE_RECOMMEND_CLIENT_PROTO,
+ DIRVOTE_REQUIRE_RELAY_PROTO,
+ DIRVOTE_REQUIRE_CLIENT_PROTO,
+ };
+ unsigned u;
+ smartlist_t *votes = smartlist_new();
+ char *result = NULL;
+
+ for (u = 0; u < ARRAY_LENGTH(examples); ++u) {
+ tt_assert(examples[u]);
+ const char *input = examples[u];
+ const char *expected_output = examples[u];
+
+ smartlist_add(votes, (void*)input);
+ result = protover_compute_vote(votes, 1);
+ if (expected_output != NULL) {
+ tt_str_op(result, OP_EQ, expected_output);
+ } else {
+ tt_str_op(result, OP_EQ, "");
+ }
+
+ smartlist_clear(votes);
+ tor_free(result);
+ }
+
+ done:
+ smartlist_free(votes);
+ tor_free(result);
+}
+
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -647,5 +689,6 @@ struct testcase_t protover_tests[] = {
PV_TEST(supports_version, 0),
PV_TEST(supported_protocols, 0),
PV_TEST(vote_roundtrip, 0),
+ PV_TEST(vote_roundtrip_ours, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index 8f3ce03c42..893fec3674 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -1,17 +1,16 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define PT_PRIVATE
-#define UTIL_PRIVATE
#define STATEFILE_PRIVATE
#define CONTROL_EVENTS_PRIVATE
#define PROCESS_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "feature/control/control.h"
#include "feature/control/control_events.h"
#include "feature/client/transports.h"
@@ -580,8 +579,10 @@ test_get_pt_proxy_uri(void *arg)
tor_free(uri);
}
+#ifndef COCCI
#define PT_LEGACY(name) \
- { #name, test_pt_ ## name , 0, NULL, NULL }
+ { (#name), test_pt_ ## name , 0, NULL, NULL }
+#endif
struct testcase_t pt_tests[] = {
PT_LEGACY(parsing),
diff --git a/src/test/test_ptr_slow.c b/src/test/test_ptr_slow.c
index 76bdbf1891..25b893c4c0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 021323fbf1..5f9005926c 100644
--- a/src/test/test_pubsub_build.c
+++ b/src/test/test_pubsub_build.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, 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 73c7c9f540..3054db885d 100644
--- a/src/test/test_pubsub_msg.c
+++ b/src/test/test_pubsub_msg.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DISPATCH_PRIVATE
diff --git a/src/test/test_rebind.py b/src/test/test_rebind.py
index c9b9200b2d..3fc3deb68e 100644
--- a/src/test/test_rebind.py
+++ b/src/test/test_rebind.py
@@ -1,4 +1,7 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
import errno
import logging
diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh
index d6d9d86668..879008c1c1 100755
--- a/src/test/test_rebind.sh
+++ b/src/test/test_rebind.sh
@@ -1,7 +1,23 @@
#!/bin/sh
+umask 077
+set -e
set -x
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
UNAME_OS=$(uname -s | cut -d_ -f1)
if test "$UNAME_OS" = 'CYGWIN' || \
test "$UNAME_OS" = 'MSYS' || \
@@ -12,6 +28,23 @@ if test "$UNAME_OS" = 'CYGWIN' || \
fi
fi
+# find the tor binary
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "${TOR_BINARY}" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
+fi
+
tmpdir=
clean () {
if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then
@@ -30,6 +63,6 @@ elif [ ! -d "$tmpdir" ]; then
exit 3
fi
-"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/test_rebind.py" "${TESTING_TOR_BINARY}" "$tmpdir"
+"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/test_rebind.py" "${TOR_BINARY}" "$tmpdir"
exit $?
diff --git a/src/test/test_relay.c b/src/test/test_relay.c
index 0b7a7be332..066aeaa7b3 100644
--- a/src/test/test_relay.c
+++ b/src/test/test_relay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
@@ -10,7 +10,6 @@
#include "core/or/channeltls.h"
#include "feature/stats/rephist.h"
#include "core/or/relay.h"
-#include "feature/stats/rephist.h"
#include "lib/container/order.h"
/* For init/free stuff */
#include "core/or/scheduler.h"
@@ -21,42 +20,10 @@
/* Test suite stuff */
#include "test/test.h"
#include "test/fakechans.h"
-
-static or_circuit_t * new_fake_orcirc(channel_t *nchan, channel_t *pchan);
+#include "test/fakecircs.h"
static void test_relay_append_cell_to_circuit_queue(void *arg);
-static or_circuit_t *
-new_fake_orcirc(channel_t *nchan, channel_t *pchan)
-{
- or_circuit_t *orcirc = NULL;
- circuit_t *circ = NULL;
-
- orcirc = tor_malloc_zero(sizeof(*orcirc));
- circ = &(orcirc->base_);
- circ->magic = OR_CIRCUIT_MAGIC;
-
- circuit_set_n_circid_chan(circ, get_unique_circ_id_by_chan(nchan), nchan);
- cell_queue_init(&(circ->n_chan_cells));
-
- circ->n_hop = NULL;
- circ->streams_blocked_on_n_chan = 0;
- circ->streams_blocked_on_p_chan = 0;
- circ->n_delete_pending = 0;
- circ->p_delete_pending = 0;
- circ->received_destroy = 0;
- circ->state = CIRCUIT_STATE_OPEN;
- circ->purpose = CIRCUIT_PURPOSE_OR;
- circ->package_window = CIRCWINDOW_START_MAX;
- circ->deliver_window = CIRCWINDOW_START_MAX;
- circ->n_chan_create_cell = NULL;
-
- circuit_set_p_circid_chan(orcirc, get_unique_circ_id_by_chan(pchan), pchan);
- cell_queue_init(&(orcirc->p_chan_cells));
-
- return orcirc;
-}
-
static void
assert_circuit_ok_mock(const circuit_t *c)
{
@@ -145,7 +112,7 @@ test_relay_close_circuit(void *arg)
cell_queue_clear(&orcirc->base_.n_chan_cells);
cell_queue_clear(&orcirc->p_chan_cells);
}
- tor_free(orcirc);
+ free_fake_orcirc(orcirc);
free_fake_channel(nchan);
free_fake_channel(pchan);
UNMOCK(assert_circuit_ok);
@@ -218,7 +185,7 @@ test_relay_append_cell_to_circuit_queue(void *arg)
cell_queue_clear(&orcirc->base_.n_chan_cells);
cell_queue_clear(&orcirc->p_chan_cells);
}
- tor_free(orcirc);
+ free_fake_orcirc(orcirc);
free_fake_channel(nchan);
free_fake_channel(pchan);
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
index c65279fb25..da9e791fb6 100644
--- a/src/test/test_relaycell.c
+++ b/src/test/test_relaycell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for handling different kinds of relay cell */
@@ -30,7 +30,6 @@
#include "core/or/half_edge_st.h"
#include "feature/client/circpathbias.h"
-#include "core/or/connection_edge.h"
static int srm_ncalls;
static entry_connection_t *srm_conn;
diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c
index 4bbf07c3ec..737c243e2d 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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
index 4f544cf21c..e396f9fd50 100644
--- a/src/test/test_rendcache.c
+++ b/src/test/test_rendcache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -21,8 +21,6 @@
#include "test/rend_test_helpers.h"
#include "test/log_test_helpers.h"
-#define NS_MODULE rend_cache
-
static const int RECENT_TIME = -10;
static const int TIME_IN_THE_PAST = -(REND_CACHE_MAX_AGE + \
REND_CACHE_MAX_SKEW + 60);
@@ -369,13 +367,12 @@ test_rend_cache_store_v2_desc_as_client_with_different_time(void *data)
rend_data_free(mock_rend_query);
}
-#define NS_SUBMODULE lookup_v2_desc_as_dir
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static const routerinfo_t *rcache_lookup_v2_as_dir_get_my_routerinfo(void);
static routerinfo_t *mock_routerinfo;
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+rcache_lookup_v2_as_dir_get_my_routerinfo(void)
{
if (!mock_routerinfo) {
mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
@@ -395,7 +392,8 @@ test_rend_cache_lookup_v2_desc_as_dir(void *data)
(void)data;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rcache_lookup_v2_as_dir_get_my_routerinfo);
rend_cache_init();
@@ -418,20 +416,17 @@ test_rend_cache_lookup_v2_desc_as_dir(void *data)
tt_assert(ret_desc);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ 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);
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE store_v2_desc_as_dir
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static const routerinfo_t *rcache_store_v2_as_dir_get_my_routerinfo(void);
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+rcache_store_v2_as_dir_get_my_routerinfo(void)
{
return mock_routerinfo;
}
@@ -444,7 +439,8 @@ test_rend_cache_store_v2_desc_as_dir(void *data)
rend_encoded_v2_service_descriptor_t *desc_holder = NULL;
char *service_id = NULL;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rcache_store_v2_as_dir_get_my_routerinfo);
rend_cache_init();
@@ -485,7 +481,7 @@ test_rend_cache_store_v2_desc_as_dir(void *data)
tt_int_op(ret, OP_EQ, 0);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
rend_encoded_v2_service_descriptor_free(desc_holder);
tor_free(service_id);
rend_cache_free_all();
@@ -505,7 +501,8 @@ test_rend_cache_store_v2_desc_as_dir_with_different_time(void *data)
rend_encoded_v2_service_descriptor_t *desc_holder_newer;
rend_encoded_v2_service_descriptor_t *desc_holder_older;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rcache_store_v2_as_dir_get_my_routerinfo);
rend_cache_init();
@@ -543,7 +540,7 @@ test_rend_cache_store_v2_desc_as_dir_with_different_time(void *data)
tt_int_op(ret, OP_EQ, 0);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
rend_cache_free_all();
rend_service_descriptor_free(generated);
tor_free(service_id);
@@ -568,7 +565,8 @@ test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data)
rend_encoded_v2_service_descriptor_t *desc_holder_one = NULL;
rend_encoded_v2_service_descriptor_t *desc_holder_two = NULL;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rcache_store_v2_as_dir_get_my_routerinfo);
rend_cache_init();
@@ -602,7 +600,7 @@ test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data)
tt_int_op(ret, OP_EQ, 0);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
rend_cache_free_all();
rend_service_descriptor_free(generated);
tor_free(service_id);
@@ -613,8 +611,6 @@ test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data)
rend_encoded_v2_service_descriptor_free(desc_holder_two);
}
-#undef NS_SUBMODULE
-
static void
test_rend_cache_init(void *data)
{
@@ -1074,8 +1070,6 @@ test_rend_cache_intro_failure_note(void *data)
rend_cache_free_all();
}
-#define NS_SUBMODULE clean_v2_descs_as_dir
-
static void
test_rend_cache_clean_v2_descs_as_dir(void *data)
{
@@ -1116,8 +1110,6 @@ test_rend_cache_clean_v2_descs_as_dir(void *data)
rend_cache_free_all();
}
-#undef NS_SUBMODULE
-
static void
test_rend_cache_entry_allocation(void *data)
{
@@ -1250,4 +1242,3 @@ struct testcase_t rend_cache_tests[] = {
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 28a508bf4d..1487b0a29d 100644
--- a/src/test/test_replay.c
+++ b/src/test/test_replay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, 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 dcf08fff1d..ebaffb74f5 100644
--- a/src/test/test_rng.c
+++ b/src/test/test_rng.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
diff --git a/src/test/test_router.c b/src/test/test_router.c
index 5477ab51e9..cf0c2b3dd1 100644
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* Copyright (c) 2017, isis agora lovecruft */
/* See LICENSE for licensing information */
@@ -8,11 +8,13 @@
**/
#define CONFIG_PRIVATE
+#define CONNECTION_PRIVATE
#define ROUTER_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/mainloop/mainloop.h"
+#include "core/mainloop/connection.h"
#include "feature/hibernate/hibernate.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -27,16 +29,19 @@
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/encoding/confline.h"
+#include "core/or/listener_connection_st.h"
+
/* Test suite stuff */
#include "test/test.h"
#include "test/log_test_helpers.h"
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static const routerinfo_t * rtr_tests_router_get_my_routerinfo(void);
+ATTR_UNUSED static int rtr_tests_router_get_my_routerinfo_called = 0;
static routerinfo_t* mock_routerinfo;
static const routerinfo_t*
-NS(router_get_my_routerinfo)(void)
+rtr_tests_router_get_my_routerinfo(void)
{
crypto_pk_t* ident_key;
crypto_pk_t* tap_key;
@@ -86,19 +91,20 @@ test_router_dump_router_to_string_no_bridge_distribution_method(void *arg)
char* found = NULL;
(void)arg;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rtr_tests_router_get_my_routerinfo);
options->ORPort_set = 1;
options->BridgeRelay = 1;
/* Generate keys which router_dump_router_to_string() expects to exist. */
- tt_int_op(0, ==, curve25519_keypair_generate(&ntor_keypair, 0));
- tt_int_op(0, ==, ed25519_keypair_generate(&signing_keypair, 0));
+ tt_int_op(0, OP_EQ, curve25519_keypair_generate(&ntor_keypair, 0));
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&signing_keypair, 0));
/* Set up part of our routerinfo_t so that we don't trigger any other
* assertions in router_dump_router_to_string(). */
router = (routerinfo_t*)router_get_my_routerinfo();
- tt_ptr_op(router, !=, NULL);
+ tt_ptr_op(router, OP_NE, NULL);
/* The real router_get_my_routerinfo() looks up onion_curve25519_pkey using
* get_current_curve25519_keypair(), but we don't initialise static data in
@@ -115,12 +121,12 @@ test_router_dump_router_to_string_no_bridge_distribution_method(void *arg)
&ntor_keypair,
&signing_keypair);
crypto_pk_free(onion_pkey);
- tt_ptr_op(desc, !=, NULL);
+ tt_ptr_op(desc, OP_NE, NULL);
found = strstr(desc, needle);
- tt_ptr_op(found, !=, NULL);
+ tt_ptr_op(found, OP_NE, NULL);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
tor_free(desc);
}
@@ -484,6 +490,117 @@ test_router_get_my_family(void *arg)
#undef CLEAR
}
+static smartlist_t *fake_connection_array = NULL;
+static smartlist_t *
+mock_get_connection_array(void)
+{
+ return fake_connection_array;
+}
+
+static void
+test_router_get_advertised_or_port(void *arg)
+{
+ (void)arg;
+ int r, w=0, n=0;
+ char *msg=NULL;
+ or_options_t *opts = options_new();
+ listener_connection_t *listener = NULL;
+ tor_addr_port_t ipv6;
+
+ // Test one failing case of router_get_advertised_ipv6_or_ap().
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
+
+ // And one failing case of router_get_advertised_or_port().
+ tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(0, OP_EQ, router_get_advertised_or_port(opts));
+
+ // Set up a couple of configured ports.
+ config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:auto");
+ config_line_append(&opts->ORPort_lines, "ORPort", "5.6.7.8:9999");
+ r = parse_ports(opts, 0, &msg, &n, &w);
+ tt_assert(r == 0);
+
+ // There are no listeners, so the "auto" case will turn up no results.
+ tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
+
+ // This will return the matching value from the configured port.
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts));
+
+ // Now set up a dummy listener.
+ MOCK(get_connection_array, mock_get_connection_array);
+ fake_connection_array = smartlist_new();
+ listener = listener_connection_new(CONN_TYPE_OR_LISTENER, AF_INET6);
+ TO_CONN(listener)->port = 54321;
+ smartlist_add(fake_connection_array, TO_CONN(listener));
+
+ // We should get a port this time.
+ tt_int_op(54321, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+
+ // Test one succeeding case of router_get_advertised_ipv6_or_ap().
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ,
+ "[1234::5678]:54321");
+
+ // This will return the matching value from the configured port.
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts));
+
+ done:
+ or_options_free(opts);
+ config_free_all();
+ smartlist_free(fake_connection_array);
+ connection_free_minimal(TO_CONN(listener));
+ UNMOCK(get_connection_array);
+}
+
+static void
+test_router_get_advertised_or_port_localhost(void *arg)
+{
+ (void)arg;
+ int r, w=0, n=0;
+ char *msg=NULL;
+ or_options_t *opts = options_new();
+ tor_addr_port_t ipv6;
+
+ // Set up a couple of configured ports on localhost.
+ config_line_append(&opts->ORPort_lines, "ORPort", "[::1]:9999");
+ config_line_append(&opts->ORPort_lines, "ORPort", "127.0.0.1:8888");
+ r = parse_ports(opts, 0, &msg, &n, &w);
+ tt_assert(r == 0);
+
+ // We should refuse to advertise them, since we have default dirauths.
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
+ // But the lower-level function should still report the correct value
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+
+ // The IPv4 checks are done in resolve_my_address(), which doesn't use
+ // ORPorts so we can't test them here. (See #33681.) Both these lower-level
+ // functions should still report the correct value.
+ tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts));
+
+ // Now try with a fake authority set up.
+ config_line_append(&opts->DirAuthorities, "DirAuthority",
+ "127.0.0.1:1066 "
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::1]:9999");
+
+ tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts));
+
+ done:
+ or_options_free(opts);
+ config_free_all();
+}
+
#define ROUTER_TEST(name, flags) \
{ #name, test_router_ ## name, flags, NULL, NULL }
@@ -492,5 +609,7 @@ struct testcase_t router_tests[] = {
ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method, TT_FORK),
ROUTER_TEST(mark_if_too_old, TT_FORK),
ROUTER_TEST(get_my_family, TT_FORK),
+ ROUTER_TEST(get_advertised_or_port, TT_FORK),
+ ROUTER_TEST(get_advertised_or_port_localhost, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index 0c6b533698..fc437dccc0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, 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 6d596e87ea..f2a83c18a3 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, 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 cc73e6c20a..892ac6e210 100644
--- a/src/test/test_routerset.c
+++ b/src/test/test_routerset.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERSET_PRIVATE
@@ -18,17 +18,13 @@
#include "test/test.h"
-#define NS_MODULE routerset
-
-#define NS_SUBMODULE routerset_new
-
/*
* Functional (blackbox) test to determine that each member of the routerset
* is non-NULL
*/
static void
-NS(test_main)(void *arg)
+test_rset_new(void *arg)
{
routerset_t *rs;
(void)arg;
@@ -46,15 +42,12 @@ NS(test_main)(void *arg)
routerset_free(rs);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_get_countryname
-
/*
* Functional test to strip the braces from a "{xx}" country code string.
*/
static void
-NS(test_main)(void *arg)
+test_rset_get_countryname(void *arg)
{
const char *input;
char *name;
@@ -91,257 +84,272 @@ NS(test_main)(void *arg)
tor_free(name);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_refresh_counties, geoip_not_loaded)
-
/*
* Structural (whitebox) test for routerset_refresh_counties, when the GeoIP DB
* is not loaded.
*/
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
-NS_DECL(int, geoip_get_n_countries, (void));
+static int rset_refresh_geoip_not_loaded_geoip_is_loaded(sa_family_t family);
+static int rset_refresh_geoip_not_loaded_geoip_is_loaded_called = 0;
+static int rset_refresh_geoip_not_loaded_geoip_get_n_countries(void);
+static int rset_refresh_geoip_not_loaded_geoip_get_n_countries_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_refresh_geoip_not_loaded(void *arg)
{
routerset_t *set = routerset_new();
(void)arg;
- NS_MOCK(geoip_is_loaded);
- NS_MOCK(geoip_get_n_countries);
+ MOCK(geoip_is_loaded,
+ rset_refresh_geoip_not_loaded_geoip_is_loaded);
+ MOCK(geoip_get_n_countries,
+ rset_refresh_geoip_not_loaded_geoip_get_n_countries);
routerset_refresh_countries(set);
tt_ptr_op(set->countries, OP_EQ, NULL);
tt_int_op(set->n_countries, OP_EQ, 0);
- tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 0);
+ tt_int_op(rset_refresh_geoip_not_loaded_geoip_is_loaded_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_geoip_not_loaded_geoip_get_n_countries_called,
+ OP_EQ, 0);
done:
- NS_UNMOCK(geoip_is_loaded);
- NS_UNMOCK(geoip_get_n_countries);
+ UNMOCK(geoip_is_loaded);
+ UNMOCK(geoip_get_n_countries);
routerset_free(set);
}
static int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_refresh_geoip_not_loaded_geoip_is_loaded(sa_family_t family)
{
(void)family;
- CALLED(geoip_is_loaded)++;
+ rset_refresh_geoip_not_loaded_geoip_is_loaded_called++;
return 0;
}
static int
-NS(geoip_get_n_countries)(void)
+rset_refresh_geoip_not_loaded_geoip_get_n_countries(void)
{
- CALLED(geoip_get_n_countries)++;
+ rset_refresh_geoip_not_loaded_geoip_get_n_countries_called++;
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_refresh_counties, no_countries)
-
/*
* Structural test for routerset_refresh_counties, when there are no countries.
*/
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
-NS_DECL(int, geoip_get_n_countries, (void));
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static int rset_refresh_no_countries_geoip_is_loaded(sa_family_t family);
+static int rset_refresh_no_countries_geoip_is_loaded_called = 0;
+static int rset_refresh_no_countries_geoip_get_n_countries(void);
+static int rset_refresh_no_countries_geoip_get_n_countries_called = 0;
+static country_t rset_refresh_no_countries_geoip_get_country(
+ const char *country);
+static int rset_refresh_no_countries_geoip_get_country_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_refresh_no_countries(void *arg)
{
routerset_t *set = routerset_new();
(void)arg;
- NS_MOCK(geoip_is_loaded);
- NS_MOCK(geoip_get_n_countries);
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_refresh_no_countries_geoip_is_loaded);
+ MOCK(geoip_get_n_countries,
+ rset_refresh_no_countries_geoip_get_n_countries);
+ MOCK(geoip_get_country,
+ rset_refresh_no_countries_geoip_get_country);
routerset_refresh_countries(set);
tt_ptr_op(set->countries, OP_NE, NULL);
tt_int_op(set->n_countries, OP_EQ, 1);
tt_int_op((unsigned int)(*set->countries), OP_EQ, 0);
- tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country), OP_EQ, 0);
+ tt_int_op(rset_refresh_no_countries_geoip_is_loaded_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_no_countries_geoip_get_n_countries_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_no_countries_geoip_get_country_called, OP_EQ, 0);
done:
- NS_UNMOCK(geoip_is_loaded);
- NS_UNMOCK(geoip_get_n_countries);
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_is_loaded);
+ UNMOCK(geoip_get_n_countries);
+ UNMOCK(geoip_get_country);
routerset_free(set);
}
static int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_refresh_no_countries_geoip_is_loaded(sa_family_t family)
{
(void)family;
- CALLED(geoip_is_loaded)++;
+ rset_refresh_no_countries_geoip_is_loaded_called++;
return 1;
}
static int
-NS(geoip_get_n_countries)(void)
+rset_refresh_no_countries_geoip_get_n_countries(void)
{
- CALLED(geoip_get_n_countries)++;
+ rset_refresh_no_countries_geoip_get_n_countries_called++;
return 1;
}
static country_t
-NS(geoip_get_country)(const char *countrycode)
+rset_refresh_no_countries_geoip_get_country(const char *countrycode)
{
(void)countrycode;
- CALLED(geoip_get_country)++;
+ rset_refresh_no_countries_geoip_get_country_called++;
return 1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_refresh_counties, one_valid_country)
-
/*
* Structural test for routerset_refresh_counties, with one valid country.
*/
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
-NS_DECL(int, geoip_get_n_countries, (void));
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static int rset_refresh_one_valid_country_geoip_is_loaded(sa_family_t family);
+static int rset_refresh_one_valid_country_geoip_is_loaded_called = 0;
+static int rset_refresh_one_valid_country_geoip_get_n_countries(void);
+static int rset_refresh_one_valid_country_geoip_get_n_countries_called = 0;
+static country_t rset_refresh_one_valid_country_geoip_get_country(
+ const char *country);
+static int rset_refresh_one_valid_country_geoip_get_country_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_refresh_one_valid_country(void *arg)
{
routerset_t *set = routerset_new();
(void)arg;
- NS_MOCK(geoip_is_loaded);
- NS_MOCK(geoip_get_n_countries);
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_refresh_one_valid_country_geoip_is_loaded);
+ MOCK(geoip_get_n_countries,
+ rset_refresh_one_valid_country_geoip_get_n_countries);
+ MOCK(geoip_get_country,
+ rset_refresh_one_valid_country_geoip_get_country);
smartlist_add(set->country_names, tor_strndup("foo", 3));
routerset_refresh_countries(set);
tt_ptr_op(set->countries, OP_NE, NULL);
tt_int_op(set->n_countries, OP_EQ, 2);
- tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country), OP_EQ, 1);
+ tt_int_op(rset_refresh_one_valid_country_geoip_is_loaded_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_one_valid_country_geoip_get_n_countries_called,
+ OP_EQ, 1);
+ tt_int_op(rset_refresh_one_valid_country_geoip_get_country_called, OP_EQ, 1);
tt_int_op((unsigned int)(*set->countries), OP_NE, 0);
done:
- NS_UNMOCK(geoip_is_loaded);
- NS_UNMOCK(geoip_get_n_countries);
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_is_loaded);
+ UNMOCK(geoip_get_n_countries);
+ UNMOCK(geoip_get_country);
routerset_free(set);
}
static int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_refresh_one_valid_country_geoip_is_loaded(sa_family_t family)
{
(void)family;
- CALLED(geoip_is_loaded)++;
+ rset_refresh_one_valid_country_geoip_is_loaded_called++;
return 1;
}
static int
-NS(geoip_get_n_countries)(void)
+rset_refresh_one_valid_country_geoip_get_n_countries(void)
{
- CALLED(geoip_get_n_countries)++;
+ rset_refresh_one_valid_country_geoip_get_n_countries_called++;
return 2;
}
static country_t
-NS(geoip_get_country)(const char *countrycode)
+rset_refresh_one_valid_country_geoip_get_country(const char *countrycode)
{
(void)countrycode;
- CALLED(geoip_get_country)++;
+ rset_refresh_one_valid_country_geoip_get_country_called++;
return 1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_refresh_counties, one_invalid_country)
-
/*
* Structural test for routerset_refresh_counties, with one invalid
* country code..
*/
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
-NS_DECL(int, geoip_get_n_countries, (void));
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static int rset_refresh_one_invalid_country_geoip_is_loaded(
+ sa_family_t family);
+static int rset_refresh_one_invalid_country_geoip_is_loaded_called = 0;
+static int rset_refresh_one_invalid_country_geoip_get_n_countries(void);
+static int rset_refresh_one_invalid_country_geoip_get_n_countries_called = 0;
+static country_t rset_refresh_one_invalid_country_geoip_get_country(
+ const char *country);
+static int rset_refresh_one_invalid_country_geoip_get_country_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_refresh_one_invalid_country(void *arg)
{
routerset_t *set = routerset_new();
(void)arg;
- NS_MOCK(geoip_is_loaded);
- NS_MOCK(geoip_get_n_countries);
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_refresh_one_invalid_country_geoip_is_loaded);
+ MOCK(geoip_get_n_countries,
+ rset_refresh_one_invalid_country_geoip_get_n_countries);
+ MOCK(geoip_get_country,
+ rset_refresh_one_invalid_country_geoip_get_country);
smartlist_add(set->country_names, tor_strndup("foo", 3));
routerset_refresh_countries(set);
tt_ptr_op(set->countries, OP_NE, NULL);
tt_int_op(set->n_countries, OP_EQ, 2);
- tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country), OP_EQ, 1);
+ tt_int_op(rset_refresh_one_invalid_country_geoip_is_loaded_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_one_invalid_country_geoip_get_n_countries_called,
+ OP_EQ, 1);
+ tt_int_op(rset_refresh_one_invalid_country_geoip_get_country_called,
+ OP_EQ, 1);
tt_int_op((unsigned int)(*set->countries), OP_EQ, 0);
done:
- NS_UNMOCK(geoip_is_loaded);
- NS_UNMOCK(geoip_get_n_countries);
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_is_loaded);
+ UNMOCK(geoip_get_n_countries);
+ UNMOCK(geoip_get_country);
routerset_free(set);
}
static int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_refresh_one_invalid_country_geoip_is_loaded(sa_family_t family)
{
(void)family;
- CALLED(geoip_is_loaded)++;
+ rset_refresh_one_invalid_country_geoip_is_loaded_called++;
return 1;
}
static int
-NS(geoip_get_n_countries)(void)
+rset_refresh_one_invalid_country_geoip_get_n_countries(void)
{
- CALLED(geoip_get_n_countries)++;
+ rset_refresh_one_invalid_country_geoip_get_n_countries_called++;
return 2;
}
static country_t
-NS(geoip_get_country)(const char *countrycode)
+rset_refresh_one_invalid_country_geoip_get_country(const char *countrycode)
{
(void)countrycode;
- CALLED(geoip_get_country)++;
+ rset_refresh_one_invalid_country_geoip_get_country_called++;
return -1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, malformed)
-
/*
* Functional test, with a malformed string to parse.
*/
static void
-NS(test_main)(void *arg)
+test_rset_parse_malformed(void *arg)
{
routerset_t *set = routerset_new();
const char *s = "_";
@@ -356,16 +364,13 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, valid_hexdigest)
-
/*
* Functional test for routerset_parse, that routerset_parse returns 0
* on a valid hexdigest entry.
*/
static void
-NS(test_main)(void *arg)
+test_rset_parse_valid_hexdigest(void *arg)
{
routerset_t *set;
const char *s;
@@ -382,15 +387,12 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, valid_nickname)
-
/*
* Functional test for routerset_parse, when given a valid nickname as input.
*/
static void
-NS(test_main)(void *arg)
+test_rset_parse_valid_nickname(void *arg)
{
routerset_t *set;
const char *s;
@@ -407,15 +409,12 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, get_countryname)
-
/*
* Functional test for routerset_parse, when given a valid countryname.
*/
static void
-NS(test_main)(void *arg)
+test_rset_parse_get_countryname(void *arg)
{
routerset_t *set;
const char *s;
@@ -432,158 +431,158 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, policy_wildcard)
-
/*
* Structural test for routerset_parse, when given a valid wildcard policy.
*/
-NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
- (const char *s, int assume_action, int *malformed_list));
+static addr_policy_t * rset_parse_policy_wildcard_parse_item_from_string(
+ const char *s, int assume_action, int *malformed_list);
+static int rset_parse_policy_wildcard_parse_item_from_string_called = 0;
-static addr_policy_t *NS(mock_addr_policy);
+static addr_policy_t *rset_parse_policy_wildcard_mock_addr_policy;
static void
-NS(test_main)(void *arg)
+test_rset_parse_policy_wildcard(void *arg)
{
routerset_t *set;
const char *s;
int r;
(void)arg;
- NS_MOCK(router_parse_addr_policy_item_from_string);
- NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t));
+ MOCK(router_parse_addr_policy_item_from_string,
+ rset_parse_policy_wildcard_parse_item_from_string);
+ rset_parse_policy_wildcard_mock_addr_policy =
+ tor_malloc_zero(sizeof(addr_policy_t));
set = routerset_new();
s = "*";
r = routerset_parse(set, s, "");
tt_int_op(r, OP_EQ, 0);
tt_int_op(smartlist_len(set->policies), OP_NE, 0);
- tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1);
+ tt_int_op(rset_parse_policy_wildcard_parse_item_from_string_called,
+ OP_EQ, 1);
done:
routerset_free(set);
}
addr_policy_t *
-NS(router_parse_addr_policy_item_from_string)(const char *s,
+rset_parse_policy_wildcard_parse_item_from_string(const char *s,
int assume_action,
int *malformed_list)
{
(void)s;
(void)assume_action;
(void)malformed_list;
- CALLED(router_parse_addr_policy_item_from_string)++;
+ rset_parse_policy_wildcard_parse_item_from_string_called++;
- return NS(mock_addr_policy);
+ return rset_parse_policy_wildcard_mock_addr_policy;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, policy_ipv4)
-
/*
* Structural test for routerset_parse, when given a valid IPv4 address
* literal policy.
*/
-NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
- (const char *s, int assume_action, int *bogus));
+static addr_policy_t * rset_parse_policy_ipv4_parse_item_from_string(
+ const char *s, int assume_action, int *bogus);
+static int rset_parse_policy_ipv4_parse_item_from_string_called = 0;
-static addr_policy_t *NS(mock_addr_policy);
+static addr_policy_t *rset_parse_policy_ipv4_mock_addr_policy;
static void
-NS(test_main)(void *arg)
+test_rset_parse_policy_ipv4(void *arg)
{
routerset_t *set;
const char *s;
int r;
(void)arg;
- NS_MOCK(router_parse_addr_policy_item_from_string);
- NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t));
+ MOCK(router_parse_addr_policy_item_from_string,
+ rset_parse_policy_ipv4_parse_item_from_string);
+ rset_parse_policy_ipv4_mock_addr_policy =
+ tor_malloc_zero(sizeof(addr_policy_t));
set = routerset_new();
s = "127.0.0.1";
r = routerset_parse(set, s, "");
tt_int_op(r, OP_EQ, 0);
tt_int_op(smartlist_len(set->policies), OP_NE, 0);
- tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1);
+ tt_int_op(rset_parse_policy_ipv4_parse_item_from_string_called, OP_EQ, 1);
done:
routerset_free(set);
}
addr_policy_t *
-NS(router_parse_addr_policy_item_from_string)(const char *s, int assume_action,
- int *bogus)
+rset_parse_policy_ipv4_parse_item_from_string(
+ const char *s, int assume_action,
+ int *bogus)
{
(void)s;
(void)assume_action;
- CALLED(router_parse_addr_policy_item_from_string)++;
+ rset_parse_policy_ipv4_parse_item_from_string_called++;
*bogus = 0;
- return NS(mock_addr_policy);
+ return rset_parse_policy_ipv4_mock_addr_policy;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, policy_ipv6)
-
/*
* Structural test for routerset_parse, when given a valid IPv6 address
* literal policy.
*/
-NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
- (const char *s, int assume_action, int *bad));
+static addr_policy_t * rset_parse_policy_ipv6_parse_item_from_string(
+ const char *s, int assume_action, int *bad);
+static int rset_parse_policy_ipv6_parse_item_from_string_called = 0;
-static addr_policy_t *NS(mock_addr_policy);
+static addr_policy_t *rset_parse_policy_ipv6_mock_addr_policy;
static void
-NS(test_main)(void *arg)
+test_rset_parse_policy_ipv6(void *arg)
{
routerset_t *set;
const char *s;
int r;
(void)arg;
- NS_MOCK(router_parse_addr_policy_item_from_string);
- NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t));
+ MOCK(router_parse_addr_policy_item_from_string,
+ rset_parse_policy_ipv6_parse_item_from_string);
+ rset_parse_policy_ipv6_mock_addr_policy =
+ tor_malloc_zero(sizeof(addr_policy_t));
set = routerset_new();
s = "::1";
r = routerset_parse(set, s, "");
tt_int_op(r, OP_EQ, 0);
tt_int_op(smartlist_len(set->policies), OP_NE, 0);
- tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1);
+ tt_int_op(rset_parse_policy_ipv6_parse_item_from_string_called, OP_EQ, 1);
done:
routerset_free(set);
}
addr_policy_t *
-NS(router_parse_addr_policy_item_from_string)(const char *s,
+rset_parse_policy_ipv6_parse_item_from_string(const char *s,
int assume_action, int *bad)
{
(void)s;
(void)assume_action;
- CALLED(router_parse_addr_policy_item_from_string)++;
+ rset_parse_policy_ipv6_parse_item_from_string_called++;
*bad = 0;
- return NS(mock_addr_policy);
+ return rset_parse_policy_ipv6_mock_addr_policy;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_union, source_bad)
-
/*
* Structural test for routerset_union, when given a bad source argument.
*/
-NS_DECL(smartlist_t *, smartlist_new, (void));
+static smartlist_t * rset_union_source_bad_smartlist_new(void);
+static int rset_union_source_bad_smartlist_new_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_union_source_bad(void *arg)
{
routerset_t *set, *bad_set;
(void)arg;
@@ -593,16 +592,17 @@ NS(test_main)(void *arg)
smartlist_free(bad_set->list);
bad_set->list = NULL;
- NS_MOCK(smartlist_new);
+ MOCK(smartlist_new,
+ rset_union_source_bad_smartlist_new);
routerset_union(set, NULL);
- tt_int_op(CALLED(smartlist_new), OP_EQ, 0);
+ tt_int_op(rset_union_source_bad_smartlist_new_called, OP_EQ, 0);
routerset_union(set, bad_set);
- tt_int_op(CALLED(smartlist_new), OP_EQ, 0);
+ tt_int_op(rset_union_source_bad_smartlist_new_called, OP_EQ, 0);
done:
- NS_UNMOCK(smartlist_new);
+ UNMOCK(smartlist_new);
routerset_free(set);
/* Just recreate list, so we can simply use routerset_free. */
@@ -611,22 +611,19 @@ NS(test_main)(void *arg)
}
static smartlist_t *
-NS(smartlist_new)(void)
+rset_union_source_bad_smartlist_new(void)
{
- CALLED(smartlist_new)++;
+ rset_union_source_bad_smartlist_new_called++;
return NULL;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_union, one)
-
/*
* Functional test for routerset_union.
*/
static void
-NS(test_main)(void *arg)
+test_rset_union_one(void *arg)
{
routerset_t *src = routerset_new();
routerset_t *tgt;
@@ -643,15 +640,12 @@ NS(test_main)(void *arg)
routerset_free(tgt);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_is_list
-
/*
* Functional tests for routerset_is_list.
*/
static void
-NS(test_main)(void *arg)
+test_rset_is_list(void *arg)
{
routerset_t *set;
addr_policy_t *policy;
@@ -696,15 +690,12 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_needs_geoip
-
/*
* Functional tests for routerset_needs_geoip.
*/
static void
-NS(test_main)(void *arg)
+test_rset_needs_geoip(void *arg)
{
routerset_t *set;
int needs_geoip;
@@ -731,15 +722,12 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_is_empty
-
/*
* Functional tests for routerset_is_empty.
*/
static void
-NS(test_main)(void *arg)
+test_rset_is_empty(void *arg)
{
routerset_t *set = NULL;
int is_empty;
@@ -765,16 +753,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, null_set_or_null_set_list)
-
/*
* Functional test for routerset_contains, when given a NULL set or the
* set has a NULL list.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_null_set_or_list(void *arg)
{
routerset_t *set = NULL;
int contains;
@@ -794,16 +779,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_nickname)
-
/*
* Functional test for routerset_contains, when given a valid routerset but a
* NULL nickname.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_null_nickname(void *arg)
{
routerset_t *set = routerset_new();
char *nickname = NULL;
@@ -819,16 +801,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_nickname)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the nickname is in the routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_nickname(void *arg)
{
routerset_t *set = routerset_new();
const char *nickname;
@@ -845,16 +824,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_nickname)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the nickname is not in the routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_no_nickname(void *arg)
{
routerset_t *set = routerset_new();
int contains;
@@ -869,16 +845,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_digest)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the digest is contained in the routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_digest(void *arg)
{
routerset_t *set = routerset_new();
int contains;
@@ -894,16 +867,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_digest)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the digest is not contained in the routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_no_digest(void *arg)
{
routerset_t *set = routerset_new();
int contains;
@@ -920,16 +890,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_digest)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the digest is NULL.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_null_digest(void *arg)
{
routerset_t *set = routerset_new();
int contains;
@@ -945,34 +912,34 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_addr)
-
/*
* Structural test for routerset_contains, when given a valid routerset
* and the address is rejected by policy.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+static addr_policy_result_t rset_contains_addr_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_contains_addr_cmp_addr_to_policy_called = 0;
static tor_addr_t MOCK_TOR_ADDR;
#define MOCK_TOR_ADDR_PTR (&MOCK_TOR_ADDR)
static void
-NS(test_main)(void *arg)
+test_rset_contains_addr(void *arg)
{
routerset_t *set = routerset_new();
tor_addr_t *addr = MOCK_TOR_ADDR_PTR;
int contains;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_contains_addr_cmp_addr_to_policy);
contains = routerset_contains(set, addr, 0, NULL, NULL, 0);
routerset_free(set);
- tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
+ tt_int_op(rset_contains_addr_cmp_addr_to_policy_called, OP_EQ, 1);
tt_int_op(contains, OP_EQ, 3);
done:
@@ -980,12 +947,12 @@ NS(test_main)(void *arg)
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_contains_addr_cmp_addr_to_policy(const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_contains_addr_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
return ADDR_POLICY_REJECTED;
@@ -993,31 +960,31 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_addr)
-
/*
* Structural test for routerset_contains, when given a valid routerset
* and the address is not rejected by policy.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+static addr_policy_result_t rset_contains_no_addr_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_contains_no_addr_cmp_addr_to_policy_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_contains_no_addr(void *arg)
{
routerset_t *set = routerset_new();
tor_addr_t *addr = MOCK_TOR_ADDR_PTR;
int contains;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_contains_no_addr_cmp_addr_to_policy);
contains = routerset_contains(set, addr, 0, NULL, NULL, 0);
routerset_free(set);
- tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
+ tt_int_op(rset_contains_no_addr_cmp_addr_to_policy_called, OP_EQ, 1);
tt_int_op(contains, OP_EQ, 0);
done:
@@ -1025,12 +992,12 @@ NS(test_main)(void *arg)
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_contains_no_addr_cmp_addr_to_policy(const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_contains_no_addr_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
return ADDR_POLICY_ACCEPTED;
@@ -1039,25 +1006,25 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_addr)
-
/*
* Structural test for routerset_contains, when given a valid routerset
* and the address is NULL.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+static addr_policy_result_t rset_contains_null_addr_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_contains_null_addr_cmp_addr_to_policy_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_contains_null_addr(void *arg)
{
routerset_t *set = routerset_new();
int contains;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_contains_null_addr_cmp_addr_to_policy);
contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
routerset_free(set);
@@ -1069,12 +1036,13 @@ NS(test_main)(void *arg)
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_contains_null_addr_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_contains_null_addr_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
return ADDR_POLICY_ACCEPTED;
@@ -1083,27 +1051,30 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, countries_no_geoip)
-
/*
* Structural test for routerset_contains, when there is no matching country
* for the address.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
-NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+static addr_policy_result_t rset_countries_no_geoip_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_countries_no_geoip_cmp_addr_to_policy_called = 0;
+static int rset_countries_no_geoip_geoip_get_country_by_addr(
+ const tor_addr_t *addr);
+static int rset_countries_no_geoip_geoip_get_country_by_addr_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_countries_no_geoip(void *arg)
{
routerset_t *set = routerset_new();
int contains = 1;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
- NS_MOCK(geoip_get_country_by_addr);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_countries_no_geoip_cmp_addr_to_policy);
+ MOCK(geoip_get_country_by_addr,
+ rset_countries_no_geoip_geoip_get_country_by_addr);
set->countries = bitarray_init_zero(1);
bitarray_set(set->countries, 1);
@@ -1111,20 +1082,23 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(contains, OP_EQ, 0);
- tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country_by_addr), OP_EQ, 1);
+ tt_int_op(rset_countries_no_geoip_cmp_addr_to_policy_called,
+ OP_EQ, 1);
+ tt_int_op(rset_countries_no_geoip_geoip_get_country_by_addr_called,
+ OP_EQ, 1);
done:
;
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_countries_no_geoip_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_countries_no_geoip_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
done:
@@ -1132,36 +1106,39 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
}
int
-NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+rset_countries_no_geoip_geoip_get_country_by_addr(const tor_addr_t *addr)
{
- CALLED(geoip_get_country_by_addr)++;
+ rset_countries_no_geoip_geoip_get_country_by_addr_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
done:
return -1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, countries_geoip)
-
/*
* Structural test for routerset_contains, when there a matching country
* for the address.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
-NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+static addr_policy_result_t rset_countries_geoip_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_countries_geoip_cmp_addr_to_policy_called = 0;
+static int rset_countries_geoip_geoip_get_country_by_addr(
+ const tor_addr_t *addr);
+static int rset_countries_geoip_geoip_get_country_by_addr_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_countries_geoip(void *arg)
{
routerset_t *set = routerset_new();
int contains = 1;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
- NS_MOCK(geoip_get_country_by_addr);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_countries_geoip_cmp_addr_to_policy);
+ MOCK(geoip_get_country_by_addr,
+ rset_countries_geoip_geoip_get_country_by_addr);
set->n_countries = 2;
set->countries = bitarray_init_zero(1);
@@ -1170,20 +1147,24 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(contains, OP_EQ, 2);
- tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country_by_addr), OP_EQ, 1);
+ tt_int_op(
+ rset_countries_geoip_cmp_addr_to_policy_called,
+ OP_EQ, 1);
+ tt_int_op(rset_countries_geoip_geoip_get_country_by_addr_called,
+ OP_EQ, 1);
done:
;
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_countries_geoip_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_countries_geoip_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
done:
@@ -1191,25 +1172,22 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
}
int
-NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+rset_countries_geoip_geoip_get_country_by_addr(const tor_addr_t *addr)
{
- CALLED(geoip_get_country_by_addr)++;
+ rset_countries_geoip_geoip_get_country_by_addr_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
done:
return 1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, only_flag_and_no_ccs)
-
/*
* Functional test for routerset_add_unknown_ccs, where only_if_some_cc_set
* is set and there are no country names.
*/
static void
-NS(test_main)(void *arg)
+test_rset_add_unknown_ccs_only_flag(void *arg)
{
routerset_t *set = routerset_new();
routerset_t **setp = &set;
@@ -1224,26 +1202,26 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, creates_set)
-
/*
* Functional test for routerset_add_unknown_ccs, where the set argument
* is created if passed in as NULL.
*/
/* The mock is only used to stop the test from asserting erroneously. */
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static country_t rset_add_unknown_ccs_creates_set_geoip_get_country(
+ const char *country);
+static int rset_add_unknown_ccs_creates_set_geoip_get_country_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_add_unknown_ccs_creates_set(void *arg)
{
routerset_t *set = NULL;
routerset_t **setp = &set;
int r;
(void)arg;
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_get_country,
+ rset_add_unknown_ccs_creates_set_geoip_get_country);
r = routerset_add_unknown_ccs(setp, 0);
@@ -1256,35 +1234,38 @@ NS(test_main)(void *arg)
}
country_t
-NS(geoip_get_country)(const char *country)
+rset_add_unknown_ccs_creates_set_geoip_get_country(const char *country)
{
(void)country;
- CALLED(geoip_get_country)++;
+ rset_add_unknown_ccs_creates_set_geoip_get_country_called++;
return -1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, add_unknown)
-
/*
* Structural test for routerset_add_unknown_ccs, that the "{??}"
* country code is added to the list.
*/
-NS_DECL(country_t, geoip_get_country, (const char *country));
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+static country_t rset_add_unknown_ccs_add_unknown_geoip_get_country(
+ const char *country);
+static int rset_add_unknown_ccs_add_unknown_geoip_get_country_called = 0;
+static int rset_add_unknown_ccs_add_unknown_geoip_is_loaded(
+ sa_family_t family);
+static int rset_add_unknown_ccs_add_unknown_geoip_is_loaded_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_add_unknown_ccs_add_unknown(void *arg)
{
routerset_t *set = routerset_new();
routerset_t **setp = &set;
int r;
(void)arg;
- NS_MOCK(geoip_get_country);
- NS_MOCK(geoip_is_loaded);
+ MOCK(geoip_get_country,
+ rset_add_unknown_ccs_add_unknown_geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_add_unknown_ccs_add_unknown_geoip_is_loaded);
r = routerset_add_unknown_ccs(setp, 0);
@@ -1298,11 +1279,11 @@ NS(test_main)(void *arg)
}
country_t
-NS(geoip_get_country)(const char *country)
+rset_add_unknown_ccs_add_unknown_geoip_get_country(const char *country)
{
int arg_is_qq, arg_is_a1;
- CALLED(geoip_get_country)++;
+ rset_add_unknown_ccs_add_unknown_geoip_get_country_called++;
arg_is_qq = !strcmp(country, "??");
arg_is_a1 = !strcmp(country, "A1");
@@ -1317,9 +1298,9 @@ NS(geoip_get_country)(const char *country)
}
int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_add_unknown_ccs_add_unknown_geoip_is_loaded(sa_family_t family)
{
- CALLED(geoip_is_loaded)++;
+ rset_add_unknown_ccs_add_unknown_geoip_is_loaded_called++;
tt_int_op(family, OP_EQ, AF_INET);
@@ -1327,27 +1308,29 @@ NS(geoip_is_loaded)(sa_family_t family)
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, add_a1)
-
/*
* Structural test for routerset_add_unknown_ccs, that the "{a1}"
* country code is added to the list.
*/
-NS_DECL(country_t, geoip_get_country, (const char *country));
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+static country_t rset_add_unknown_ccs_add_a1_geoip_get_country(
+ const char *country);
+static int rset_add_unknown_ccs_add_a1_geoip_get_country_called = 0;
+static int rset_add_unknown_ccs_add_a1_geoip_is_loaded(sa_family_t family);
+static int rset_add_unknown_ccs_add_a1_geoip_is_loaded_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_add_unknown_ccs_add_a1(void *arg)
{
routerset_t *set = routerset_new();
routerset_t **setp = &set;
int r;
(void)arg;
- NS_MOCK(geoip_get_country);
- NS_MOCK(geoip_is_loaded);
+ MOCK(geoip_get_country,
+ rset_add_unknown_ccs_add_a1_geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_add_unknown_ccs_add_a1_geoip_is_loaded);
r = routerset_add_unknown_ccs(setp, 0);
@@ -1361,11 +1344,11 @@ NS(test_main)(void *arg)
}
country_t
-NS(geoip_get_country)(const char *country)
+rset_add_unknown_ccs_add_a1_geoip_get_country(const char *country)
{
int arg_is_qq, arg_is_a1;
- CALLED(geoip_get_country)++;
+ rset_add_unknown_ccs_add_a1_geoip_get_country_called++;
arg_is_qq = !strcmp(country, "??");
arg_is_a1 = !strcmp(country, "A1");
@@ -1380,9 +1363,9 @@ NS(geoip_get_country)(const char *country)
}
int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_add_unknown_ccs_add_a1_geoip_is_loaded(sa_family_t family)
{
- CALLED(geoip_is_loaded)++;
+ rset_add_unknown_ccs_add_a1_geoip_is_loaded_called++;
tt_int_op(family, OP_EQ, AF_INET);
@@ -1390,15 +1373,12 @@ NS(geoip_is_loaded)(sa_family_t family)
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_contains_extendinfo
-
/*
* Functional test for routerset_contains_extendinfo.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_extendinfo(void *arg)
{
routerset_t *set = routerset_new();
extend_info_t ei;
@@ -1418,15 +1398,12 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_contains_router
-
/*
* Functional test for routerset_contains_router.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_router(void *arg)
{
routerset_t *set = routerset_new();
routerinfo_t ri;
@@ -1446,9 +1423,6 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_contains_routerstatus
-
/*
* Functional test for routerset_contains_routerstatus.
*/
@@ -1458,7 +1432,7 @@ NS(test_main)(void *arg)
// a bit more or test a bit more.
static void
-NS(test_main)(void *arg)
+test_rset_contains_routerstatus(void *arg)
{
routerset_t *set = routerset_new();
routerstatus_t rs;
@@ -1479,46 +1453,41 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains_node, none)
-
/*
* Functional test for routerset_contains_node, when the node has no
* routerset or routerinfo.
*/
-static node_t NS(mock_node);
+static node_t rset_contains_none_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_contains_none(void *arg)
{
routerset_t *set = routerset_new();
int r;
(void)arg;
- memset(&NS(mock_node), 0, sizeof(NS(mock_node)));
- NS(mock_node).ri = NULL;
- NS(mock_node).rs = NULL;
+ memset(&rset_contains_none_mock_node, 0,
+ sizeof(rset_contains_none_mock_node));
+ rset_contains_none_mock_node.ri = NULL;
+ rset_contains_none_mock_node.rs = NULL;
- r = routerset_contains_node(set, &NS(mock_node));
+ r = routerset_contains_node(set, &rset_contains_none_mock_node);
tt_int_op(r, OP_EQ, 0);
done:
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains_node, routerstatus)
-
/*
* Functional test for routerset_contains_node, when the node has a
* routerset and no routerinfo.
*/
-static node_t NS(mock_node);
+static node_t rset_contains_rs_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_contains_rs(void *arg)
{
routerset_t *set = routerset_new();
int r;
@@ -1530,27 +1499,24 @@ NS(test_main)(void *arg)
strncpy(rs.nickname, nickname, sizeof(rs.nickname) - 1);
rs.nickname[sizeof(rs.nickname) - 1] = '\0';
- memset(&NS(mock_node), 0, sizeof(NS(mock_node)));
- NS(mock_node).ri = NULL;
- NS(mock_node).rs = &rs;
+ memset(&rset_contains_rs_mock_node, 0, sizeof(rset_contains_rs_mock_node));
+ rset_contains_rs_mock_node.ri = NULL;
+ rset_contains_rs_mock_node.rs = &rs;
- r = routerset_contains_node(set, &NS(mock_node));
+ r = routerset_contains_node(set, &rset_contains_rs_mock_node);
tt_int_op(r, OP_EQ, 4);
done:
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains_node, routerinfo)
-
/*
* Functional test for routerset_contains_node, when the node has no
* routerset and a routerinfo.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_routerinfo(void *arg)
{
routerset_t *set = routerset_new();
int r;
@@ -1573,16 +1539,13 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, no_routerset)
-
/*
* Functional test for routerset_get_all_nodes, when routerset is NULL or
* the routerset list is NULL.
*/
static void
-NS(test_main)(void *arg)
+test_rset_get_all_no_routerset(void *arg)
{
smartlist_t *out = smartlist_new();
routerset_t *set = NULL;
@@ -1606,30 +1569,29 @@ NS(test_main)(void *arg)
smartlist_free(out);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list_with_no_nodes)
-
/*
* Structural test for routerset_get_all_nodes, when the routerset list
* is empty.
*/
-NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, unsigned flags));
-static const char *NS(mock_nickname);
+static const node_t * rset_get_all_l_no_nodes_node_get_by_nickname(
+ const char *nickname, unsigned flags);
+static int rset_get_all_l_no_nodes_node_get_by_nickname_called = 0;
+static const char *rset_get_all_l_no_nodes_mock_nickname;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_l_no_nodes(void *arg)
{
smartlist_t *out = smartlist_new();
routerset_t *set = routerset_new();
int out_len;
(void)arg;
- NS_MOCK(node_get_by_nickname);
+ MOCK(node_get_by_nickname,
+ rset_get_all_l_no_nodes_node_get_by_nickname);
- NS(mock_nickname) = "foo";
- smartlist_add_strdup(set->list, NS(mock_nickname));
+ rset_get_all_l_no_nodes_mock_nickname = "foo";
+ smartlist_add_strdup(set->list, rset_get_all_l_no_nodes_mock_nickname);
routerset_get_all_nodes(out, set, NULL, 0);
out_len = smartlist_len(out);
@@ -1638,49 +1600,49 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(out_len, OP_EQ, 0);
- tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+ tt_int_op(rset_get_all_l_no_nodes_node_get_by_nickname_called, OP_EQ, 1);
done:
;
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, unsigned flags)
+rset_get_all_l_no_nodes_node_get_by_nickname(const char *nickname,
+ unsigned flags)
{
- CALLED(node_get_by_nickname)++;
- tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ rset_get_all_l_no_nodes_node_get_by_nickname_called++;
+ tt_str_op(nickname, OP_EQ, rset_get_all_l_no_nodes_mock_nickname);
tt_uint_op(flags, OP_EQ, 0);
done:
return NULL;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list_flag_not_running)
-
/*
* Structural test for routerset_get_all_nodes, with the running_only flag
* is set but the nodes are not running.
*/
-NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, unsigned flags));
-static const char *NS(mock_nickname);
-static node_t NS(mock_node);
+static const node_t * rset_get_all_l_not_running_node_get_by_nickname(
+ const char *nickname, unsigned flags);
+static int rset_get_all_l_not_running_node_get_by_nickname_called = 0;
+static const char *rset_get_all_l_not_running_mock_nickname;
+static node_t rset_get_all_l_not_running_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_l_not_running(void *arg)
{
smartlist_t *out = smartlist_new();
routerset_t *set = routerset_new();
int out_len;
(void)arg;
- NS_MOCK(node_get_by_nickname);
+ MOCK(node_get_by_nickname,
+ rset_get_all_l_not_running_node_get_by_nickname);
- NS(mock_node).is_running = 0;
- NS(mock_nickname) = "foo";
- smartlist_add_strdup(set->list, NS(mock_nickname));
+ rset_get_all_l_not_running_mock_node.is_running = 0;
+ rset_get_all_l_not_running_mock_nickname = "foo";
+ smartlist_add_strdup(set->list, rset_get_all_l_not_running_mock_nickname);
routerset_get_all_nodes(out, set, NULL, 1);
out_len = smartlist_len(out);
@@ -1689,37 +1651,36 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(out_len, OP_EQ, 0);
- tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+ tt_int_op(rset_get_all_l_not_running_node_get_by_nickname_called, OP_EQ, 1);
done:
;
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, unsigned flags)
+rset_get_all_l_not_running_node_get_by_nickname(const char *nickname,
+ unsigned flags)
{
- CALLED(node_get_by_nickname)++;
- tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ rset_get_all_l_not_running_node_get_by_nickname_called++;
+ tt_str_op(nickname, OP_EQ, rset_get_all_l_not_running_mock_nickname);
tt_int_op(flags, OP_EQ, 0);
done:
- return &NS(mock_node);
+ return &rset_get_all_l_not_running_mock_node;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list)
-
/*
* Structural test for routerset_get_all_nodes.
*/
-NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, unsigned flags));
-static char *NS(mock_nickname);
-static node_t NS(mock_node);
+static const node_t * rset_get_all_list_node_get_by_nickname(
+ const char *nickname, unsigned flags);
+static int rset_get_all_list_node_get_by_nickname_called = 0;
+static char *rset_get_all_list_mock_nickname;
+static node_t rset_get_all_list_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_list(void *arg)
{
smartlist_t *out = smartlist_new();
routerset_t *set = routerset_new();
@@ -1727,10 +1688,11 @@ NS(test_main)(void *arg)
node_t *ent;
(void)arg;
- NS_MOCK(node_get_by_nickname);
+ MOCK(node_get_by_nickname,
+ rset_get_all_list_node_get_by_nickname);
- NS(mock_nickname) = tor_strdup("foo");
- smartlist_add(set->list, NS(mock_nickname));
+ rset_get_all_list_mock_nickname = tor_strdup("foo");
+ smartlist_add(set->list, rset_get_all_list_mock_nickname);
routerset_get_all_nodes(out, set, NULL, 0);
out_len = smartlist_len(out);
@@ -1740,127 +1702,122 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(out_len, OP_EQ, 1);
- tt_ptr_op(ent, OP_EQ, &NS(mock_node));
- tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+ tt_ptr_op(ent, OP_EQ, &rset_get_all_list_mock_node);
+ tt_int_op(rset_get_all_list_node_get_by_nickname_called, OP_EQ, 1);
done:
;
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, unsigned flags)
+rset_get_all_list_node_get_by_nickname(const char *nickname, unsigned flags)
{
- CALLED(node_get_by_nickname)++;
- tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ rset_get_all_list_node_get_by_nickname_called++;
+ tt_str_op(nickname, OP_EQ, rset_get_all_list_mock_nickname);
tt_int_op(flags, OP_EQ, 0);
done:
- return &NS(mock_node);
+ return &rset_get_all_list_mock_node;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, nodelist_with_no_nodes)
-
/*
* Structural test for routerset_get_all_nodes, when the nodelist has no nodes.
*/
-NS_DECL(const smartlist_t *, nodelist_get_list, (void));
-
-static smartlist_t *NS(mock_smartlist);
+static const smartlist_t * rset_get_all_n_no_nodes_nodelist_get_list(void);
+static int rset_get_all_n_no_nodes_nodelist_get_list_called = 0;
+static smartlist_t *rset_get_all_n_no_nodes_mock_smartlist;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_n_no_nodes(void *arg)
{
routerset_t *set = routerset_new();
smartlist_t *out = smartlist_new();
int r;
(void)arg;
- NS_MOCK(nodelist_get_list);
+ MOCK(nodelist_get_list,
+ rset_get_all_n_no_nodes_nodelist_get_list);
smartlist_add_strdup(set->country_names, "{xx}");
- NS(mock_smartlist) = smartlist_new();
+ rset_get_all_n_no_nodes_mock_smartlist = smartlist_new();
routerset_get_all_nodes(out, set, NULL, 1);
r = smartlist_len(out);
routerset_free(set);
smartlist_free(out);
- smartlist_free(NS(mock_smartlist));
+ smartlist_free(rset_get_all_n_no_nodes_mock_smartlist);
tt_int_op(r, OP_EQ, 0);
- tt_int_op(CALLED(nodelist_get_list), OP_EQ, 1);
+ tt_int_op(rset_get_all_n_no_nodes_nodelist_get_list_called, OP_EQ, 1);
done:
;
}
const smartlist_t *
-NS(nodelist_get_list)(void)
+rset_get_all_n_no_nodes_nodelist_get_list(void)
{
- CALLED(nodelist_get_list)++;
+ rset_get_all_n_no_nodes_nodelist_get_list_called++;
- return NS(mock_smartlist);
+ return rset_get_all_n_no_nodes_mock_smartlist;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, nodelist_flag_not_running)
-
/*
* Structural test for routerset_get_all_nodes, with a non-list routerset
* the running_only flag is set, but the nodes are not running.
*/
-NS_DECL(const smartlist_t *, nodelist_get_list, (void));
+static const smartlist_t * rset_get_all_n_not_running_nodelist_get_list(void);
+static int rset_get_all_n_not_running_nodelist_get_list_called = 0;
-static smartlist_t *NS(mock_smartlist);
-static node_t NS(mock_node);
+static smartlist_t *rset_get_all_n_not_running_mock_smartlist;
+static node_t rset_get_all_n_not_running_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_n_not_running(void *arg)
{
routerset_t *set = routerset_new();
smartlist_t *out = smartlist_new();
int r;
(void)arg;
- NS_MOCK(nodelist_get_list);
+ MOCK(nodelist_get_list,
+ rset_get_all_n_not_running_nodelist_get_list);
smartlist_add_strdup(set->country_names, "{xx}");
- NS(mock_smartlist) = smartlist_new();
- NS(mock_node).is_running = 0;
- smartlist_add(NS(mock_smartlist), (void *)&NS(mock_node));
+ rset_get_all_n_not_running_mock_smartlist = smartlist_new();
+ rset_get_all_n_not_running_mock_node.is_running = 0;
+ smartlist_add(rset_get_all_n_not_running_mock_smartlist,
+ (void *)&rset_get_all_n_not_running_mock_node);
routerset_get_all_nodes(out, set, NULL, 1);
r = smartlist_len(out);
routerset_free(set);
smartlist_free(out);
- smartlist_free(NS(mock_smartlist));
+ smartlist_free(rset_get_all_n_not_running_mock_smartlist);
tt_int_op(r, OP_EQ, 0);
- tt_int_op(CALLED(nodelist_get_list), OP_EQ, 1);
+ tt_int_op(rset_get_all_n_not_running_nodelist_get_list_called, OP_EQ, 1);
done:
;
}
const smartlist_t *
-NS(nodelist_get_list)(void)
+rset_get_all_n_not_running_nodelist_get_list(void)
{
- CALLED(nodelist_get_list)++;
+ rset_get_all_n_not_running_nodelist_get_list_called++;
- return NS(mock_smartlist);
+ return rset_get_all_n_not_running_mock_smartlist;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_subtract_nodes
-
/*
* Functional test for routerset_subtract_nodes.
*/
static void
-NS(test_main)(void *arg)
+test_rset_subtract_nodes(void *arg)
{
routerset_t *set = routerset_new();
smartlist_t *list = smartlist_new();
@@ -1885,15 +1842,12 @@ NS(test_main)(void *arg)
smartlist_free(list);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_subtract_nodes, null_routerset)
-
/*
* Functional test for routerset_subtract_nodes, with a NULL routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_subtract_nodes_null_routerset(void *arg)
{
routerset_t *set = NULL;
smartlist_t *list = smartlist_new();
@@ -1915,15 +1869,12 @@ NS(test_main)(void *arg)
smartlist_free(list);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_to_string
-
/*
* Functional test for routerset_to_string.
*/
static void
-NS(test_main)(void *arg)
+test_rset_to_string(void *arg)
{
routerset_t *set = NULL;
char *s = NULL;
@@ -1960,15 +1911,12 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, empty_empty)
-
/*
* Functional test for routerset_equal, with both routersets empty.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_empty_empty(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -1984,15 +1932,12 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, empty_not_empty)
-
/*
* Functional test for routerset_equal, with one routersets empty.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_empty_not_empty(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -2008,16 +1953,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, differing_lengths)
-
/*
* Functional test for routerset_equal, with the routersets having
* differing lengths.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_differing_lengths(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -2035,16 +1977,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, unequal)
-
/*
* Functional test for routerset_equal, with the routersets being
* different.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_unequal(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -2061,16 +2000,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, equal)
-
/*
* Functional test for routerset_equal, with the routersets being
* equal.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_equal(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -2087,147 +2023,176 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_free, null_routerset)
-
/*
* Structural test for routerset_free, where the routerset is NULL.
*/
-NS_DECL(void, smartlist_free_, (smartlist_t *sl));
+static void rset_free_null_routerset_smartlist_free_(smartlist_t *sl);
+static int rset_free_null_routerset_smartlist_free__called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_free_null_routerset(void *arg)
{
(void)arg;
- NS_MOCK(smartlist_free_);
+ MOCK(smartlist_free_,
+ rset_free_null_routerset_smartlist_free_);
routerset_free_(NULL);
- tt_int_op(CALLED(smartlist_free_), OP_EQ, 0);
+ tt_int_op(rset_free_null_routerset_smartlist_free__called, OP_EQ, 0);
done:
;
}
void
-NS(smartlist_free_)(smartlist_t *s)
+rset_free_null_routerset_smartlist_free_(smartlist_t *s)
{
(void)s;
- CALLED(smartlist_free_)++;
+ rset_free_null_routerset_smartlist_free__called++;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_free
-
/*
* Structural test for routerset_free.
*/
-NS_DECL(void, smartlist_free_, (smartlist_t *sl));
-NS_DECL(void, strmap_free_,(strmap_t *map, void (*free_val)(void*)));
-NS_DECL(void, digestmap_free_, (digestmap_t *map, void (*free_val)(void*)));
+static void rset_free_smartlist_free_(smartlist_t *sl);
+static int rset_free_smartlist_free__called = 0;
+static void rset_free_strmap_free_(strmap_t *map, void (*free_val)(void*));
+static int rset_free_strmap_free__called = 0;
+static void rset_free_digestmap_free_(digestmap_t *map,
+ void (*free_val)(void*));
+static int rset_free_digestmap_free__called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_free(void *arg)
{
routerset_t *routerset = routerset_new();
(void)arg;
- NS_MOCK(smartlist_free_);
- NS_MOCK(strmap_free_);
- NS_MOCK(digestmap_free_);
+ MOCK(smartlist_free_,
+ rset_free_smartlist_free_);
+ MOCK(strmap_free_,
+ rset_free_strmap_free_);
+ MOCK(digestmap_free_,
+ rset_free_digestmap_free_);
routerset_free(routerset);
- tt_int_op(CALLED(smartlist_free_), OP_NE, 0);
- tt_int_op(CALLED(strmap_free_), OP_NE, 0);
- tt_int_op(CALLED(digestmap_free_), OP_NE, 0);
+ tt_int_op(rset_free_smartlist_free__called, OP_NE, 0);
+ tt_int_op(rset_free_strmap_free__called, OP_NE, 0);
+ tt_int_op(rset_free_digestmap_free__called, OP_NE, 0);
done:
;
}
void
-NS(smartlist_free_)(smartlist_t *s)
+rset_free_smartlist_free_(smartlist_t *s)
{
- CALLED(smartlist_free_)++;
+ rset_free_smartlist_free__called++;
smartlist_free___real(s);
}
void
-NS(strmap_free_)(strmap_t *map, void (*free_val)(void*))
+rset_free_strmap_free_(strmap_t *map, void (*free_val)(void*))
{
- CALLED(strmap_free_)++;
+ rset_free_strmap_free__called++;
strmap_free___real(map, free_val);
}
void
-NS(digestmap_free_)(digestmap_t *map, void (*free_val)(void*))
+rset_free_digestmap_free_(digestmap_t *map, void (*free_val)(void*))
{
- CALLED(digestmap_free_)++;
+ rset_free_digestmap_free__called++;
digestmap_free___real(map, free_val);
}
-#undef NS_SUBMODULE
-
struct testcase_t routerset_tests[] = {
- TEST_CASE(routerset_new),
- TEST_CASE(routerset_get_countryname),
- TEST_CASE(routerset_is_list),
- TEST_CASE(routerset_needs_geoip),
- TEST_CASE(routerset_is_empty),
- TEST_CASE_ASPECT(routerset_contains, null_set_or_null_set_list),
- TEST_CASE_ASPECT(routerset_contains, set_and_nickname),
- TEST_CASE_ASPECT(routerset_contains, set_and_null_nickname),
- TEST_CASE_ASPECT(routerset_contains, set_and_no_nickname),
- TEST_CASE_ASPECT(routerset_contains, set_and_digest),
- TEST_CASE_ASPECT(routerset_contains, set_and_no_digest),
- TEST_CASE_ASPECT(routerset_contains, set_and_null_digest),
- TEST_CASE_ASPECT(routerset_contains, set_and_addr),
- TEST_CASE_ASPECT(routerset_contains, set_and_no_addr),
- TEST_CASE_ASPECT(routerset_contains, set_and_null_addr),
- TEST_CASE_ASPECT(routerset_contains, countries_no_geoip),
- TEST_CASE_ASPECT(routerset_contains, countries_geoip),
- TEST_CASE_ASPECT(routerset_add_unknown_ccs, only_flag_and_no_ccs),
- TEST_CASE_ASPECT(routerset_add_unknown_ccs, creates_set),
- TEST_CASE_ASPECT(routerset_add_unknown_ccs, add_unknown),
- TEST_CASE_ASPECT(routerset_add_unknown_ccs, add_a1),
- TEST_CASE(routerset_contains_extendinfo),
- TEST_CASE(routerset_contains_router),
- TEST_CASE(routerset_contains_routerstatus),
- TEST_CASE_ASPECT(routerset_contains_node, none),
- TEST_CASE_ASPECT(routerset_contains_node, routerinfo),
- TEST_CASE_ASPECT(routerset_contains_node, routerstatus),
- TEST_CASE_ASPECT(routerset_get_all_nodes, no_routerset),
- TEST_CASE_ASPECT(routerset_get_all_nodes, list_with_no_nodes),
- TEST_CASE_ASPECT(routerset_get_all_nodes, list_flag_not_running),
- TEST_CASE_ASPECT(routerset_get_all_nodes, list),
- TEST_CASE_ASPECT(routerset_get_all_nodes, nodelist_with_no_nodes),
- TEST_CASE_ASPECT(routerset_get_all_nodes, nodelist_flag_not_running),
- TEST_CASE_ASPECT(routerset_refresh_counties, geoip_not_loaded),
- TEST_CASE_ASPECT(routerset_refresh_counties, no_countries),
- TEST_CASE_ASPECT(routerset_refresh_counties, one_valid_country),
- TEST_CASE_ASPECT(routerset_refresh_counties, one_invalid_country),
- TEST_CASE_ASPECT(routerset_union, source_bad),
- TEST_CASE_ASPECT(routerset_union, one),
- TEST_CASE_ASPECT(routerset_parse, malformed),
- TEST_CASE_ASPECT(routerset_parse, valid_hexdigest),
- TEST_CASE_ASPECT(routerset_parse, valid_nickname),
- TEST_CASE_ASPECT(routerset_parse, get_countryname),
- TEST_CASE_ASPECT(routerset_parse, policy_wildcard),
- TEST_CASE_ASPECT(routerset_parse, policy_ipv4),
- TEST_CASE_ASPECT(routerset_parse, policy_ipv6),
- TEST_CASE(routerset_subtract_nodes),
- TEST_CASE_ASPECT(routerset_subtract_nodes, null_routerset),
- TEST_CASE(routerset_to_string),
- TEST_CASE_ASPECT(routerset_equal, empty_empty),
- TEST_CASE_ASPECT(routerset_equal, empty_not_empty),
- TEST_CASE_ASPECT(routerset_equal, differing_lengths),
- TEST_CASE_ASPECT(routerset_equal, unequal),
- TEST_CASE_ASPECT(routerset_equal, equal),
- TEST_CASE_ASPECT(routerset_free, null_routerset),
- TEST_CASE(routerset_free),
+ { "new", test_rset_new, TT_FORK, NULL, NULL },
+ { "get_countryname", test_rset_get_countryname, TT_FORK, NULL, NULL },
+ { "is_list", test_rset_is_list, TT_FORK, NULL, NULL },
+ { "needs_geoip", test_rset_needs_geoip, TT_FORK, NULL, NULL },
+ { "is_empty", test_rset_is_empty, TT_FORK, NULL, NULL },
+ { "contains_null_set_or_list", test_rset_contains_null_set_or_list,
+ TT_FORK, NULL, NULL },
+ { "contains_nickname", test_rset_contains_nickname, TT_FORK, NULL, NULL },
+ { "contains_null_nickname", test_rset_contains_null_nickname,
+ TT_FORK, NULL, NULL },
+ { "contains_no_nickname", test_rset_contains_no_nickname,
+ TT_FORK, NULL, NULL },
+ { "contains_digest", test_rset_contains_digest, TT_FORK, NULL, NULL },
+ { "contains_no_digest", test_rset_contains_no_digest, TT_FORK, NULL, NULL },
+ { "contains_null_digest", test_rset_contains_null_digest,
+ TT_FORK, NULL, NULL },
+ { "contains_addr", test_rset_contains_addr, TT_FORK, NULL, NULL },
+ { "contains_no_addr", test_rset_contains_no_addr, TT_FORK, NULL, NULL },
+ { "contains_null_addr", test_rset_contains_null_addr, TT_FORK, NULL, NULL },
+ { "contains_countries_no_geoip", test_rset_countries_no_geoip,
+ TT_FORK, NULL, NULL },
+ { "contains_countries_geoip", test_rset_countries_geoip,
+ TT_FORK, NULL, NULL },
+ { "add_unknown_ccs_only_flag", test_rset_add_unknown_ccs_only_flag,
+ TT_FORK, NULL, NULL },
+ { "add_unknown_ccs_creates_set", test_rset_add_unknown_ccs_creates_set,
+ TT_FORK, NULL, NULL },
+ { "add_unknown_ccs_add_unknown", test_rset_add_unknown_ccs_add_unknown,
+ TT_FORK, NULL, NULL },
+ { "add_unknown_ccs_add_a1", test_rset_add_unknown_ccs_add_a1,
+ TT_FORK, NULL, NULL },
+ { "contains_extendinfo", test_rset_contains_extendinfo,
+ TT_FORK, NULL, NULL },
+ { "contains_router", test_rset_contains_router, TT_FORK, NULL, NULL },
+ { "contains_routerstatus", test_rset_contains_routerstatus,
+ TT_FORK, NULL, NULL },
+ { "contains_none", test_rset_contains_none, TT_FORK, NULL, NULL },
+ { "contains_routerinfo", test_rset_contains_routerinfo,
+ TT_FORK, NULL, NULL },
+ { "contains_rs", test_rset_contains_rs, TT_FORK, NULL, NULL },
+ { "get_all_no_routerset", test_rset_get_all_no_routerset,
+ TT_FORK, NULL, NULL },
+ { "get_all_l_no_nodes", test_rset_get_all_l_no_nodes, TT_FORK, NULL, NULL },
+ { "get_all_l_not_running", test_rset_get_all_l_not_running,
+ TT_FORK, NULL, NULL },
+ { "get_all_list", test_rset_get_all_list, TT_FORK, NULL, NULL },
+ { "get_all_n_no_nodes", test_rset_get_all_n_no_nodes, TT_FORK, NULL, NULL },
+ { "get_all_n_not_running", test_rset_get_all_n_not_running,
+ TT_FORK, NULL, NULL },
+ { "refresh_geoip_not_loaded", test_rset_refresh_geoip_not_loaded,
+ TT_FORK, NULL, NULL },
+ { "refresh_no_countries", test_rset_refresh_no_countries,
+ TT_FORK, NULL, NULL },
+ { "refresh_one_valid_country", test_rset_refresh_one_valid_country,
+ TT_FORK, NULL, NULL },
+ { "refresh_one_invalid_country", test_rset_refresh_one_invalid_country,
+ TT_FORK, NULL, NULL },
+ { "union_source_bad", test_rset_union_source_bad, TT_FORK, NULL, NULL },
+ { "union_one", test_rset_union_one, TT_FORK, NULL, NULL },
+ { "parse_malformed", test_rset_parse_malformed, TT_FORK, NULL, NULL },
+ { "parse_valid_hexdigest", test_rset_parse_valid_hexdigest,
+ TT_FORK, NULL, NULL },
+ { "parse_valid_nickname", test_rset_parse_valid_nickname,
+ TT_FORK, NULL, NULL },
+ { "parse_get_countryname", test_rset_parse_get_countryname,
+ TT_FORK, NULL, NULL },
+ { "parse_policy_wildcard", test_rset_parse_policy_wildcard,
+ TT_FORK, NULL, NULL },
+ { "parse_policy_ipv4", test_rset_parse_policy_ipv4, TT_FORK, NULL, NULL },
+ { "parse_policy_ipv6", test_rset_parse_policy_ipv6, TT_FORK, NULL, NULL },
+ { "subtract_nodes", test_rset_subtract_nodes, TT_FORK, NULL, NULL },
+ { "subtract_nodes_null_routerset", test_rset_subtract_nodes_null_routerset,
+ TT_FORK, NULL, NULL },
+ { "to_string", test_rset_to_string, TT_FORK, NULL, NULL },
+ { "equal_empty_empty", test_rset_equal_empty_empty, TT_FORK, NULL, NULL },
+ { "equal_empty_not_empty", test_rset_equal_empty_not_empty,
+ TT_FORK, NULL, NULL },
+ { "equal_differing_lengths", test_rset_equal_differing_lengths,
+ TT_FORK, NULL, NULL },
+ { "equal_unequal", test_rset_equal_unequal, TT_FORK, NULL, NULL },
+ { "equal_equal", test_rset_equal_equal, TT_FORK, NULL, NULL },
+ { "free_null_routerset", test_rset_free_null_routerset,
+ TT_FORK, NULL, NULL },
+ { "free", test_rset_free, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index bf9c6a49cd..9ec15948e8 100644
--- a/src/test/test_scheduler.c
+++ b/src/test/test_scheduler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -6,8 +6,8 @@
#include <math.h>
#define SCHEDULER_KIST_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
-#define CHANNEL_PRIVATE_
+#define CHANNEL_OBJECT_PRIVATE
+#define CHANNEL_FILE_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "lib/evloop/compat_libevent.h"
@@ -15,7 +15,7 @@
#include "core/or/channeltls.h"
#include "core/mainloop/connection.h"
#include "feature/nodelist/networkstatus.h"
-#define SCHEDULER_PRIVATE_
+#define SCHEDULER_PRIVATE
#include "core/or/scheduler.h"
/* Test suite stuff */
@@ -848,8 +848,8 @@ test_scheduler_initfree(void *arg)
{
(void)arg;
- tt_ptr_op(channels_pending, ==, NULL);
- tt_ptr_op(run_sched_ev, ==, NULL);
+ tt_ptr_op(channels_pending, OP_EQ, NULL);
+ tt_ptr_op(run_sched_ev, OP_EQ, NULL);
MOCK(get_options, mock_get_options);
set_scheduler_options(SCHEDULER_KIST);
@@ -858,17 +858,17 @@ test_scheduler_initfree(void *arg)
scheduler_init();
- tt_ptr_op(channels_pending, !=, NULL);
- tt_ptr_op(run_sched_ev, !=, NULL);
+ tt_ptr_op(channels_pending, OP_NE, NULL);
+ tt_ptr_op(run_sched_ev, OP_NE, NULL);
/* We have specified nothing in the torrc and there's no consensus so the
* KIST scheduler is what should be in use */
- tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
- tt_int_op(sched_run_interval, ==, 10);
+ tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
+ tt_int_op(sched_run_interval, OP_EQ, 10);
scheduler_free_all();
- tt_ptr_op(channels_pending, ==, NULL);
- tt_ptr_op(run_sched_ev, ==, NULL);
+ tt_ptr_op(channels_pending, OP_EQ, NULL);
+ tt_ptr_op(run_sched_ev, OP_EQ, NULL);
done:
UNMOCK(get_options);
@@ -890,11 +890,11 @@ test_scheduler_can_use_kist(void *arg)
res_should = scheduler_can_use_kist();
res_freq = kist_scheduler_run_interval();
#ifdef HAVE_KIST_SUPPORT
- tt_int_op(res_should, ==, 1);
+ tt_int_op(res_should, OP_EQ, 1);
#else /* HAVE_KIST_SUPPORT */
- tt_int_op(res_should, ==, 0);
+ tt_int_op(res_should, OP_EQ, 0);
#endif /* HAVE_KIST_SUPPORT */
- tt_int_op(res_freq, ==, 1234);
+ tt_int_op(res_freq, OP_EQ, 1234);
/* Test defer to consensus, but no consensus available */
clear_options();
@@ -902,11 +902,11 @@ test_scheduler_can_use_kist(void *arg)
res_should = scheduler_can_use_kist();
res_freq = kist_scheduler_run_interval();
#ifdef HAVE_KIST_SUPPORT
- tt_int_op(res_should, ==, 1);
+ tt_int_op(res_should, OP_EQ, 1);
#else /* HAVE_KIST_SUPPORT */
- tt_int_op(res_should, ==, 0);
+ tt_int_op(res_should, OP_EQ, 0);
#endif /* HAVE_KIST_SUPPORT */
- tt_int_op(res_freq, ==, 10);
+ tt_int_op(res_freq, OP_EQ, 10);
/* Test defer to consensus, and kist consensus available */
MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
@@ -915,11 +915,11 @@ test_scheduler_can_use_kist(void *arg)
res_should = scheduler_can_use_kist();
res_freq = kist_scheduler_run_interval();
#ifdef HAVE_KIST_SUPPORT
- tt_int_op(res_should, ==, 1);
+ tt_int_op(res_should, OP_EQ, 1);
#else /* HAVE_KIST_SUPPORT */
- tt_int_op(res_should, ==, 0);
+ tt_int_op(res_should, OP_EQ, 0);
#endif /* HAVE_KIST_SUPPORT */
- tt_int_op(res_freq, ==, 12);
+ tt_int_op(res_freq, OP_EQ, 12);
UNMOCK(networkstatus_get_param);
/* Test defer to consensus, and vanilla consensus available */
@@ -928,8 +928,8 @@ test_scheduler_can_use_kist(void *arg)
mocked_options.KISTSchedRunInterval = 0;
res_should = scheduler_can_use_kist();
res_freq = kist_scheduler_run_interval();
- tt_int_op(res_should, ==, 0);
- tt_int_op(res_freq, ==, 0);
+ tt_int_op(res_should, OP_EQ, 0);
+ tt_int_op(res_freq, OP_EQ, 0);
UNMOCK(networkstatus_get_param);
done:
@@ -956,7 +956,7 @@ test_scheduler_ns_changed(void *arg)
set_scheduler_options(SCHEDULER_KIST);
set_scheduler_options(SCHEDULER_VANILLA);
- tt_ptr_op(the_scheduler, ==, NULL);
+ tt_ptr_op(the_scheduler, OP_EQ, NULL);
/* Change from vanilla to kist via consensus */
the_scheduler = get_vanilla_scheduler();
@@ -964,9 +964,9 @@ test_scheduler_ns_changed(void *arg)
scheduler_notify_networkstatus_changed();
UNMOCK(networkstatus_get_param);
#ifdef HAVE_KIST_SUPPORT
- tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
#else
- tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
#endif
/* Change from kist to vanilla via consensus */
@@ -974,7 +974,7 @@ test_scheduler_ns_changed(void *arg)
MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
scheduler_notify_networkstatus_changed();
UNMOCK(networkstatus_get_param);
- tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
/* Doesn't change when using KIST */
the_scheduler = get_kist_scheduler();
@@ -982,9 +982,9 @@ test_scheduler_ns_changed(void *arg)
scheduler_notify_networkstatus_changed();
UNMOCK(networkstatus_get_param);
#ifdef HAVE_KIST_SUPPORT
- tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
#else
- tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
#endif
/* Doesn't change when using vanilla */
@@ -992,7 +992,7 @@ test_scheduler_ns_changed(void *arg)
MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
scheduler_notify_networkstatus_changed();
UNMOCK(networkstatus_get_param);
- tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
done:
UNMOCK(get_options);
diff --git a/src/test/test_sendme.c b/src/test/test_sendme.c
index eb402232bc..2ff4809124 100644
--- a/src/test/test_sendme.c
+++ b/src/test/test_sendme.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for handling different kinds of relay cell */
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index 9c8703fa6f..148eb5cf90 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SHARED_RANDOM_PRIVATE
@@ -21,7 +21,7 @@
#include "feature/nodelist/dirlist.h"
#include "feature/dirparse/authcert_parse.h"
#include "feature/hs_common/shared_random_client.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirclient/dir_server_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -193,7 +193,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
/* Compare it with the correct result */
@@ -205,7 +205,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 19:22:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -216,7 +216,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -227,7 +227,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -265,7 +265,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -277,7 +277,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:59 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -289,7 +289,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -319,7 +319,7 @@ test_get_start_time_of_current_run(void *arg)
&current_time);
tt_int_op(retval, OP_EQ, 0);
update_approx_time(current_time);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
@@ -327,7 +327,7 @@ test_get_start_time_of_current_run(void *arg)
format_iso_time(tbuf, run_start_time);
tt_str_op("2015-04-19 00:00:00", OP_EQ, tbuf);
/* Check that voting_schedule.interval_starts is at 01:00 (see above) */
- time_t interval_starts = voting_schedule_get_next_valid_after_time();
+ time_t interval_starts = dirauth_sched_get_next_valid_after_time();
format_iso_time(tbuf, interval_starts);
tt_str_op("2015-04-20 01:00:00", OP_EQ, tbuf);
}
@@ -346,7 +346,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:15:32 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -378,13 +378,13 @@ test_get_start_time_functions(void *arg)
tt_int_op(retval, OP_EQ, 0);
time_t now = mock_consensus.valid_after;
- voting_schedule_recalculate_timing(get_options(), now);
+ dirauth_sched_recalculate_timing(get_options(), now);
time_t start_time_of_protocol_run =
sr_state_get_start_time_of_current_protocol_run();
tt_assert(start_time_of_protocol_run);
/* Check that the round start time of the beginning of the run, is itself */
- tt_int_op(get_start_time_of_current_round(), OP_EQ,
+ tt_int_op(dirauth_sched_get_cur_valid_after_time(), OP_EQ,
start_time_of_protocol_run);
done:
diff --git a/src/test/test_slow.c b/src/test/test_slow.c
index d4d5b755a5..49b1066dac 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_socks.c b/src/test/test_socks.c
index 6d3ebd2320..4a465c7361 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -399,6 +399,43 @@ test_socks_5_supported_commands(void *ptr)
tt_int_op(0,OP_EQ, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE_PTR [F1] for an IPv6 address */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF1\x00\x04"
+ "\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34"
+ "\x12\x34");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+ tt_str_op("[2001:db8:85a3::8a2e:370:7334]",OP_EQ, socks->address);
+
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
+
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE_PTR [F1] for a an IPv6 address written as a
+ * string with brackets */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF1\x00\x03\x1e");
+ ADD_DATA(buf, "[2001:db8:85a3::8a2e:370:7334]");
+ ADD_DATA(buf, "\x12\x34");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+ tt_str_op("[2001:db8:85a3::8a2e:370:7334]",OP_EQ, socks->address);
+
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
+
done:
;
}
diff --git a/src/test/test_stats.c b/src/test/test_stats.c
new file mode 100644
index 0000000000..291473ebc9
--- /dev/null
+++ b/src/test/test_stats.c
@@ -0,0 +1,258 @@
+/* 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 test_stats.c
+ * \brief Unit tests for the statistics (reputation history) module.
+ **/
+
+#include "orconfig.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "app/config/or_state_st.h"
+#include "test/rng_test_helpers.h"
+
+#include <stdio.h>
+
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#else
+#include <dirent.h>
+#endif /* defined(_WIN32) */
+
+#include <math.h>
+
+/* These macros pull in declarations for some functions and structures that
+ * are typically file-private. */
+#define CIRCUITSTATS_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#define MAINLOOP_PRIVATE
+#define STATEFILE_PRIVATE
+
+#include "core/or/or.h"
+#include "lib/err/backtrace.h"
+#include "lib/buf/buffers.h"
+#include "core/or/circuitstats.h"
+#include "app/config/config.h"
+#include "test/test.h"
+#include "core/mainloop/mainloop.h"
+#include "lib/memarea/memarea.h"
+#include "feature/stats/rephist.h"
+#include "app/config/statefile.h"
+
+/** Run unit tests for some stats code. */
+static void
+test_stats(void *arg)
+{
+ time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
+ char *s = NULL;
+ int i;
+
+ /* Start with testing exit port statistics; we shouldn't collect exit
+ * stats without initializing them. */
+ (void)arg;
+ rep_hist_note_exit_stream_opened(80);
+ rep_hist_note_exit_bytes(80, 100, 10000);
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats, note some streams and bytes, and generate history
+ * string. */
+ rep_hist_exit_stats_init(now);
+ rep_hist_note_exit_stream_opened(80);
+ rep_hist_note_exit_bytes(80, 100, 10000);
+ rep_hist_note_exit_stream_opened(443);
+ rep_hist_note_exit_bytes(443, 100, 10000);
+ rep_hist_note_exit_bytes(443, 100, 10000);
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "exit-kibibytes-written 80=1,443=1,other=0\n"
+ "exit-kibibytes-read 80=10,443=20,other=0\n"
+ "exit-streams-opened 80=4,443=4,other=0\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Add a few bytes on 10 more ports and ensure that only the top 10
+ * ports are contained in the history string. */
+ for (i = 50; i < 60; i++) {
+ rep_hist_note_exit_bytes(i, i, i);
+ rep_hist_note_exit_stream_opened(i);
+ }
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "exit-kibibytes-written 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
+ "59=1,80=1,443=1,other=1\n"
+ "exit-kibibytes-read 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
+ "59=1,80=10,443=20,other=1\n"
+ "exit-streams-opened 52=4,53=4,54=4,55=4,56=4,57=4,58=4,"
+ "59=4,80=4,443=4,other=4\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add some bytes, and ensure we don't generate
+ * a history string. */
+ rep_hist_exit_stats_term();
+ rep_hist_note_exit_bytes(80, 100, 10000);
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Re-start stats, add some bytes, reset stats, and see what history we
+ * get when observing no streams or bytes at all. */
+ rep_hist_exit_stats_init(now);
+ rep_hist_note_exit_stream_opened(80);
+ rep_hist_note_exit_bytes(80, 100, 10000);
+ rep_hist_reset_exit_stats(now);
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "exit-kibibytes-written other=0\n"
+ "exit-kibibytes-read other=0\n"
+ "exit-streams-opened other=0\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Continue with testing connection statistics; we shouldn't collect
+ * conn stats without initializing them. */
+ rep_hist_note_or_conn_bytes(1, 20, 400, now);
+ s = rep_hist_format_conn_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats, note bytes, and generate history string. */
+ rep_hist_conn_stats_init(now);
+ rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
+ rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
+ s = rep_hist_format_conn_stats(now + 86400);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add some bytes, and ensure we don't generate
+ * a history string. */
+ rep_hist_conn_stats_term();
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
+ s = rep_hist_format_conn_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Re-start stats, add some bytes, reset stats, and see what history we
+ * get when observing no bytes at all. */
+ rep_hist_conn_stats_init(now);
+ rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
+ rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
+ rep_hist_reset_conn_stats(now);
+ s = rep_hist_format_conn_stats(now + 86400);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Continue with testing buffer statistics; we shouldn't collect buffer
+ * stats without initializing them. */
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats, add statistics for a single circuit, and generate
+ * the history string. */
+ rep_hist_buffer_stats_init(now);
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n"
+ "cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
+ "0.00,0.00\n"
+ "cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n"
+ "cell-circuits-per-decile 1\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Add nineteen more circuit statistics to the one that's already in the
+ * history to see that the math works correctly. */
+ for (i = 21; i < 30; i++)
+ rep_hist_add_buffer_stats(2.0, 2.0, i);
+ for (i = 20; i < 30; i++)
+ rep_hist_add_buffer_stats(3.5, 3.5, i);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n"
+ "cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75,"
+ "2.75,2.75\n"
+ "cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n"
+ "cell-circuits-per-decile 2\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add statistics for one circuit, and ensure we
+ * don't generate a history string. */
+ rep_hist_buffer_stats_term();
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Re-start stats, add statistics for one circuit, reset stats, and make
+ * sure that the history has all zeros. */
+ rep_hist_buffer_stats_init(now);
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ rep_hist_reset_buffer_stats(now);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n"
+ "cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
+ "0.00,0.00\n"
+ "cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n"
+ "cell-circuits-per-decile 0\n",OP_EQ, s);
+
+ done:
+ tor_free(s);
+}
+
+/** Run unit tests the mtbf stats code. */
+static void
+test_rephist_mtbf(void *arg)
+{
+ (void)arg;
+
+ time_t now = 1572500000; /* 2010-10-31 05:33:20 UTC */
+ time_t far_future = MAX(now, time(NULL)) + 365*24*60*60;
+ int r;
+
+ /* Make a temporary datadir for these tests */
+ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_mtbf"));
+ tor_free(get_options_mutable()->DataDirectory);
+ get_options_mutable()->DataDirectory = tor_strdup(ddir_fname);
+ check_private_dir(ddir_fname, CPD_CREATE, NULL);
+
+ rep_history_clean(far_future);
+
+ /* No data */
+
+ r = rep_hist_load_mtbf_data(now);
+ tt_int_op(r, OP_EQ, -1);
+ rep_history_clean(far_future);
+
+ /* Blank data */
+
+ r = rep_hist_record_mtbf_data(now, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = rep_hist_load_mtbf_data(now);
+ tt_int_op(r, OP_EQ, 0);
+ rep_history_clean(far_future);
+
+ r = rep_hist_record_mtbf_data(now, 1);
+ tt_int_op(r, OP_EQ, 0);
+ r = rep_hist_load_mtbf_data(now);
+ tt_int_op(r, OP_EQ, 0);
+ rep_history_clean(far_future);
+
+ done:
+ rep_history_clean(far_future);
+ tor_free(ddir_fname);
+}
+
+#define ENT(name) \
+ { #name, test_ ## name , 0, NULL, NULL }
+#define FORK(name) \
+ { #name, test_ ## name , TT_FORK, NULL, NULL }
+
+struct testcase_t stats_tests[] = {
+ FORK(stats),
+ ENT(rephist_mtbf),
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_status.c b/src/test/test_status.c
index 2fb2a7b24f..82afe0fd2a 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define STATUS_PRIVATE
@@ -33,10 +33,6 @@
#include "test/test.h"
-#define NS_MODULE status
-
-#define NS_SUBMODULE count_circuits
-
/*
* Test that count_circuits() is correctly counting the number of
* global circuits.
@@ -44,10 +40,10 @@
static smartlist_t * mock_global_circuitlist = NULL;
-NS_DECL(smartlist_t *, circuit_get_global_list, (void));
+static smartlist_t * status_count_circuits_circuit_get_global_list(void);
static void
-NS(test_main)(void *arg)
+test_status_count_circuits(void *arg)
{
/* Choose origin_circuit_t wlog. */
origin_circuit_t *mock_circuit1, *mock_circuit2;
@@ -61,7 +57,8 @@ NS(test_main)(void *arg)
smartlist_add(mock_global_circuitlist, TO_CIRCUIT(mock_circuit1));
smartlist_add(mock_global_circuitlist, TO_CIRCUIT(mock_circuit2));
- NS_MOCK(circuit_get_global_list);
+ MOCK(circuit_get_global_list,
+ status_count_circuits_circuit_get_global_list);
actual_circuits = count_circuits();
@@ -72,25 +69,22 @@ NS(test_main)(void *arg)
tor_free(mock_circuit2);
smartlist_free(mock_global_circuitlist);
mock_global_circuitlist = NULL;
- NS_UNMOCK(circuit_get_global_list);
+ UNMOCK(circuit_get_global_list);
}
static smartlist_t *
-NS(circuit_get_global_list)(void)
+status_count_circuits_circuit_get_global_list(void)
{
return mock_global_circuitlist;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE secs_to_uptime
-
/*
* Test that secs_to_uptime() is converting the number of seconds that
* Tor is up for into the appropriate string form containing hours and minutes.
*/
static void
-NS(test_main)(void *arg)
+test_status_secs_to_uptime(void *arg)
{
const char *expected;
char *actual;
@@ -161,9 +155,6 @@ NS(test_main)(void *arg)
tor_free(actual);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE bytes_to_usage
-
/*
* Test that bytes_to_usage() is correctly converting the number of bytes that
* Tor has read/written into the appropriate string form containing kilobytes,
@@ -171,7 +162,7 @@ NS(test_main)(void *arg)
*/
static void
-NS(test_main)(void *arg)
+test_status_bytes_to_usage(void *arg)
{
const char *expected;
char *actual;
@@ -242,29 +233,30 @@ NS(test_main)(void *arg)
tor_free(actual);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, fails)
-
/*
* Tests that log_heartbeat() fails when in the public server mode,
* not hibernating, and we couldn't get the current routerinfo.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static double status_hb_fails_tls_get_write_overhead_ratio(void);
+static int status_hb_fails_we_are_hibernating(void);
+static int status_hb_fails_public_server_mode(const or_options_t *options);
+static const routerinfo_t * status_hb_fails_router_get_my_routerinfo(void);
static void
-NS(test_main)(void *arg)
+test_status_hb_fails(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_fails_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_fails_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_fails_public_server_mode);
+ MOCK(router_get_my_routerinfo,
+ status_hb_fails_router_get_my_routerinfo);
expected = -1;
actual = log_heartbeat(0);
@@ -272,26 +264,26 @@ NS(test_main)(void *arg)
tt_int_op(actual, OP_EQ, expected);
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(router_get_my_routerinfo);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_fails_tls_get_write_overhead_ratio(void)
{
return 2.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_fails_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_fails_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -299,43 +291,51 @@ NS(public_server_mode)(const or_options_t *options)
}
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+status_hb_fails_router_get_my_routerinfo(void)
{
return NULL;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, not_in_consensus)
-
/*
* Tests that log_heartbeat() logs appropriately if we are not in the cached
* consensus.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
-NS_DECL(const node_t *, node_get_by_id, (const char *identity_digest));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
+static double status_hb_not_in_consensus_tls_get_write_overhead_ratio(void);
+static int status_hb_not_in_consensus_we_are_hibernating(void);
+static int status_hb_not_in_consensus_public_server_mode(
+ const or_options_t *options);
+static const routerinfo_t *status_hb_not_in_consensus_get_my_routerinfo(void);
+static const node_t * status_hb_not_in_consensus_node_get_by_id(
+ const char *identity_digest);
+static void status_hb_not_in_consensus_logv(
+ int severity, log_domain_mask_t domain, const char *funcname,
+ const char *suffix, const char *format, va_list ap);
+static int status_hb_not_in_consensus_logv_called = 0;
+static int status_hb_not_in_consensus_server_mode(const or_options_t *options);
static routerinfo_t *mock_routerinfo;
static void
-NS(test_main)(void *arg)
+test_status_hb_not_in_consensus(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(router_get_my_routerinfo);
- NS_MOCK(node_get_by_id);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_not_in_consensus_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_not_in_consensus_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_not_in_consensus_public_server_mode);
+ MOCK(router_get_my_routerinfo,
+ status_hb_not_in_consensus_get_my_routerinfo);
+ MOCK(node_get_by_id,
+ status_hb_not_in_consensus_node_get_by_id);
+ MOCK(logv,
+ status_hb_not_in_consensus_logv);
+ MOCK(server_mode,
+ status_hb_not_in_consensus_server_mode);
log_global_min_severity_ = LOG_DEBUG;
onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP] = 1;
@@ -347,33 +347,33 @@ NS(test_main)(void *arg)
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 6);
+ tt_int_op(status_hb_not_in_consensus_logv_called, OP_EQ, 6);
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(router_get_my_routerinfo);
- NS_UNMOCK(node_get_by_id);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(router_get_my_routerinfo);
+ UNMOCK(node_get_by_id);
+ UNMOCK(logv);
+ UNMOCK(server_mode);
tor_free(mock_routerinfo);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_not_in_consensus_tls_get_write_overhead_ratio(void)
{
return 1.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_not_in_consensus_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_not_in_consensus_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -381,7 +381,7 @@ NS(public_server_mode)(const or_options_t *options)
}
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+status_hb_not_in_consensus_get_my_routerinfo(void)
{
mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
@@ -389,7 +389,7 @@ NS(router_get_my_routerinfo)(void)
}
static const node_t *
-NS(node_get_by_id)(const char *identity_digest)
+status_hb_not_in_consensus_node_get_by_id(const char *identity_digest)
{
(void)identity_digest;
@@ -397,10 +397,10 @@ NS(node_get_by_id)(const char *identity_digest)
}
static void
-NS(logv)(int severity, log_domain_mask_t domain,
+status_hb_not_in_consensus_logv(int severity, log_domain_mask_t domain,
const char *funcname, const char *suffix, const char *format, va_list ap)
{
- switch (CALLED(logv))
+ switch (status_hb_not_in_consensus_logv_called)
{
case 0:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
@@ -449,12 +449,13 @@ NS(logv)(int severity, log_domain_mask_t domain,
case 5:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s");
+ tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s%s");
tt_str_op(va_arg(ap, char *), OP_EQ,
" 0 circuits killed with too many cells.");
tt_str_op(va_arg(ap, char *), OP_EQ, " [cc not enabled]");
tt_str_op(va_arg(ap, char *), OP_EQ, " [conn not enabled]");
tt_str_op(va_arg(ap, char *), OP_EQ, "");
+ tt_str_op(va_arg(ap, char *), OP_EQ, " 0 INTRODUCE2 rejected.");
break;
default:
tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
@@ -462,51 +463,58 @@ NS(logv)(int severity, log_domain_mask_t domain,
}
done:
- CALLED(logv)++;
+ status_hb_not_in_consensus_logv_called++;
}
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_not_in_consensus_server_mode(const or_options_t *options)
{
(void)options;
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, simple)
-
/*
* Tests that log_heartbeat() correctly logs heartbeat information
* normally.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(long, get_uptime, (void));
-NS_DECL(uint64_t, get_bytes_read, (void));
-NS_DECL(uint64_t, get_bytes_written, (void));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
+static double status_hb_simple_tls_get_write_overhead_ratio(void);
+static int status_hb_simple_we_are_hibernating(void);
+static int status_hb_simple_public_server_mode(const or_options_t *options);
+static long status_hb_simple_get_uptime(void);
+static uint64_t status_hb_simple_get_bytes_read(void);
+static uint64_t status_hb_simple_get_bytes_written(void);
+static void status_hb_simple_logv(int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix,
+ const char *format, va_list ap);
+ATTR_UNUSED static int status_hb_simple_logv_called = 0;
+static int status_hb_simple_server_mode(const or_options_t *options);
-static int NS(n_msgs) = 0;
+static int status_hb_simple_n_msgs = 0;
static void
-NS(test_main)(void *arg)
+test_status_hb_simple(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(get_uptime);
- NS_MOCK(get_bytes_read);
- NS_MOCK(get_bytes_written);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_simple_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_simple_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_simple_public_server_mode);
+ MOCK(get_uptime,
+ status_hb_simple_get_uptime);
+ MOCK(get_bytes_read,
+ status_hb_simple_get_bytes_read);
+ MOCK(get_bytes_written,
+ status_hb_simple_get_bytes_written);
+ MOCK(logv,
+ status_hb_simple_logv);
+ MOCK(server_mode,
+ status_hb_simple_server_mode);
log_global_min_severity_ = LOG_DEBUG;
@@ -514,33 +522,33 @@ NS(test_main)(void *arg)
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(NS(n_msgs), OP_EQ, 1);
+ tt_int_op(status_hb_simple_n_msgs, OP_EQ, 1);
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(get_uptime);
- NS_UNMOCK(get_bytes_read);
- NS_UNMOCK(get_bytes_written);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(get_uptime);
+ UNMOCK(get_bytes_read);
+ UNMOCK(get_bytes_written);
+ UNMOCK(logv);
+ UNMOCK(server_mode);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_simple_tls_get_write_overhead_ratio(void)
{
return 1.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_simple_we_are_hibernating(void)
{
return 1;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_simple_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -548,30 +556,31 @@ NS(public_server_mode)(const or_options_t *options)
}
static long
-NS(get_uptime)(void)
+status_hb_simple_get_uptime(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_read)(void)
+status_hb_simple_get_bytes_read(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_written)(void)
+status_hb_simple_get_bytes_written(void)
{
return 0;
}
static void
-NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
+status_hb_simple_logv(int severity, log_domain_mask_t domain,
+ const char *funcname,
const char *suffix, const char *format, va_list ap)
{
if (severity == LOG_INFO)
return;
- ++NS(n_msgs);
+ ++status_hb_simple_n_msgs;
tt_int_op(severity, OP_EQ, LOG_NOTICE);
tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
@@ -591,54 +600,69 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
}
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_simple_server_mode(const or_options_t *options)
{
(void)options;
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, calls_log_accounting)
-
/*
* Tests that log_heartbeat() correctly logs heartbeat information
* and accounting information when configured.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(long, get_uptime, (void));
-NS_DECL(uint64_t, get_bytes_read, (void));
-NS_DECL(uint64_t, get_bytes_written, (void));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
-NS_DECL(or_state_t *, get_or_state, (void));
-NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
-NS_DECL(time_t, accounting_get_end_time, (void));
-
-static or_state_t * NS(mock_state) = NULL;
-static or_options_t * NS(mock_options) = NULL;
+static double status_hb_calls_log_accounting_tls_get_write_overhead_ratio(
+ void);
+static int status_hb_calls_log_accounting_we_are_hibernating(void);
+static int status_hb_calls_log_accounting_public_server_mode(
+ const or_options_t *options);
+static long status_hb_calls_log_accounting_get_uptime(void);
+static uint64_t status_hb_calls_log_accounting_get_bytes_read(void);
+static uint64_t status_hb_calls_log_accounting_get_bytes_written(void);
+static void status_hb_calls_log_accounting_logv(
+ int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix,
+ const char *format, va_list ap);
+static int status_hb_calls_log_accounting_logv_called = 0;
+static int status_hb_calls_log_accounting_server_mode(
+ const or_options_t *options);
+static or_state_t * status_hb_calls_log_accounting_get_or_state(void);
+static int status_hb_calls_log_accounting_accounting_is_enabled(
+ const or_options_t *options);
+static time_t status_hb_calls_log_accounting_accounting_get_end_time(void);
+
+static or_state_t * status_hb_calls_log_accounting_mock_state = NULL;
+static or_options_t * status_hb_calls_log_accounting_mock_options = NULL;
static void
-NS(test_main)(void *arg)
+test_status_hb_calls_log_accounting(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(get_uptime);
- NS_MOCK(get_bytes_read);
- NS_MOCK(get_bytes_written);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
- NS_MOCK(get_or_state);
- NS_MOCK(accounting_is_enabled);
- NS_MOCK(accounting_get_end_time);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_calls_log_accounting_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_calls_log_accounting_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_calls_log_accounting_public_server_mode);
+ MOCK(get_uptime,
+ status_hb_calls_log_accounting_get_uptime);
+ MOCK(get_bytes_read,
+ status_hb_calls_log_accounting_get_bytes_read);
+ MOCK(get_bytes_written,
+ status_hb_calls_log_accounting_get_bytes_written);
+ MOCK(logv,
+ status_hb_calls_log_accounting_logv);
+ MOCK(server_mode,
+ status_hb_calls_log_accounting_server_mode);
+ MOCK(get_or_state,
+ status_hb_calls_log_accounting_get_or_state);
+ MOCK(accounting_is_enabled,
+ status_hb_calls_log_accounting_accounting_is_enabled);
+ MOCK(accounting_get_end_time,
+ status_hb_calls_log_accounting_accounting_get_end_time);
log_global_min_severity_ = LOG_DEBUG;
@@ -646,37 +670,37 @@ NS(test_main)(void *arg)
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 3);
+ tt_int_op(status_hb_calls_log_accounting_logv_called, OP_EQ, 3);
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(get_uptime);
- NS_UNMOCK(get_bytes_read);
- NS_UNMOCK(get_bytes_written);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
- NS_UNMOCK(accounting_is_enabled);
- NS_UNMOCK(accounting_get_end_time);
- tor_free_(NS(mock_state));
- tor_free_(NS(mock_options));
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(get_uptime);
+ UNMOCK(get_bytes_read);
+ UNMOCK(get_bytes_written);
+ UNMOCK(logv);
+ UNMOCK(server_mode);
+ UNMOCK(accounting_is_enabled);
+ UNMOCK(accounting_get_end_time);
+ tor_free_(status_hb_calls_log_accounting_mock_state);
+ tor_free_(status_hb_calls_log_accounting_mock_options);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_calls_log_accounting_tls_get_write_overhead_ratio(void)
{
return 1.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_calls_log_accounting_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_calls_log_accounting_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -684,28 +708,28 @@ NS(public_server_mode)(const or_options_t *options)
}
static long
-NS(get_uptime)(void)
+status_hb_calls_log_accounting_get_uptime(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_read)(void)
+status_hb_calls_log_accounting_get_bytes_read(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_written)(void)
+status_hb_calls_log_accounting_get_bytes_written(void)
{
return 0;
}
static void
-NS(logv)(int severity, log_domain_mask_t domain,
+status_hb_calls_log_accounting_logv(int severity, log_domain_mask_t domain,
const char *funcname, const char *suffix, const char *format, va_list ap)
{
- switch (CALLED(logv))
+ switch (status_hb_calls_log_accounting_logv_called)
{
case 0:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
@@ -750,11 +774,11 @@ NS(logv)(int severity, log_domain_mask_t domain,
}
done:
- CALLED(logv)++;
+ status_hb_calls_log_accounting_logv_called++;
}
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_calls_log_accounting_server_mode(const or_options_t *options)
{
(void)options;
@@ -762,7 +786,8 @@ NS(server_mode)(const or_options_t *options)
}
static int
-NS(accounting_is_enabled)(const or_options_t *options)
+status_hb_calls_log_accounting_accounting_is_enabled(
+ const or_options_t *options)
{
(void)options;
@@ -770,55 +795,71 @@ NS(accounting_is_enabled)(const or_options_t *options)
}
static time_t
-NS(accounting_get_end_time)(void)
+status_hb_calls_log_accounting_accounting_get_end_time(void)
{
return 60;
}
static or_state_t *
-NS(get_or_state)(void)
+status_hb_calls_log_accounting_get_or_state(void)
{
- NS(mock_state) = tor_malloc_zero(sizeof(or_state_t));
- NS(mock_state)->AccountingBytesReadInInterval = 0;
- NS(mock_state)->AccountingBytesWrittenInInterval = 0;
-
- return NS(mock_state);
+ status_hb_calls_log_accounting_mock_state =
+ tor_malloc_zero(sizeof(or_state_t));
+ status_hb_calls_log_accounting_mock_state
+ ->AccountingBytesReadInInterval = 0;
+ status_hb_calls_log_accounting_mock_state
+ ->AccountingBytesWrittenInInterval = 0;
+
+ return status_hb_calls_log_accounting_mock_state;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, packaged_cell_fullness)
-
/*
* Tests that log_heartbeat() correctly logs packaged cell
* fullness information.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(long, get_uptime, (void));
-NS_DECL(uint64_t, get_bytes_read, (void));
-NS_DECL(uint64_t, get_bytes_written, (void));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
-NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
+static double status_hb_packaged_cell_fullness_tls_get_write_overhead_ratio(
+ void);
+static int status_hb_packaged_cell_fullness_we_are_hibernating(void);
+static int status_hb_packaged_cell_fullness_public_server_mode(
+ const or_options_t *options);
+static long status_hb_packaged_cell_fullness_get_uptime(void);
+static uint64_t status_hb_packaged_cell_fullness_get_bytes_read(void);
+static uint64_t status_hb_packaged_cell_fullness_get_bytes_written(void);
+static void status_hb_packaged_cell_fullness_logv(
+ int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix,
+ const char *format, va_list ap);
+static int status_hb_packaged_cell_fullness_logv_called = 0;
+static int status_hb_packaged_cell_fullness_server_mode(
+ const or_options_t *options);
+static int status_hb_packaged_cell_fullness_accounting_is_enabled(
+ const or_options_t *options);
static void
-NS(test_main)(void *arg)
+test_status_hb_packaged_cell_fullness(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(get_uptime);
- NS_MOCK(get_bytes_read);
- NS_MOCK(get_bytes_written);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
- NS_MOCK(accounting_is_enabled);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_packaged_cell_fullness_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_packaged_cell_fullness_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_packaged_cell_fullness_public_server_mode);
+ MOCK(get_uptime,
+ status_hb_packaged_cell_fullness_get_uptime);
+ MOCK(get_bytes_read,
+ status_hb_packaged_cell_fullness_get_bytes_read);
+ MOCK(get_bytes_written,
+ status_hb_packaged_cell_fullness_get_bytes_written);
+ MOCK(logv,
+ status_hb_packaged_cell_fullness_logv);
+ MOCK(server_mode,
+ status_hb_packaged_cell_fullness_server_mode);
+ MOCK(accounting_is_enabled,
+ status_hb_packaged_cell_fullness_accounting_is_enabled);
log_global_min_severity_ = LOG_DEBUG;
stats_n_data_bytes_packaged = RELAY_PAYLOAD_SIZE;
@@ -827,36 +868,37 @@ NS(test_main)(void *arg)
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 2);
+ tt_int_op(status_hb_packaged_cell_fullness_logv_called, OP_EQ, 2);
done:
stats_n_data_bytes_packaged = 0;
stats_n_data_cells_packaged = 0;
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(get_uptime);
- NS_UNMOCK(get_bytes_read);
- NS_UNMOCK(get_bytes_written);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
- NS_UNMOCK(accounting_is_enabled);
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(get_uptime);
+ UNMOCK(get_bytes_read);
+ UNMOCK(get_bytes_written);
+ UNMOCK(logv);
+ UNMOCK(server_mode);
+ UNMOCK(accounting_is_enabled);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_packaged_cell_fullness_tls_get_write_overhead_ratio(void)
{
return 1.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_packaged_cell_fullness_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_packaged_cell_fullness_public_server_mode(
+ const or_options_t *options)
{
(void)options;
@@ -864,28 +906,29 @@ NS(public_server_mode)(const or_options_t *options)
}
static long
-NS(get_uptime)(void)
+status_hb_packaged_cell_fullness_get_uptime(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_read)(void)
+status_hb_packaged_cell_fullness_get_bytes_read(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_written)(void)
+status_hb_packaged_cell_fullness_get_bytes_written(void)
{
return 0;
}
static void
-NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
+status_hb_packaged_cell_fullness_logv(int severity,
+ log_domain_mask_t domain, const char *funcname,
const char *suffix, const char *format, va_list ap)
{
- switch (CALLED(logv))
+ switch (status_hb_packaged_cell_fullness_logv_called)
{
case 0:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
@@ -918,11 +961,11 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
}
done:
- CALLED(logv)++;
+ status_hb_packaged_cell_fullness_logv_called++;
}
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_packaged_cell_fullness_server_mode(const or_options_t *options)
{
(void)options;
@@ -930,47 +973,60 @@ NS(server_mode)(const or_options_t *options)
}
static int
-NS(accounting_is_enabled)(const or_options_t *options)
+status_hb_packaged_cell_fullness_accounting_is_enabled(
+ const or_options_t *options)
{
(void)options;
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, tls_write_overhead)
-
/*
* Tests that log_heartbeat() correctly logs the TLS write overhead information
* when the TLS write overhead ratio exceeds 1.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(long, get_uptime, (void));
-NS_DECL(uint64_t, get_bytes_read, (void));
-NS_DECL(uint64_t, get_bytes_written, (void));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
-NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
+static double status_hb_tls_write_overhead_tls_get_write_overhead_ratio(void);
+static int status_hb_tls_write_overhead_we_are_hibernating(void);
+static int status_hb_tls_write_overhead_public_server_mode(
+ const or_options_t *options);
+static long status_hb_tls_write_overhead_get_uptime(void);
+static uint64_t status_hb_tls_write_overhead_get_bytes_read(void);
+static uint64_t status_hb_tls_write_overhead_get_bytes_written(void);
+static void status_hb_tls_write_overhead_logv(
+ int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix,
+ const char *format, va_list ap);
+static int status_hb_tls_write_overhead_logv_called = 0;
+static int status_hb_tls_write_overhead_server_mode(
+ const or_options_t *options);
+static int status_hb_tls_write_overhead_accounting_is_enabled(
+ const or_options_t *options);
static void
-NS(test_main)(void *arg)
+test_status_hb_tls_write_overhead(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(get_uptime);
- NS_MOCK(get_bytes_read);
- NS_MOCK(get_bytes_written);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
- NS_MOCK(accounting_is_enabled);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_tls_write_overhead_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_tls_write_overhead_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_tls_write_overhead_public_server_mode);
+ MOCK(get_uptime,
+ status_hb_tls_write_overhead_get_uptime);
+ MOCK(get_bytes_read,
+ status_hb_tls_write_overhead_get_bytes_read);
+ MOCK(get_bytes_written,
+ status_hb_tls_write_overhead_get_bytes_written);
+ MOCK(logv,
+ status_hb_tls_write_overhead_logv);
+ MOCK(server_mode,
+ status_hb_tls_write_overhead_server_mode);
+ MOCK(accounting_is_enabled,
+ status_hb_tls_write_overhead_accounting_is_enabled);
stats_n_data_cells_packaged = 0;
log_global_min_severity_ = LOG_DEBUG;
@@ -978,34 +1034,34 @@ NS(test_main)(void *arg)
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 2);
+ tt_int_op(status_hb_tls_write_overhead_logv_called, OP_EQ, 2);
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(get_uptime);
- NS_UNMOCK(get_bytes_read);
- NS_UNMOCK(get_bytes_written);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
- NS_UNMOCK(accounting_is_enabled);
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(get_uptime);
+ UNMOCK(get_bytes_read);
+ UNMOCK(get_bytes_written);
+ UNMOCK(logv);
+ UNMOCK(server_mode);
+ UNMOCK(accounting_is_enabled);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_tls_write_overhead_tls_get_write_overhead_ratio(void)
{
return 2.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_tls_write_overhead_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_tls_write_overhead_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -1013,28 +1069,28 @@ NS(public_server_mode)(const or_options_t *options)
}
static long
-NS(get_uptime)(void)
+status_hb_tls_write_overhead_get_uptime(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_read)(void)
+status_hb_tls_write_overhead_get_bytes_read(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_written)(void)
+status_hb_tls_write_overhead_get_bytes_written(void)
{
return 0;
}
static void
-NS(logv)(int severity, log_domain_mask_t domain,
+status_hb_tls_write_overhead_logv(int severity, log_domain_mask_t domain,
const char *funcname, const char *suffix, const char *format, va_list ap)
{
- switch (CALLED(logv))
+ switch (status_hb_tls_write_overhead_logv_called)
{
case 0:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
@@ -1067,11 +1123,11 @@ NS(logv)(int severity, log_domain_mask_t domain,
}
done:
- CALLED(logv)++;
+ status_hb_tls_write_overhead_logv_called++;
}
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_tls_write_overhead_server_mode(const or_options_t *options)
{
(void)options;
@@ -1079,24 +1135,26 @@ NS(server_mode)(const or_options_t *options)
}
static int
-NS(accounting_is_enabled)(const or_options_t *options)
+status_hb_tls_write_overhead_accounting_is_enabled(const or_options_t *options)
{
(void)options;
return 0;
}
-#undef NS_SUBMODULE
-
struct testcase_t status_tests[] = {
- TEST_CASE(count_circuits),
- TEST_CASE(secs_to_uptime),
- TEST_CASE(bytes_to_usage),
- TEST_CASE_ASPECT(log_heartbeat, fails),
- TEST_CASE_ASPECT(log_heartbeat, simple),
- TEST_CASE_ASPECT(log_heartbeat, not_in_consensus),
- TEST_CASE_ASPECT(log_heartbeat, calls_log_accounting),
- TEST_CASE_ASPECT(log_heartbeat, packaged_cell_fullness),
- TEST_CASE_ASPECT(log_heartbeat, tls_write_overhead),
+ { "count_circuits", test_status_count_circuits, TT_FORK, NULL, NULL },
+ { "secs_to_uptime", test_status_secs_to_uptime, TT_FORK, NULL, NULL },
+ { "bytes_to_usage", test_status_bytes_to_usage, TT_FORK, NULL, NULL },
+ { "hb_fails", test_status_hb_fails, TT_FORK, NULL, NULL },
+ { "hb_simple", test_status_hb_simple, TT_FORK, NULL, NULL },
+ { "hb_not_in_consensus", test_status_hb_not_in_consensus,
+ TT_FORK, NULL, NULL },
+ { "hb_calls_log_accounting", test_status_hb_calls_log_accounting,
+ TT_FORK, NULL, NULL },
+ { "hb_packaged_cell_fullness", test_status_hb_packaged_cell_fullness,
+ TT_FORK, NULL, NULL },
+ { "hb_tls_write_overhead", test_status_hb_tls_write_overhead,
+ TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c
index 24e45c7428..eb3779cfee 100644
--- a/src/test/test_storagedir.c
+++ b/src/test/test_storagedir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, 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 19483713f7..ca189a9cf5 100644
--- a/src/test/test_switch_id.c
+++ b/src/test/test_switch_id.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, 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 4a5ecc6fae..d5a1834aef 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -155,7 +155,7 @@ test_threads_basic(void *arg)
tor_mutex_free(thread_test_start2_);
}
-typedef struct cv_testinfo_s {
+typedef struct cv_testinfo_t {
tor_cond_t *cond;
tor_mutex_t *mutex;
int value;
diff --git a/src/test/test_token_bucket.c b/src/test/test_token_bucket.c
index 31670718d9..cf315f2944 100644
--- a/src/test/test_token_bucket.c
+++ b/src/test/test_token_bucket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index d59b8e001d..12ba873650 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TORTLS_PRIVATE
@@ -225,7 +225,7 @@ test_tortls_tor_tls_get_error(void *data)
done:
UNMOCK(tor_tls_cert_matches_key);
- NS_UNMOCK(logv);
+ UNMOCK(logv);
crypto_pk_free(key1);
crypto_pk_free(key2);
tor_tls_free(tls);
diff --git a/src/test/test_tortls.h b/src/test/test_tortls.h
index 4567b9f6a0..21c6fa0a8f 100644
--- a/src/test/test_tortls.h
+++ b/src/test/test_tortls.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, 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 93135d0b19..e20b0d1ede 100644
--- a/src/test/test_tortls_openssl.c
+++ b/src/test/test_tortls_openssl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TORTLS_PRIVATE
@@ -16,7 +16,7 @@
/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
* srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/opensslv.h>
@@ -29,7 +29,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/evp.h>
#include <openssl/bn.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#include "core/or/or.h"
#include "lib/log/log.h"
@@ -46,8 +46,6 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "test/log_test_helpers.h"
#include "test/test_tortls.h"
-#define NS_MODULE tortls
-
#ifndef HAVE_SSL_STATE
#define OPENSSL_OPAQUE
#endif
@@ -123,8 +121,6 @@ test_tortls_tor_tls_new(void *data)
tor_tls_free_all();
}
-#define NS_MODULE tortls
-
static void
library_init(void)
{
diff --git a/src/test/test_util.c b/src/test/test_util.c
index aebefe64c5..7700cfa2b1 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,14 +1,11 @@
/* 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-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
-#define COMPAT_PRIVATE
#define COMPAT_TIME_PRIVATE
-#define UTIL_PRIVATE
#define UTIL_MALLOC_PRIVATE
-#define SOCKET_PRIVATE
#define PROCESS_WIN32_PRIVATE
#include "lib/testsupport/testsupport.h"
#include "core/or/or.h"
@@ -33,6 +30,7 @@
#include "lib/process/env.h"
#include "lib/process/pidfile.h"
#include "lib/intmath/weakrng.h"
+#include "lib/intmath/muldiv.h"
#include "lib/thread/numcpus.h"
#include "lib/math/fp.h"
#include "lib/math/laplace.h"
@@ -74,6 +72,11 @@
#include <ctype.h>
#include <float.h>
+/* These platforms don't have meaningful pwdb or homedirs. */
+#if defined(_WIN32) || defined(__ANDROID__)
+#define DISABLE_PWDB_TESTS
+#endif
+
#define INFINITY_DBL ((double)INFINITY)
#define NAN_DBL ((double)NAN)
@@ -304,6 +307,7 @@ test_util_write_chunks_to_file(void *arg)
tor_free(temp_str);
}
+#ifndef COCCI
#define _TFE(a, b, f) tt_int_op((a).f, OP_EQ, (b).f)
/** test the minimum set of struct tm fields needed for a unique epoch value
* this is also the set we use to test tor_timegm */
@@ -316,6 +320,7 @@ test_util_write_chunks_to_file(void *arg)
_TFE(a, b, tm_min ); \
_TFE(a, b, tm_sec ); \
TT_STMT_END
+#endif /* !defined(COCCI) */
static void
test_util_time(void *arg)
@@ -1845,7 +1850,57 @@ test_util_config_line_crlf(void *arg)
tor_free(k); tor_free(v);
}
-#ifndef _WIN32
+static void
+test_util_config_line_partition(void *arg)
+{
+ (void)arg;
+ config_line_t *lines = NULL, *orig, *rest = NULL;
+
+ config_line_append(&lines, "Header", "X");
+ config_line_append(&lines, "Item", "Y");
+ config_line_append(&lines, "Thing", "Z");
+
+ config_line_append(&lines, "HEADER", "X2");
+
+ config_line_append(&lines, "header", "X3");
+ config_line_append(&lines, "Item3", "Foob");
+
+ /* set up h2 and h3 to point to the places where we hope the headers will
+ be. */
+ config_line_t *h2 = lines->next->next->next;
+ config_line_t *h3 = h2->next;
+ tt_str_op(h2->key, OP_EQ, "HEADER");
+ tt_str_op(h3->key, OP_EQ, "header");
+
+ orig = lines;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, h2);
+ tt_str_op(lines->next->key, OP_EQ, "Item");
+ tt_str_op(lines->next->next->key, OP_EQ, "Thing");
+ tt_ptr_op(lines->next->next->next, OP_EQ, NULL);
+ config_free_lines(lines);
+
+ orig = lines = rest;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, h3);
+ tt_ptr_op(lines->next, OP_EQ, NULL);
+ config_free_lines(lines);
+
+ orig = lines = rest;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, NULL);
+ tt_str_op(lines->next->key, OP_EQ, "Item3");
+ tt_ptr_op(lines->next->next, OP_EQ, NULL);
+
+ done:
+ config_free_lines(lines);
+ config_free_lines(rest);
+}
+
+#ifndef DISABLE_PWDB_TESTS
static void
test_util_expand_filename(void *arg)
{
@@ -1942,7 +1997,7 @@ test_util_expand_filename(void *arg)
done:
tor_free(str);
}
-#endif /* !defined(_WIN32) */
+#endif /* !defined(DISABLE_PWDB_TESTS) */
/** Test tor_escape_str_for_pt_args(). */
static void
@@ -4104,10 +4159,43 @@ test_util_string_is_utf8(void *ptr)
tt_int_op(0, OP_EQ, string_is_utf8("\xed\xbf\xbf", 3));
tt_int_op(1, OP_EQ, string_is_utf8("\xee\x80\x80", 3));
- // The maximum legal codepoint, 10FFFF.
+ // The minimum legal codepoint, 0x00.
+ tt_int_op(1, OP_EQ, string_is_utf8("\0", 1));
+
+ // The maximum legal codepoint, 0x10FFFF.
tt_int_op(1, OP_EQ, string_is_utf8("\xf4\x8f\xbf\xbf", 4));
tt_int_op(0, OP_EQ, string_is_utf8("\xf4\x90\x80\x80", 4));
+ /* Test cases that vary between programming languages /
+ * UTF-8 implementations.
+ * Source: POC||GTFO 19, page 43
+ * https://www.alchemistowl.org/pocorgtfo/
+ */
+
+ // Invalid (in most implementations)
+ // surrogate
+ tt_int_op(0, OP_EQ, string_is_utf8("\xed\xa0\x81", 3));
+ // nullsurrog
+ tt_int_op(0, OP_EQ, string_is_utf8("\x30\x00\xed\xa0\x81", 5));
+ // threehigh
+ tt_int_op(0, OP_EQ, string_is_utf8("\xed\xbf\xbf", 3));
+ // fourhigh
+ tt_int_op(0, OP_EQ, string_is_utf8("\xf4\x90\xbf\xbf", 4));
+ // fivebyte
+ tt_int_op(0, OP_EQ, string_is_utf8("\xfb\x80\x80\x80\x80", 5));
+ // sixbyte
+ tt_int_op(0, OP_EQ, string_is_utf8("\xfd\x80\x80\x80\x80", 5));
+ // sixhigh
+ tt_int_op(0, OP_EQ, string_is_utf8("\xfd\xbf\xbf\xbf\xbf", 5));
+
+ // Valid (in most implementations)
+ // fourbyte
+ tt_int_op(1, OP_EQ, string_is_utf8("\xf0\x90\x8d\x88", 4));
+ // fourbyte2
+ tt_int_op(1, OP_EQ, string_is_utf8("\xf0\xbf\xbf\xbf", 4));
+ // nullbyte
+ tt_int_op(1, OP_EQ, string_is_utf8("\x30\x31\x32\x00\x33", 5));
+
done:
;
}
@@ -4534,6 +4622,35 @@ test_util_di_ops(void *arg)
}
static void
+test_util_memcpy_iftrue_timei(void *arg)
+{
+ (void)arg;
+ char buf1[25];
+ char buf2[25];
+ char buf3[25];
+
+ for (int i = 0; i < 100; ++i) {
+ crypto_rand(buf1, sizeof(buf1));
+ crypto_rand(buf2, sizeof(buf2));
+ memcpy(buf3, buf1, sizeof(buf1));
+
+ /* We just copied buf1 into buf3. Now we're going to copy buf2 into buf2,
+ iff our coin flip comes up heads. */
+ bool coinflip = crypto_rand_int(2) == 0;
+
+ memcpy_if_true_timei(coinflip, buf3, buf2, sizeof(buf3));
+
+ if (coinflip) {
+ tt_mem_op(buf3, OP_EQ, buf2, sizeof(buf2));
+ } else {
+ tt_mem_op(buf3, OP_EQ, buf1, sizeof(buf1));
+ }
+ }
+ done:
+ ;
+}
+
+static void
test_util_di_map(void *arg)
{
(void)arg;
@@ -5534,7 +5651,7 @@ test_util_hostname_validation(void *arg)
tt_assert(string_is_valid_nonrfc_hostname("luck.y13."));
// We allow punycode TLDs. For examples, see
- // http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ // https://data.iana.org/TLD/tlds-alpha-by-domain.txt
tt_assert(string_is_valid_nonrfc_hostname("example.xn--l1acc"));
done:
@@ -5653,7 +5770,7 @@ test_util_touch_file(void *arg)
;
}
-#ifndef _WIN32
+#ifndef DISABLE_PWDB_TESTS
static void
test_util_pwdb(void *arg)
{
@@ -5725,7 +5842,7 @@ test_util_pwdb(void *arg)
tor_free(dir);
teardown_capture_of_logs();
}
-#endif /* !defined(_WIN32) */
+#endif /* !defined(DISABLE_PWDB_TESTS) */
static void
test_util_calloc_check(void *arg)
@@ -5973,6 +6090,14 @@ test_util_nowrap_math(void *arg)
tt_u64_op(UINT32_MAX, OP_EQ, tor_add_u32_nowrap(2, UINT32_MAX-1));
tt_u64_op(UINT32_MAX, OP_EQ, tor_add_u32_nowrap(UINT32_MAX, UINT32_MAX));
+ tt_u64_op(0, OP_EQ, tor_mul_u64_nowrap(0, 0));
+ tt_u64_op(1, OP_EQ, tor_mul_u64_nowrap(1, 1));
+ tt_u64_op(2, OP_EQ, tor_mul_u64_nowrap(2, 1));
+ tt_u64_op(4, OP_EQ, tor_mul_u64_nowrap(2, 2));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_mul_u64_nowrap(UINT64_MAX, 1));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_mul_u64_nowrap(2, UINT64_MAX));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_mul_u64_nowrap(UINT64_MAX, UINT64_MAX));
+
done:
;
}
@@ -6257,40 +6382,44 @@ test_util_map_anon_nofork(void *arg)
#endif /* defined(_WIN32) */
}
+#ifndef COCCI
#define UTIL_LEGACY(name) \
- { #name, test_util_ ## name , 0, NULL, NULL }
+ { (#name), test_util_ ## name , 0, NULL, NULL }
#define UTIL_TEST(name, flags) \
- { #name, test_util_ ## name, flags, NULL, NULL }
+ { (#name), test_util_ ## name, flags, NULL, NULL }
#define COMPRESS(name, identifier) \
- { "compress/" #name, test_util_compress, 0, &compress_setup, \
+ { ("compress/" #name), test_util_compress, 0, &compress_setup, \
(char*)(identifier) }
#define COMPRESS_CONCAT(name, identifier) \
- { "compress_concat/" #name, test_util_decompress_concatenated, 0, \
+ { ("compress_concat/" #name), test_util_decompress_concatenated, 0, \
&compress_setup, \
(char*)(identifier) }
#define COMPRESS_JUNK(name, identifier) \
- { "compress_junk/" #name, test_util_decompress_junk, 0, \
+ { ("compress_junk/" #name), test_util_decompress_junk, 0, \
&compress_setup, \
(char*)(identifier) }
#define COMPRESS_DOS(name, identifier) \
- { "compress_dos/" #name, test_util_decompress_dos, 0, \
+ { ("compress_dos/" #name), test_util_decompress_dos, 0, \
&compress_setup, \
(char*)(identifier) }
#ifdef _WIN32
-#define UTIL_TEST_NO_WIN(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
#define UTIL_TEST_WIN_ONLY(n, f) UTIL_TEST(n, (f))
-#define UTIL_LEGACY_NO_WIN(n) UTIL_TEST_NO_WIN(n, 0)
#else
-#define UTIL_TEST_NO_WIN(n, f) UTIL_TEST(n, (f))
-#define UTIL_TEST_WIN_ONLY(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
-#define UTIL_LEGACY_NO_WIN(n) UTIL_LEGACY(n)
-#endif /* defined(_WIN32) */
+#define UTIL_TEST_WIN_ONLY(n, f) { (#n), NULL, TT_SKIP, NULL, NULL }
+#endif
+
+#ifdef DISABLE_PWDB_TESTS
+#define UTIL_TEST_PWDB(n, f) { (#n), NULL, TT_SKIP, NULL, NULL }
+#else
+#define UTIL_TEST_PWDB(n, f) UTIL_TEST(n, (f))
+#endif
+#endif /* !defined(COCCI) */
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
@@ -6300,7 +6429,8 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(config_line_comment_character),
UTIL_LEGACY(config_line_escaped_content),
UTIL_LEGACY(config_line_crlf),
- UTIL_LEGACY_NO_WIN(expand_filename),
+ UTIL_TEST(config_line_partition, 0),
+ UTIL_TEST_PWDB(expand_filename, 0),
UTIL_LEGACY(escape_string_socks),
UTIL_LEGACY(string_is_key_value),
UTIL_LEGACY(strmisc),
@@ -6336,6 +6466,7 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(path_is_relative),
UTIL_LEGACY(strtok),
UTIL_LEGACY(di_ops),
+ UTIL_TEST(memcpy_iftrue_timei, 0),
UTIL_TEST(di_map, 0),
UTIL_TEST(round_to_next_multiple_of, 0),
UTIL_TEST(laplace, 0),
@@ -6385,7 +6516,7 @@ struct testcase_t util_tests[] = {
UTIL_TEST(writepid, 0),
UTIL_TEST(get_avail_disk_space, 0),
UTIL_TEST(touch_file, 0),
- UTIL_TEST_NO_WIN(pwdb, TT_FORK),
+ UTIL_TEST_PWDB(pwdb, TT_FORK),
UTIL_TEST(calloc_check, 0),
UTIL_TEST(monotonic_time, 0),
UTIL_TEST(monotonic_time_ratchet, TT_FORK),
diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c
index 2859da66b2..726e8e7427 100644
--- a/src/test/test_util_format.c
+++ b/src/test/test_util_format.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -7,11 +7,8 @@
#include "test/test.h"
#include "lib/crypt_ops/crypto_rand.h"
-#define UTIL_FORMAT_PRIVATE
#include "lib/encoding/binascii.h"
-#define NS_MODULE util_format
-
static void
test_util_format_unaligned_accessors(void *ignored)
{
diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c
index 4d04eb6dfc..fc79fe9b1f 100644
--- a/src/test/test_util_process.c
+++ b/src/test/test_util_process.c
@@ -1,7 +1,6 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define UTIL_PROCESS_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
@@ -12,7 +11,6 @@
#include "test/log_test_helpers.h"
#ifndef _WIN32
-#define NS_MODULE util_process
static void
temp_callback(int r, void *s)
@@ -69,15 +67,16 @@ test_util_process_clear_waitpid_callback(void *ignored)
}
#endif /* !defined(_WIN32) */
+#ifndef COCCI
#ifndef _WIN32
-#define TEST(name) { #name, test_util_process_##name, 0, NULL, NULL }
+#define TEST(name) { (#name), test_util_process_##name, 0, NULL, NULL }
#else
-#define TEST(name) { #name, NULL, TT_SKIP, NULL, NULL }
+#define TEST(name) { (#name), NULL, TT_SKIP, NULL, NULL }
#endif
+#endif /* !defined(COCCI) */
struct testcase_t util_process_tests[] = {
TEST(set_waitpid_callback),
TEST(clear_waitpid_callback),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_voting_flags.c b/src/test/test_voting_flags.c
index c8111ea5df..ae89e43889 100644
--- a/src/test/test_voting_flags.c
+++ b/src/test/test_voting_flags.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -8,6 +8,7 @@
#include "core/or/or.h"
#include "feature/dirauth/voteflags.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerstatus_st.h"
#include "feature/nodelist/routerinfo_st.h"
@@ -15,6 +16,7 @@
#include "app/config/config.h"
#include "test/test.h"
+#include "test/opts_test_helpers.h"
typedef struct {
time_t now;
@@ -119,7 +121,7 @@ test_voting_flags_ipv6(void *arg)
if (!check_result(cfg))
goto done;
- get_options_mutable()->AuthDirHasIPv6Connectivity = 1;
+ get_dirauth_options(get_options_mutable())->AuthDirHasIPv6Connectivity = 1;
// no change in expected results, since last_reachable6 won't be set.
if (!check_result(cfg))
goto done;
diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c
index ba4d53a4ae..df64b79167 100644
--- a/src/test/test_voting_schedule.c
+++ b/src/test/test_voting_schedule.c
@@ -1,17 +1,18 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "core/or/or.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
+#include "feature/nodelist/networkstatus.h"
#include "test/test.h"
static void
test_voting_schedule_interval_start(void *arg)
{
-#define next_interval voting_schedule_get_start_of_next_interval
+#define next_interval voting_sched_get_start_of_interval_after
(void)arg;
char buf[ISO_TIME_LEN+1];
@@ -61,4 +62,3 @@ struct testcase_t voting_schedule_tests[] = {
VS(interval_start, 0),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c
index ba478a45a4..3734c08e48 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -32,7 +32,7 @@ int handled_len;
bitarray_t *handled;
#endif
-typedef struct state_s {
+typedef struct state_t {
int magic;
int n_handled;
crypto_pk_t *rsa;
@@ -40,13 +40,13 @@ typedef struct state_s {
int is_shutdown;
} state_t;
-typedef struct rsa_work_s {
+typedef struct rsa_work_t {
int serial;
uint8_t msg[128];
uint8_t msglen;
} rsa_work_t;
-typedef struct ecdh_work_s {
+typedef struct ecdh_work_t {
int serial;
union {
curve25519_public_key_t pk;
@@ -339,7 +339,7 @@ main(int argc, char **argv)
replyqueue_t *rq;
threadpool_t *tp;
int i;
- tor_libevent_cfg evcfg;
+ tor_libevent_cfg_t evcfg;
uint32_t as_flags = 0;
for (i = 1; i < argc; ++i) {
diff --git a/src/test/test_x509.c b/src/test/test_x509.c
index 792849ae4b..94e7db33de 100644
--- a/src/test/test_x509.c
+++ b/src/test/test_x509.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_X509_PRIVATE
diff --git a/src/test/test_zero_length_keys.sh b/src/test/test_zero_length_keys.sh
index 84ca513b0a..b944d9bf3f 100755
--- a/src/test/test_zero_length_keys.sh
+++ b/src/test/test_zero_length_keys.sh
@@ -1,10 +1,44 @@
#!/bin/sh
# Check that tor regenerates keys when key files are zero-length
+umask 077
+set -e
+
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+# find the tor binary
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "$TOR_BINARY" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
+fi
+
exitcode=0
-"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -z || exitcode=1
-"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -d || exitcode=1
-"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -e || exitcode=1
+"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "$TOR_BINARY" -z || exitcode=1
+"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "$TOR_BINARY" -d || exitcode=1
+"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "$TOR_BINARY" -e || exitcode=1
exit ${exitcode}
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 06a6f312ad..b3337f24b0 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -89,6 +89,17 @@ setup_directory(void)
(int)getpid(), rnd32);
r = mkdir(temp_dir);
}
+#elif defined(__ANDROID__)
+ /* tor might not like the default perms, so create a subdir */
+ tor_snprintf(temp_dir, sizeof(temp_dir),
+ "/data/local/tmp/tor_%d_%d_%s",
+ (int) getuid(), (int) getpid(), rnd32);
+ r = mkdir(temp_dir, 0700);
+ if (r) {
+ fprintf(stderr, "Can't create directory %s:", temp_dir);
+ perror("");
+ exit(1);
+ }
#else /* !defined(_WIN32) */
tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
(int) getpid(), rnd32);
@@ -97,7 +108,7 @@ setup_directory(void)
/* undo sticky bit so tests don't get confused. */
r = chown(temp_dir, getuid(), getgid());
}
-#endif /* defined(_WIN32) */
+#endif /* defined(_WIN32) || ... */
if (r) {
fprintf(stderr, "Can't create directory %s:", temp_dir);
perror("");
@@ -262,16 +273,19 @@ main(int c, const char **v)
int loglevel = LOG_ERR;
int accel_crypto = 0;
- subsystems_init_upto(SUBSYS_LEVEL_LIBS);
+ subsystems_init();
options = options_new();
- struct tor_libevent_cfg cfg;
+ struct tor_libevent_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
tor_libevent_initialize(&cfg);
control_initialize_event_queue();
+ /* Don't add default logs; the tests manage their own. */
+ quiet_level = QUIET_SILENT;
+
for (i_out = i = 1; i < c; ++i) {
if (!strcmp(v[i], "--warn")) {
loglevel = LOG_WARN;
@@ -323,6 +337,7 @@ main(int c, const char **v)
initialize_mainloop_events();
options_init(options);
options->DataDirectory = tor_strdup(temp_dir);
+ options->DataDirectory_option = tor_strdup(temp_dir);
tor_asprintf(&options->KeyDirectory, "%s"PATH_SEPARATOR"keys",
options->DataDirectory);
options->CacheDirectory = tor_strdup(temp_dir);
diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c
index 727449e6eb..e058f72d01 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "lib/crypt_ops/crypto_rand.h"
diff --git a/src/tools/.may_include b/src/tools/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/tools/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/tools/tools.md b/src/tools/tools.md
new file mode 100644
index 0000000000..1f00381679
--- /dev/null
+++ b/src/tools/tools.md
@@ -0,0 +1,6 @@
+@dir /tools
+@brief tools: other command-line tools for use with Tor.
+
+The "tools" directory has a few other programs that use Tor, but are not part
+of the main Tor binary.
+
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index ea96f41dbf..e4f6530b46 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -21,7 +21,7 @@
/* Some versions of OpenSSL declare X509_STORE_CTX_set_verify_cb twice in
* x509.h and x509_vfy.h. Suppress the GCC warning so we can build with
* -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/evp.h>
#include <openssl/pem.h>
@@ -30,7 +30,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/obj_mac.h>
#include <openssl/err.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#endif /* defined(ENABLE_OPENSSL) */
#include <errno.h>
diff --git a/src/tools/tor-print-ed-signing-cert.c b/src/tools/tor-print-ed-signing-cert.c
index 43a1d7bcbd..7836293df4 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-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, 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 5d97696c18..e6d6bddcdb 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-2019, The Tor Project, Inc.
+ * Copyright (c) 2007-2020, The Tor Project, Inc.
*/
/* See LICENSE for licensing information */
@@ -45,8 +45,10 @@
#define RESPONSE_LEN_4 8
#define log_sock_error(act, _s) \
- STMT_BEGIN log_fn(LOG_ERR, LD_NET, "Error while %s: %s", act, \
- tor_socket_strerror(tor_socket_errno(_s))); STMT_END
+ STMT_BEGIN \
+ log_fn(LOG_ERR, LD_NET, "Error while %s: %s", act, \
+ tor_socket_strerror(tor_socket_errno(_s))); \
+ STMT_END
static void usage(void) ATTR_NORETURN;
@@ -507,7 +509,7 @@ do_resolve(const char *hostname,
} else if (atype == SOCKS5_ATYPE_IPV6) {
/* IPv6 address */
tor_addr_from_ipv6_bytes(result_addr,
- (const char *)socks5_server_reply_getarray_bind_addr_ipv6(reply));
+ socks5_server_reply_getarray_bind_addr_ipv6(reply));
} else if (atype == SOCKS5_ATYPE_HOSTNAME) {
/* Domain name */
domainname_t *dn =
diff --git a/src/tools/tor_runner.c b/src/tools/tor_runner.c
index 3c6ade91d9..83f1a495cd 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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/trunnel/.may_include b/src/trunnel/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/trunnel/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/trunnel/hs/.may_include b/src/trunnel/hs/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/trunnel/hs/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index 38464f1c59..bb8eb4c769 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -102,7 +102,6 @@
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
-
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H
@@ -218,9 +217,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.4.2.8-dev"
-
-
+#define VERSION "0.4.4.4-rc"
#define HAVE_STRUCT_SOCKADDR_IN6
#define HAVE_STRUCT_IN6_ADDR