diff options
Diffstat (limited to 'src/app/main')
-rw-r--r-- | src/app/main/.may_include | 1 | ||||
-rw-r--r-- | src/app/main/app_main.md | 2 | ||||
-rw-r--r-- | src/app/main/include.am | 20 | ||||
-rw-r--r-- | src/app/main/main.c | 482 | ||||
-rw-r--r-- | src/app/main/main.h | 8 | ||||
-rw-r--r-- | src/app/main/ntmain.c | 16 | ||||
-rw-r--r-- | src/app/main/ntmain.h | 5 | ||||
-rw-r--r-- | src/app/main/risky_options.c | 35 | ||||
-rw-r--r-- | src/app/main/risky_options.h | 17 | ||||
-rw-r--r-- | src/app/main/shutdown.c | 171 | ||||
-rw-r--r-- | src/app/main/shutdown.h | 18 | ||||
-rw-r--r-- | src/app/main/subsysmgr.c | 478 | ||||
-rw-r--r-- | src/app/main/subsysmgr.h | 53 | ||||
-rw-r--r-- | src/app/main/subsystem_list.c | 77 | ||||
-rw-r--r-- | src/app/main/tor_main.c | 2 |
15 files changed, 1064 insertions, 321 deletions
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..576c750377 --- /dev/null +++ b/src/app/main/include.am @@ -0,0 +1,20 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/app/main/main.c \ + src/app/main/risky_options.c \ + src/app/main/shutdown.c \ + src/app/main/subsystem_list.c \ + src/app/main/subsysmgr.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/app/main/main.h \ + src/app/main/ntmain.h \ + src/app/main/risky_options.h \ + src/app/main/shutdown.h \ + src/app/main/subsysmgr.h + +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 ca3148e7fc..5043caedb6 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,80 +13,73 @@ #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/risky_options.h" +#include "app/main/shutdown.h" +#include "app/main/subsysmgr.h" #include "core/mainloop/connection.h" #include "core/mainloop/cpuworker.h" #include "core/mainloop/mainloop.h" +#include "core/mainloop/mainloop_pubsub.h" #include "core/mainloop/netstatus.h" #include "core/or/channel.h" #include "core/or/channelpadding.h" -#include "core/or/channeltls.h" +#include "core/or/circuitpadding.h" #include "core/or/circuitlist.h" -#include "core/or/circuitmux_ewma.h" #include "core/or/command.h" -#include "core/or/connection_edge.h" #include "core/or/connection_or.h" -#include "core/or/dos.h" -#include "core/or/policies.h" -#include "core/or/protover.h" #include "core/or/relay.h" -#include "core/or/scheduler.h" #include "core/or/status.h" #include "feature/api/tor_api.h" #include "feature/api/tor_api_internal.h" #include "feature/client/addressmap.h" -#include "feature/client/bridges.h" -#include "feature/client/entrynodes.h" -#include "feature/client/transports.h" #include "feature/control/control.h" -#include "feature/dirauth/bwauth.h" +#include "feature/control/control_auth.h" +#include "feature/control/control_events.h" #include "feature/dirauth/keypin.h" #include "feature/dirauth/process_descs.h" #include "feature/dircache/consdiffmgr.h" -#include "feature/dircache/dirserv.h" #include "feature/dirparse/routerparse.h" #include "feature/hibernate/hibernate.h" -#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_dos.h" #include "feature/nodelist/authcert.h" -#include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" -#include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" #include "feature/relay/dns.h" #include "feature/relay/ext_orport.h" -#include "feature/relay/onion_queue.h" #include "feature/relay/routerkeys.h" #include "feature/relay/routermode.h" #include "feature/rend/rendcache.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendservice.h" -#include "feature/stats/geoip_stats.h" #include "feature/stats/predict_ports.h" +#include "feature/stats/bwhist.h" #include "feature/stats/rephist.h" #include "lib/compress/compress.h" -#include "lib/container/buffers.h" +#include "lib/buf/buffers.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_s2k.h" -#include "lib/err/backtrace.h" -#include "lib/geoip/geoip.h" +#include "lib/net/resolve.h" +#include "lib/trace/trace.h" #include "lib/process/waitpid.h" +#include "lib/pubsub/pubsub_build.h" #include "lib/meminfo/meminfo.h" #include "lib/osinfo/uname.h" +#include "lib/osinfo/libc.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" #include "lib/evloop/timers.h" #include "lib/crypt_ops/crypto_init.h" +#include "lib/version/torversion.h" #include <event2/event.h> -#include "feature/dirauth/dirvote.h" #include "feature/dirauth/authmode.h" #include "feature/dirauth/shared_random.h" @@ -107,8 +100,6 @@ #include <systemd/sd-daemon.h> #endif /* defined(HAVE_SYSTEMD) */ -void evdns_shutdown(int); - #ifdef HAVE_RUST // helper function defined in Rust to output a log message indicating if tor is // running with Rust enabled. See src/rust/tor_util @@ -121,16 +112,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 @@ -301,9 +282,35 @@ process_signal(int sig) log_heartbeat(time(NULL)); control_event_signal(sig); break; + case SIGACTIVE: + /* "SIGACTIVE" counts as ersatz user activity. */ + note_user_activity(approx_time()); + control_event_signal(sig); + break; + case SIGDORMANT: + /* "SIGDORMANT" means to ignore past user activity */ + log_notice(LD_GENERAL, "Going dormant because of controller request."); + reset_user_activity(0); + set_network_participation(false); + schedule_rescan_periodic_events(); + control_event_signal(sig); + break; } } +#ifdef _WIN32 +/** Activate SIGINT on receiving 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. */ @@ -332,16 +339,12 @@ dumpstats(int severity) SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { int i = conn_sl_idx; tor_log(severity, LD_GENERAL, - "Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago", - i, (int)conn->s, conn->type, conn_type_to_string(conn->type), - conn->state, conn_state_to_string(conn->type, conn->state), + "Conn %d (socket %d) is a %s, created %d secs ago", + i, (int)conn->s, + connection_describe(conn), (int)(now - conn->timestamp_created)); if (!connection_is_listener(conn)) { tor_log(severity,LD_GENERAL, - "Conn %d is to %s:%d.", i, - safe_str_client(conn->address), - conn->port); - tor_log(severity,LD_GENERAL, "Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)", i, (int)connection_get_inbuf_len(conn), @@ -423,18 +426,7 @@ dumpstats(int severity) rep_hist_dump_stats(now,severity); rend_service_dump_stats(severity); -} - -/** Called by exit() as we shut down the process. - */ -static void -exit_function(void) -{ - /* NOTE: If we ever daemonize, this gets called immediately. That's - * okay for now, because we only use this on Windows. */ -#ifdef _WIN32 - WSACleanup(); -#endif + hs_service_dump_stats(severity); } #ifdef _WIN32 @@ -481,6 +473,8 @@ static struct { { SIGNEWNYM, 0, NULL }, { SIGCLEARDNSCACHE, 0, NULL }, { SIGHEARTBEAT, 0, NULL }, + { SIGACTIVE, 0, NULL }, + { SIGDORMANT, 0, NULL }, { -1, -1, NULL } }; @@ -515,6 +509,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. */ @@ -537,7 +538,8 @@ int tor_init(int argc, char *argv[]) { char progname[256]; - int quiet = 0; + quiet_level_t quiet = QUIET_NONE; + bool running_tor = false; time_of_process_start = time(NULL); tor_init_connection_lists(); @@ -545,66 +547,39 @@ tor_init(int argc, char *argv[]) tor_snprintf(progname, sizeof(progname), "Tor %s", get_version()); log_set_application_name(progname); - /* Set up the crypto nice and early */ - if (crypto_early_init() < 0) { - log_err(LD_GENERAL, "Unable to initialize the crypto subsystem!"); - return -1; - } - /* Initialize the history structures. */ rep_hist_init(); + bwhist_init(); /* Initialize the service cache. */ rend_cache_init(); addressmap_init(); /* Init the client dns cache. Do it always, since it's * cheap. */ + /* Initialize the HS subsystem. */ 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; - } + /* 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; + running_tor = (cmdline->command == CMD_RUN_TOR); } - config_free_lines(opts); - config_free_lines(cmdline_opts); + 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; { const char *version = get_version(); log_notice(LD_GENERAL, "Tor %s running on %s with Libevent %s, " - "%s %s, Zlib %s, Liblzma %s, and Libzstd %s.", version, + "%s %s, Zlib %s, Liblzma %s, Libzstd %s and %s %s as libc.", + version, get_uname(), tor_libevent_get_version_str(), crypto_get_library_name(), @@ -614,7 +589,10 @@ tor_init(int argc, char *argv[]) tor_compress_supports_method(LZMA_METHOD) ? tor_compress_version_str(LZMA_METHOD) : "N/A", tor_compress_supports_method(ZSTD_METHOD) ? - tor_compress_version_str(ZSTD_METHOD) : "N/A"); + tor_compress_version_str(ZSTD_METHOD) : "N/A", + tor_libc_get_name() ? + tor_libc_get_name() : "Unknown", + tor_libc_get_version_str()); log_notice(LD_GENERAL, "Tor can't help you if you use it wrong! " "Learn how to be safe at " @@ -624,6 +602,12 @@ tor_init(int argc, char *argv[]) log_notice(LD_GENERAL, "This version is not a stable Tor release. " "Expect more bugs than usual."); + if (strlen(risky_option_list) && running_tor) { + log_warn(LD_GENERAL, "This build of Tor has been compiled with one " + "or more options that might make it less reliable or secure! " + "They are:%s", risky_option_list); + } + tor_compress_log_init_warnings(); } @@ -631,11 +615,8 @@ tor_init(int argc, char *argv[]) rust_log_welcome_string(); #endif /* defined(HAVE_RUST) */ - if (network_init()<0) { - log_err(LD_BUG,"Error initializing network; exiting."); - return -1; - } - atexit(exit_function); + /* Warn _if_ the tracing subsystem is built in. */ + tracing_log_warning(); int init_rv = options_init_from_torrc(argc,argv); if (init_rv < 0) { @@ -647,12 +628,17 @@ tor_init(int argc, char *argv[]) return 1; } - /* The options are now initialised */ - const or_options_t *options = get_options(); - - /* Initialize channelpadding parameters to defaults until we get - * a consensus */ + /* Initialize channelpadding and circpad parameters to defaults + * until we get a consensus */ channelpadding_new_consensus_params(NULL); + circpad_new_consensus_params(NULL); + + /* Initialize circuit padding to defaults+torrc until we get a consensus */ + circpad_machines_init(); + + /* Initialize hidden service DoS subsystem. We need to do this once the + * configuration object has been set because it can be accessed. */ + hs_dos_init(); /* Initialize predicted ports list after loading options */ predicted_ports_init(); @@ -663,17 +649,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; - } - stream_choice_seed_weak_rng(); - if (tor_init_libevent_rng() < 0) { - log_warn(LD_NET, "Problem initializing libevent RNG."); - } - /* Scan/clean unparseable descriptors; after reading config */ routerparse_init(); @@ -742,86 +717,6 @@ release_lockfile(void) } } -/** Free all memory that we might have allocated somewhere. - * If <b>postfork</b>, we are a worker process and we want to free - * only the parts of memory that we won't touch. If !<b>postfork</b>, - * Tor is shutting down and we should free everything. - * - * Helps us find the real leaks with sanitizers and the like. Also valgrind - * should then report 0 reachable in its leak report (in an ideal world -- - * in practice libevent, SSL, libc etc never quite free everything). */ -void -tor_free_all(int postfork) -{ - if (!postfork) { - evdns_shutdown(1); - } - geoip_free_all(); - geoip_stats_free_all(); - dirvote_free_all(); - routerlist_free_all(); - networkstatus_free_all(); - addressmap_free_all(); - dirserv_free_fingerprint_list(); - dirserv_free_all(); - dirserv_clear_measured_bw_cache(); - rend_cache_free_all(); - rend_service_authorization_free_all(); - rep_hist_free_all(); - dns_free_all(); - clear_pending_onions(); - circuit_free_all(); - entry_guards_free_all(); - pt_free_all(); - channel_tls_free_all(); - channel_free_all(); - connection_free_all(); - connection_edge_free_all(); - scheduler_free_all(); - nodelist_free_all(); - microdesc_free_all(); - routerparse_free_all(); - ext_orport_free_all(); - control_free_all(); - tor_free_getaddrinfo_cache(); - protover_free_all(); - bridges_free_all(); - consdiffmgr_free_all(); - hs_free_all(); - dos_free_all(); - circuitmux_ewma_free_all(); - accounting_free_all(); - - if (!postfork) { - config_free_all(); - or_state_free_all(); - router_free_all(); - routerkeys_free_all(); - policies_free_all(); - } - if (!postfork) { - tor_tls_free_all(); -#ifndef _WIN32 - tor_getpwnam(NULL); -#endif - } - /* stuff in main.c */ - - tor_mainloop_free_all(); - - if (!postfork) { - release_lockfile(); - } - tor_libevent_free_all(); - /* Stuff in util.c and address.c*/ - if (!postfork) { - escaped(NULL); - esc_router_info(NULL); - clean_up_backtrace_handler(); - logs_free_all(); /* free log strings. do this last so logs keep working. */ - } -} - /** * Remove the specified file, and log a warning if the operation fails for * any reason other than the file not existing. Ignores NULL filenames. @@ -835,51 +730,6 @@ tor_remove_file(const char *filename) } } -/** Do whatever cleanup is necessary before shutting Tor down. */ -void -tor_cleanup(void) -{ - const or_options_t *options = get_options(); - if (options->command == CMD_RUN_TOR) { - time_t now = time(NULL); - /* Remove our pid file. We don't care if there was an error when we - * unlink, nothing we could do about it anyways. */ - tor_remove_file(options->PidFile); - /* Remove control port file */ - tor_remove_file(options->ControlPortWriteToFile); - /* Remove cookie authentication file */ - { - char *cookie_fname = get_controller_cookie_file_name(); - tor_remove_file(cookie_fname); - tor_free(cookie_fname); - } - /* Remove Extended ORPort cookie authentication file */ - { - char *cookie_fname = get_ext_or_auth_cookie_file_name(); - tor_remove_file(cookie_fname); - tor_free(cookie_fname); - } - if (accounting_is_enabled(options)) - accounting_record_bandwidth_usage(now, get_or_state()); - or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */ - or_state_save(now); - if (authdir_mode(options)) { - sr_save_and_cleanup(); - } - if (authdir_mode_tests_reachability(options)) - rep_hist_record_mtbf_data(now, 0); - keypin_close_journal(); - } - - timers_shutdown(); - - tor_free_all(0); /* We could move tor_free_all back into the ifdef below - later, if it makes shutdown unacceptably slow. But for - now, leave it here: it's helped us catch bugs in the - past. */ - crypto_global_cleanup(); -} - /** Read/create keys as needed, and echo our fingerprint to stdout. */ static int do_list_fingerprint(void) @@ -941,12 +791,14 @@ do_dump_config(void) if (!strcmp(arg, "short")) { how = OPTIONS_DUMP_MINIMAL; } else if (!strcmp(arg, "non-builtin")) { - how = OPTIONS_DUMP_DEFAULTS; + // Deprecated since 0.4.5.1-alpha. + fprintf(stderr, "'non-builtin' is deprecated; use 'short' instead.\n"); + how = OPTIONS_DUMP_MINIMAL; } else if (!strcmp(arg, "full")) { how = OPTIONS_DUMP_ALL; } else { fprintf(stderr, "No valid argument to --dump-config found!\n"); - fprintf(stderr, "Please select 'short', 'non-builtin', or 'full'.\n"); + fprintf(stderr, "Please select 'short' or 'full'.\n"); return -1; } @@ -961,8 +813,7 @@ do_dump_config(void) static void init_addrinfo(void) { - if (! server_mode(get_options()) || - (get_options()->Address && strlen(get_options()->Address) > 0)) { + if (! server_mode(get_options()) || get_options()->Address) { /* We don't need to seed our own hostname, because we won't be calling * resolve_my_address on it. */ @@ -980,7 +831,6 @@ sandbox_init_filter(void) { const or_options_t *options = get_options(); sandbox_cfg_t *cfg = sandbox_cfg_new(); - int i; sandbox_cfg_allow_openat_filename(&cfg, get_cachedir_fname("cached-status")); @@ -988,6 +838,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)) @@ -1004,8 +857,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 { \ @@ -1019,6 +874,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(); @@ -1059,14 +916,31 @@ sandbox_init_filter(void) else sandbox_cfg_allow_open_filename(&cfg, tor_strdup("/etc/resolv.conf")); - for (i = 0; i < 2; ++i) { - if (get_torrc_fname(i)) { - sandbox_cfg_allow_open_filename(&cfg, tor_strdup(get_torrc_fname(i))); - } + const char *torrc_defaults_fname = get_torrc_fname(1); + if (torrc_defaults_fname) { + sandbox_cfg_allow_open_filename(&cfg, tor_strdup(torrc_defaults_fname)); + } + const char *torrc_fname = get_torrc_fname(0); + if (torrc_fname) { + sandbox_cfg_allow_open_filename(&cfg, tor_strdup(torrc_fname)); + // allow torrc backup and torrc.tmp to make SAVECONF work + char *torrc_bck = NULL; + tor_asprintf(&torrc_bck, CONFIG_BACKUP_PATTERN, torrc_fname); + sandbox_cfg_allow_rename(&cfg, tor_strdup(torrc_fname), torrc_bck); + char *torrc_tmp = NULL; + tor_asprintf(&torrc_tmp, "%s.tmp", torrc_fname); + sandbox_cfg_allow_rename(&cfg, torrc_tmp, tor_strdup(torrc_fname)); + sandbox_cfg_allow_open_filename(&cfg, tor_strdup(torrc_tmp)); + // we need to stat the existing backup file + sandbox_cfg_allow_stat_filename(&cfg, tor_strdup(torrc_bck)); } SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, { - OPEN(f); + if (file_status(f) == FN_DIR) { + OPENDIR(f); + } else { + OPEN(f); + } }); #define RENAME_SUFFIX(name, suffix) \ @@ -1179,7 +1053,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)); @@ -1220,12 +1094,14 @@ sandbox_init_filter(void) OPEN_DATADIR("approved-routers"); OPEN_DATADIR_SUFFIX("fingerprint", ".tmp"); + OPEN_DATADIR_SUFFIX("fingerprint-ed25519", ".tmp"); OPEN_DATADIR_SUFFIX("hashed-fingerprint", ".tmp"); OPEN_DATADIR_SUFFIX("router-stability", ".tmp"); OPEN("/etc/resolv.conf"); RENAME_SUFFIX("fingerprint", ".tmp"); + RENAME_SUFFIX("fingerprint-ed25519", ".tmp"); RENAME_KEYDIR_SUFFIX("secret_onion_key_ntor", ".tmp"); RENAME_KEYDIR_SUFFIX("secret_id_key", ".tmp"); @@ -1273,7 +1149,6 @@ int run_tor_main_loop(void) { handle_signals(); - monotime_init(); timers_initialize(); initialize_mainloop_events(); @@ -1378,6 +1253,32 @@ run_tor_main_loop(void) return do_main_loop(); } +/** Install the publish/subscribe relationships for all the subsystems. */ +void +pubsub_install(void) +{ + pubsub_builder_t *builder = pubsub_builder_new(); + int r = subsystems_add_pubsub(builder); + tor_assert(r == 0); + r = tor_mainloop_connect_pubsub(builder); // consumes builder + tor_assert(r == 0); +} + +/** Connect the mainloop to its publish/subscribe message delivery events if + * appropriate, and configure the global channels appropriately. */ +void +pubsub_connect(void) +{ + if (get_options()->command == CMD_RUN_TOR) { + tor_mainloop_connect_pubsub_events(); + /* XXXX For each pubsub channel, its delivery strategy should be set at + * this XXXX point, using tor_mainloop_set_delivery_strategy(). + */ + tor_mainloop_set_delivery_strategy("orconn", DELIV_IMMEDIATE); + tor_mainloop_set_delivery_strategy("ocirc", DELIV_IMMEDIATE); + } +} + /* Main entry point for the Tor process. Called from tor_main(), and by * anybody embedding Tor. */ int @@ -1385,54 +1286,13 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) { int result = 0; -#ifdef _WIN32 -#ifndef HeapEnableTerminationOnCorruption -#define HeapEnableTerminationOnCorruption 1 -#endif - /* On heap corruption, just give up; don't try to play along. */ - HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); - - /* SetProcessDEPPolicy is only supported on 32-bit Windows. - * (On 64-bit Windows it always fails, and some compilers don't like the - * PSETDEP cast.) - * 32-bit Windows defines _WIN32. - * 64-bit Windows defines _WIN32 and _WIN64. */ -#ifndef _WIN64 - /* Call SetProcessDEPPolicy to permanently enable DEP. - The function will not resolve on earlier versions of Windows, - and failure is not dangerous. */ - HMODULE hMod = GetModuleHandleA("Kernel32.dll"); - if (hMod) { - typedef BOOL (WINAPI *PSETDEP)(DWORD); - PSETDEP setdeppolicy = (PSETDEP)GetProcAddress(hMod, - "SetProcessDEPPolicy"); - if (setdeppolicy) { - /* PROCESS_DEP_ENABLE | PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION */ - setdeppolicy(3); - } - } -#endif /* !defined(_WIN64) */ -#endif /* defined(_WIN32) */ - - { - int bt_err = configure_backtrace_handler(get_version()); - if (bt_err < 0) { - log_warn(LD_BUG, "Unable to install backtrace handler: %s", - strerror(-bt_err)); - } - } - #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED event_set_mem_functions(tor_malloc_, tor_realloc_, tor_free_); #endif - init_protocol_warning_severity_level(); + subsystems_init(); - update_approx_time(time(NULL)); - tor_threads_init(); - tor_compress_init(); - init_logging(0); - monotime_init(); + init_protocol_warning_severity_level(); int argc = tor_cfg->argc + tor_cfg->argc_owned; char **argv = tor_calloc(argc, sizeof(char*)); @@ -1441,15 +1301,13 @@ 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(); + { int init_rv = tor_init(argc, argv); if (init_rv) { @@ -1459,6 +1317,8 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) } } + pubsub_connect(); + if (get_options()->Sandbox && get_options()->command == CMD_RUN_TOR) { sandbox_cfg_t* cfg = sandbox_init_filter(); @@ -1468,6 +1328,7 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) tor_free_all(0); return -1; } + tor_make_getaddrinfo_cache_active(); // registering libevent rng #ifdef HAVE_EVUTIL_SECURE_RNG_SET_URANDOM_DEVICE_FILE @@ -1478,9 +1339,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: @@ -1498,7 +1357,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; @@ -1506,6 +1365,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 bbbbf984fb..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 */ /** @@ -21,11 +21,11 @@ void release_lockfile(void); void tor_remove_file(const char *filename); -void tor_cleanup(void); -void tor_free_all(int postfork); - int tor_init(int argc, char **argv); int run_tor_main_loop(void); +void pubsub_install(void); +void pubsub_connect(void); + #endif /* !defined(TOR_MAIN_H) */ diff --git a/src/app/main/ntmain.c b/src/app/main/ntmain.c index 05d203b0be..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 */ /** @@ -24,6 +24,7 @@ #include "app/config/config.h" #include "app/main/main.h" #include "app/main/ntmain.h" +#include "app/main/shutdown.h" #include "core/mainloop/mainloop.h" #include "lib/evloop/compat_libevent.h" #include "lib/fs/winlib.h" @@ -65,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; /** @{ */ @@ -282,7 +283,9 @@ nt_service_body(int argc, char **argv) return; } + pubsub_install(); r = tor_init(backup_argc, backup_argv); + if (r) { /* Failed to start the Tor service */ r = NT_SERVICE_ERROR_TORINIT_FAILED; @@ -293,6 +296,8 @@ nt_service_body(int argc, char **argv) return; } + pubsub_connect(); + /* Set the service's status to SERVICE_RUNNING and start the main * event loop */ service_status.dwCurrentState = SERVICE_RUNNING; @@ -321,9 +326,12 @@ nt_service_main(void) errmsg = format_win32_error(result); printf("Service error %d : %s\n", (int) result, errmsg); tor_free(errmsg); + + pubsub_install(); if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { if (tor_init(backup_argc, backup_argv)) return; + pubsub_connect(); switch (get_options()->command) { case CMD_RUN_TOR: run_tor_main_loop(); @@ -339,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); @@ -594,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"); @@ -607,6 +616,7 @@ nt_service_install(int argc, char **argv) &sidUse) == 0) { /* XXXX For some reason, the above test segfaults. Fix that. */ printf("User \"%s\" doesn't seem to exist.\n", user_acct); + tor_free(command); return -1; } else { printf("Will try to install service as user \"%s\".\n", user_acct); 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/risky_options.c b/src/app/main/risky_options.c new file mode 100644 index 0000000000..747dda766b --- /dev/null +++ b/src/app/main/risky_options.c @@ -0,0 +1,35 @@ +/* Copyright (c) 2001 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 risky_options.c + * \brief List compile-time options that might make Tor less reliable. + **/ + +#include "orconfig.h" +#include "app/main/risky_options.h" + +/** A space-separated list of the compile-time options might make Tor less + * reliable or secure. These options mainly exist for testing or debugging. + */ +const char risky_option_list[] = + "" +#ifdef DISABLE_ASSERTS_IN_TEST + " --disable-asserts-in-test" +#endif +#ifdef TOR_UNIT_TESTS + " TOR_UNIT_TESTS" +#endif +#ifdef ENABLE_RESTART_DEBUGGING + " --enable-restart-debugging" +#endif +#ifdef ALL_BUGS_ARE_FATAL + " --enable-all-bugs-are-fatal" +#endif +#ifdef DISABLE_MEMORY_SENTINELS + " --disable-memory-sentinels" +#endif + ; diff --git a/src/app/main/risky_options.h b/src/app/main/risky_options.h new file mode 100644 index 0000000000..4548ae3efb --- /dev/null +++ b/src/app/main/risky_options.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 risky_options.h + * \brief Header for risky_options.c + **/ + +#ifndef TOR_RISKY_OPTIONS_H +#define TOR_RISKY_OPTIONS_H + +extern const char risky_option_list[]; + +#endif diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c new file mode 100644 index 0000000000..4a556333db --- /dev/null +++ b/src/app/main/shutdown.c @@ -0,0 +1,171 @@ +/* Copyright (c) 2001 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 shutdown.c + * @brief Code to free global resources used by Tor. + * + * In the future, this should all be handled by the subsystem manager. */ + +#include "core/or/or.h" + +#include "app/config/config.h" +#include "app/config/statefile.h" +#include "app/main/main.h" +#include "app/main/shutdown.h" +#include "app/main/subsysmgr.h" +#include "core/mainloop/connection.h" +#include "core/mainloop/mainloop_pubsub.h" +#include "core/or/channeltls.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitmux_ewma.h" +#include "core/or/circuitpadding.h" +#include "core/or/connection_edge.h" +#include "core/or/dos.h" +#include "core/or/scheduler.h" +#include "feature/client/addressmap.h" +#include "feature/client/bridges.h" +#include "feature/client/entrynodes.h" +#include "feature/client/transports.h" +#include "feature/control/control.h" +#include "feature/control/control_auth.h" +#include "feature/dirauth/authmode.h" +#include "feature/dirauth/shared_random.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/dircache/dirserv.h" +#include "feature/dirparse/routerparse.h" +#include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_common.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerlist.h" +#include "feature/relay/ext_orport.h" +#include "feature/relay/relay_config.h" +#include "feature/rend/rendcache.h" +#include "feature/rend/rendclient.h" +#include "feature/stats/bwhist.h" +#include "feature/stats/geoip_stats.h" +#include "feature/stats/rephist.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/geoip/geoip.h" + +void evdns_shutdown(int); + +/** Do whatever cleanup is necessary before shutting Tor down. */ +void +tor_cleanup(void) +{ + const or_options_t *options = get_options(); + if (options->command == CMD_RUN_TOR) { + time_t now = time(NULL); + /* Remove our pid file. We don't care if there was an error when we + * unlink, nothing we could do about it anyways. */ + tor_remove_file(options->PidFile); + /* Remove control port file */ + tor_remove_file(options->ControlPortWriteToFile); + /* Remove cookie authentication file */ + { + char *cookie_fname = get_controller_cookie_file_name(); + tor_remove_file(cookie_fname); + tor_free(cookie_fname); + } + /* Remove Extended ORPort cookie authentication file */ + { + char *cookie_fname = get_ext_or_auth_cookie_file_name(); + if (cookie_fname) + tor_remove_file(cookie_fname); + tor_free(cookie_fname); + } + if (accounting_is_enabled(options)) + accounting_record_bandwidth_usage(now, get_or_state()); + or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */ + or_state_save(now); + if (authdir_mode(options)) { + sr_save_and_cleanup(); + } + if (authdir_mode_tests_reachability(options)) + rep_hist_record_mtbf_data(now, 0); + } + + timers_shutdown(); + + tor_free_all(0); /* We could move tor_free_all back into the ifdef below + later, if it makes shutdown unacceptably slow. But for + now, leave it here: it's helped us catch bugs in the + past. */ +} + +/** Free all memory that we might have allocated somewhere. + * If <b>postfork</b>, we are a worker process and we want to free + * only the parts of memory that we won't touch. If !<b>postfork</b>, + * Tor is shutting down and we should free everything. + * + * Helps us find the real leaks with sanitizers and the like. Also valgrind + * should then report 0 reachable in its leak report (in an ideal world -- + * in practice libevent, SSL, libc etc never quite free everything). */ +void +tor_free_all(int postfork) +{ + if (!postfork) { + evdns_shutdown(1); + } + geoip_free_all(); + geoip_stats_free_all(); + routerlist_free_all(); + networkstatus_free_all(); + addressmap_free_all(); + dirserv_free_all(); + rend_cache_free_all(); + rend_service_authorization_free_all(); + rep_hist_free_all(); + bwhist_free_all(); + circuit_free_all(); + circpad_machines_free(); + entry_guards_free_all(); + pt_free_all(); + channel_tls_free_all(); + channel_free_all(); + connection_free_all(); + connection_edge_free_all(); + scheduler_free_all(); + nodelist_free_all(); + microdesc_free_all(); + routerparse_free_all(); + control_free_all(); + bridges_free_all(); + consdiffmgr_free_all(); + hs_free_all(); + dos_free_all(); + circuitmux_ewma_free_all(); + accounting_free_all(); + circpad_free_all(); + + if (!postfork) { + config_free_all(); + relay_config_free_all(); + or_state_free_all(); + } + if (!postfork) { +#ifndef _WIN32 + tor_getpwnam(NULL); +#endif + } + /* stuff in main.c */ + + tor_mainloop_disconnect_pubsub(); + + if (!postfork) { + release_lockfile(); + } + + subsystems_shutdown(); + + /* Stuff in util.c and address.c*/ + if (!postfork) { + esc_router_info(NULL); + } +} diff --git a/src/app/main/shutdown.h b/src/app/main/shutdown.h new file mode 100644 index 0000000000..623ae9525b --- /dev/null +++ b/src/app/main/shutdown.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file shutdown.h + * \brief Header file for shutdown.c. + **/ + +#ifndef TOR_SHUTDOWN_H +#define TOR_SHUTDOWN_H + +void tor_cleanup(void); +void tor_free_all(int postfork); + +#endif /* !defined(TOR_SHUTDOWN_H) */ diff --git a/src/app/main/subsysmgr.c b/src/app/main/subsysmgr.c new file mode 100644 index 0000000000..349803cd46 --- /dev/null +++ b/src/app/main/subsysmgr.c @@ -0,0 +1,478 @@ +/* Copyright (c) 2003-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 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" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/** + * True iff we have checked tor_subsystems for consistency. + **/ +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 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; + * initialize the subsystem_initialized array. + **/ +static void +check_and_setup(void) +{ + if (subsystem_array_validated) + return; + + raw_assert(ARRAY_LENGTH(sys_status) >= n_tor_subsystems); + memset(sys_status, 0, sizeof(sys_status)); + + int last_level = MIN_SUBSYS_LEVEL; + + for (unsigned i = 0; i < n_tor_subsystems; ++i) { + const subsys_fns_t *sys = tor_subsystems[i]; + if (sys->level < MIN_SUBSYS_LEVEL || sys->level > MAX_SUBSYS_LEVEL) { + fprintf(stderr, "BUG: Subsystem %s (at %u) has an invalid level %d. " + "It is supposed to be between %d and %d (inclusive).\n", + sys->name, i, sys->level, MIN_SUBSYS_LEVEL, MAX_SUBSYS_LEVEL); + raw_assert_unreached_msg("There is a bug in subsystem_list.c"); + } + if (sys->level < last_level) { + fprintf(stderr, "BUG: Subsystem %s (at #%u) is in the wrong position. " + "Its level is %d; but the previous subsystem's level was %d.\n", + 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; + } + + subsystem_array_validated = true; +} + +/** + * Initialize all the subsystems; exit on failure. + **/ +int +subsystems_init(void) +{ + return subsystems_init_upto(MAX_SUBSYS_LEVEL); +} + +/** + * Initialize all the subsystems whose level is less than or equal to + * <b>target_level</b>; exit on failure. + **/ +int +subsystems_init_upto(int target_level) +{ + check_and_setup(); + + for (unsigned i = 0; i < n_tor_subsystems; ++i) { + const subsys_fns_t *sys = tor_subsystems[i]; + if (!sys->supported) + continue; + if (sys->level > target_level) + break; + if (sys_status[i].initialized) + continue; + int r = 0; + if (sys->initialize) { + // Note that the logging subsystem is designed so that it does no harm + // to log a message in an uninitialized state. These messages will be + // discarded for now, however. + log_debug(LD_GENERAL, "Initializing %s", sys->name); + r = sys->initialize(); + } + if (r < 0) { + fprintf(stderr, "BUG: subsystem %s (at %u) initialization failed.\n", + sys->name, i); + raw_assert_unreached_msg("A subsystem couldn't be initialized."); + } + sys_status[i].initialized = true; + } + + return 0; +} + +/** + * Add publish/subscribe relationships to <b>builder</b> for all + * initialized subsystems of level no more than <b>target_level</b>. + **/ +int +subsystems_add_pubsub_upto(pubsub_builder_t *builder, + int target_level) +{ + for (unsigned i = 0; i < n_tor_subsystems; ++i) { + const subsys_fns_t *sys = tor_subsystems[i]; + if (!sys->supported) + continue; + if (sys->level > target_level) + break; + if (! sys_status[i].initialized) + continue; + int r = 0; + if (sys->add_pubsub) { + subsys_id_t sysid = get_subsys_id(sys->name); + raw_assert(sysid != ERROR_ID); + pubsub_connector_t *connector; + connector = pubsub_connector_for_subsystem(builder, sysid); + r = sys->add_pubsub(connector); + pubsub_connector_free(connector); + } + if (r < 0) { + fprintf(stderr, "BUG: subsystem %s (at %u) could not connect to " + "publish/subscribe system.", sys->name, sys->level); + raw_assert_unreached_msg("A subsystem couldn't be connected."); + } + } + + return 0; +} + +/** + * Add publish/subscribe relationships to <b>builder</b> for all + * initialized subsystems. + **/ +int +subsystems_add_pubsub(pubsub_builder_t *builder) +{ + return subsystems_add_pubsub_upto(builder, MAX_SUBSYS_LEVEL); +} + +/** + * Shut down all the subsystems. + **/ +void +subsystems_shutdown(void) +{ + subsystems_shutdown_downto(MIN_SUBSYS_LEVEL - 1); +} + +/** + * Shut down all the subsystems whose level is above <b>target_level</b>. + **/ +void +subsystems_shutdown_downto(int target_level) +{ + check_and_setup(); + + for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) { + const subsys_fns_t *sys = tor_subsystems[i]; + if (!sys->supported) + continue; + if (sys->level <= target_level) + break; + if (! sys_status[i].initialized) + continue; + if (sys->shutdown) { + log_debug(LD_GENERAL, "Shutting down %s", sys->name); + sys->shutdown(); + } + subsys_status_clear(&sys_status[i]); + } +} + +/** + * Run pre-fork code on all subsystems that declare any + **/ +void +subsystems_prefork(void) +{ + check_and_setup(); + + for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) { + const subsys_fns_t *sys = tor_subsystems[i]; + if (!sys->supported) + continue; + if (! sys_status[i].initialized) + continue; + if (sys->prefork) { + log_debug(LD_GENERAL, "Pre-fork: %s", sys->name); + sys->prefork(); + } + } +} + +/** + * Run post-fork code on all subsystems that declare any + **/ +void +subsystems_postfork(void) +{ + check_and_setup(); + + for (unsigned i = 0; i < n_tor_subsystems; ++i) { + const subsys_fns_t *sys = tor_subsystems[i]; + if (!sys->supported) + continue; + if (! sys_status[i].initialized) + continue; + if (sys->postfork) { + log_debug(LD_GENERAL, "Post-fork: %s", sys->name); + sys->postfork(); + } + } +} + +/** + * Run thread-cleanup code on all subsystems that declare any + **/ +void +subsystems_thread_cleanup(void) +{ + check_and_setup(); + + for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) { + const subsys_fns_t *sys = tor_subsystems[i]; + if (!sys->supported) + continue; + if (! sys_status[i].initialized) + continue; + if (sys->thread_cleanup) { + log_debug(LD_GENERAL, "Thread cleanup: %s", sys->name); + sys->thread_cleanup(); + } + } +} + +/** + * 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; ++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 new file mode 100644 index 0000000000..ae0b3df469 --- /dev/null +++ b/src/app/main/subsysmgr.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2003-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 subsysmgr.h + * @brief Header for subsysmgr.c + **/ + +#ifndef TOR_SUBSYSMGR_T +#define TOR_SUBSYSMGR_T + +#include "lib/subsys/subsys.h" + +extern const struct subsys_fns_t *tor_subsystems[]; +extern const unsigned n_tor_subsystems; + +int subsystems_init(void); +int subsystems_init_upto(int level); + +struct pubsub_builder_t; +int subsystems_add_pubsub_upto(struct pubsub_builder_t *builder, + int target_level); +int subsystems_add_pubsub(struct pubsub_builder_t *builder); + +void subsystems_shutdown(void); +void subsystems_shutdown_downto(int level); + +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 new file mode 100644 index 0000000000..cb79909e69 --- /dev/null +++ b/src/app/main/subsystem_list.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2003-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 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/or_sys.h" +#include "feature/control/btrack_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/llharden/winprocess_sys.h" +#include "lib/thread/thread_sys.h" +#include "lib/time/time_sys.h" +#include "lib/tls/tortls_sys.h" +#include "lib/trace/trace_sys.h" +#include "lib/wallclock/wallclock_sys.h" +#include "lib/evloop/evloop_sys.h" + +#include "feature/dirauth/dirauth_sys.h" +#include "feature/hs/hs_sys.h" +#include "feature/metrics/metrics_sys.h" +#include "feature/relay/relay_sys.h" + +#include <stddef.h> + +/** + * Global list of the subsystems in Tor, in the order of their initialization. + * Want to know the exact level numbers? + * We'll implement a level dump command in #31614. + **/ +const subsys_fns_t *tor_subsystems[] = { + &sys_winprocess, + &sys_torerr, + + &sys_wallclock, + &sys_logging, + &sys_threads, + + &sys_tracing, + + &sys_time, + + &sys_crypto, + &sys_compress, + &sys_network, + &sys_tortls, + + &sys_evloop, + &sys_process, + + &sys_mainloop, + &sys_or, + + &sys_relay, + &sys_hs, + + &sys_btrack, + + &sys_dirauth, + &sys_metrics, +}; + +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" |