diff options
Diffstat (limited to 'src/or')
41 files changed, 955 insertions, 276 deletions
diff --git a/src/or/addressmap.c b/src/or/addressmap.c index 7e92633601..9a2cc26b3b 100644 --- a/src/or/addressmap.c +++ b/src/or/addressmap.c @@ -541,7 +541,7 @@ addressmap_have_mapping(const char *address, int update_expiry) * (virtual address mapping) from the controller.) * * <b>new_address</b> should be a newly dup'ed string, which we'll use or - * free as appropriate. We will leave address alone. + * free as appropriate. We will leave <b>address</b> alone. * * If <b>wildcard_addr</b> is true, then the mapping will match any address * equal to <b>address</b>, or any address ending with a period followed by @@ -554,7 +554,6 @@ addressmap_have_mapping(const char *address, int update_expiry) * <b>wildcard_new_addr</b>, remove any mappings that exist from * <b>address</b>. * - * * It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is * not set. */ void diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index b36fed63b3..7f0bcc4150 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1290,7 +1290,7 @@ circuit_extend(cell_t *cell, circuit_t *circ) 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) && + node_supports_ed25519_link_authentication(node, 1) && (node_ed_id = node_get_ed25519_id(node))) { ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id); } @@ -2698,7 +2698,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect) /* Don't send the ed25519 pubkey unless the target node actually supports * authenticating with it. */ - if (node_supports_ed25519_link_authentication(node)) { + if (node_supports_ed25519_link_authentication(node, 0)) { log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node)); ed_pubkey = node_get_ed25519_id(node); } else if (node_get_ed25519_id(node)) { diff --git a/src/or/config.c b/src/or/config.c index 78db03c68a..b0a140d23b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -82,6 +82,7 @@ #include "dirvote.h" #include "dns.h" #include "entrynodes.h" +#include "git_revision.h" #include "geoip.h" #include "hibernate.h" #include "main.h" @@ -483,6 +484,7 @@ static config_var_t option_vars_[] = { V(RendPostPeriod, INTERVAL, "1 hour"), V(RephistTrackTime, INTERVAL, "24 hours"), V(RunAsDaemon, BOOL, "0"), + V(ReducedExitPolicy, BOOL, "0"), OBSOLETE("RunTesting"), // currently unused V(Sandbox, BOOL, "0"), V(SafeLogging, STRING, "1"), @@ -561,6 +563,7 @@ static config_var_t option_vars_[] = { VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword, NULL), VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL), + VAR("__OwningControllerFD",INT,OwningControllerFD, "-1"), V(MinUptimeHidServDirectoryV2, INTERVAL, "96 hours"), V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, " "300, 900, 2147483647"), @@ -833,9 +836,12 @@ set_options(or_options_t *new_val, char **msg) return -1; } if (options_act(old_options) < 0) { /* acting on the options failed. die. */ - log_err(LD_BUG, - "Acting on config options left us in a broken state. Dying."); - exit(1); + if (! tor_event_loop_shutdown_is_pending()) { + log_err(LD_BUG, + "Acting on config options left us in a broken state. Dying."); + tor_shutdown_event_loop_and_exit(1); + } + return -1; } /* Issues a CONF_CHANGED event to notify controller of the change. If Tor is * just starting up then the old_options will be undefined. */ @@ -877,8 +883,6 @@ set_options(or_options_t *new_val, char **msg) return 0; } -extern const char tor_git_revision[]; /* from tor_main.c */ - /** The version of this Tor process, as parsed. */ static char *the_tor_version = NULL; /** A shorter version of this Tor process's version, for export in our router @@ -933,6 +937,10 @@ or_options_free(or_options_t *options) SMARTLIST_FOREACH(options->SchedulerTypes_, int *, i, tor_free(i)); smartlist_free(options->SchedulerTypes_); } + if (options->FilesOpenedByIncludes) { + SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, tor_free(f)); + smartlist_free(options->FilesOpenedByIncludes); + } tor_free(options->BridgePassword_AuthDigest_); tor_free(options->command_arg); tor_free(options->master_key_fname); @@ -1687,8 +1695,11 @@ options_act(const or_options_t *old_options) else protocol_warning_severity_level = LOG_INFO; - if (consider_adding_dir_servers(options, old_options) < 0) + if (consider_adding_dir_servers(options, old_options) < 0) { + // XXXX This should get validated earlier, and committed here, to + // XXXX lower opportunities for reaching an error case. return -1; + } if (rend_non_anonymous_mode_enabled(options)) { log_warn(LD_GENERAL, "This copy of Tor was compiled or configured to run " @@ -1697,6 +1708,7 @@ options_act(const or_options_t *old_options) #ifdef ENABLE_TOR2WEB_MODE /* LCOV_EXCL_START */ + // XXXX This should move into options_validate() if (!options->Tor2webMode) { log_err(LD_CONFIG, "This copy of Tor was compiled to run in " "'tor2web mode'. It can only be run with the Tor2webMode torrc " @@ -1705,6 +1717,7 @@ options_act(const or_options_t *old_options) } /* LCOV_EXCL_STOP */ #else /* !(defined(ENABLE_TOR2WEB_MODE)) */ + // XXXX This should move into options_validate() if (options->Tor2webMode) { log_err(LD_CONFIG, "This copy of Tor was not compiled to run in " "'tor2web mode'. It cannot be run with the Tor2webMode torrc " @@ -1732,9 +1745,11 @@ options_act(const or_options_t *old_options) for (cl = options->Bridges; cl; cl = cl->next) { bridge_line_t *bridge_line = parse_bridge_line(cl->value); if (!bridge_line) { + // LCOV_EXCL_START log_warn(LD_BUG, "Previously validated Bridge line could not be added!"); return -1; + // LCOV_EXCL_STOP } bridge_add_from_config(bridge_line); } @@ -1742,15 +1757,37 @@ options_act(const or_options_t *old_options) } if (running_tor && hs_config_service_all(options, 0)<0) { + // LCOV_EXCL_START log_warn(LD_BUG, "Previously validated hidden services line could not be added!"); return -1; + // LCOV_EXCL_STOP } if (running_tor && rend_parse_service_authorization(options, 0) < 0) { + // LCOV_EXCL_START log_warn(LD_BUG, "Previously validated client authorization for " "hidden services could not be added!"); return -1; + // LCOV_EXCL_STOP + } + + if (running_tor && !old_options && options->OwningControllerFD != -1) { +#ifdef _WIN32 + log_warn(LD_CONFIG, "OwningControllerFD is not supported on Windows. " + "If you need it, tell the Tor developers."); + return -1; +#else + const unsigned ctrl_flags = + CC_LOCAL_FD_IS_OWNER | + CC_LOCAL_FD_IS_AUTHENTICATED; + tor_socket_t ctrl_sock = (tor_socket_t)options->OwningControllerFD; + if (control_connection_add_local_fd(ctrl_sock, ctrl_flags) < 0) { + log_warn(LD_CONFIG, "Could not add local controller connection with " + "given FD."); + return -1; + } +#endif } /* Load state */ @@ -1773,10 +1810,12 @@ options_act(const or_options_t *old_options) if (options->ClientTransportPlugin) { for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { if (parse_transport_line(options, cl->value, 0, 0) < 0) { + // LCOV_EXCL_START log_warn(LD_BUG, "Previously validated ClientTransportPlugin line " "could not be added!"); return -1; + // LCOV_EXCL_STOP } } } @@ -1784,10 +1823,12 @@ 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 } } } @@ -1873,8 +1914,10 @@ options_act(const or_options_t *old_options) /* Set up accounting */ if (accounting_parse_options(options, 0)<0) { - log_warn(LD_CONFIG,"Error in accounting options"); + // 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)); @@ -1897,6 +1940,7 @@ options_act(const or_options_t *old_options) char *http_authenticator; http_authenticator = alloc_http_authenticator(options->BridgePassword); if (!http_authenticator) { + // XXXX This should get validated in options_validate(). log_warn(LD_BUG, "Unable to allocate HTTP authenticator. Not setting " "BridgePassword."); return -1; @@ -1909,9 +1953,12 @@ options_act(const or_options_t *old_options) } if (parse_outbound_addresses(options, 0, &msg) < 0) { - log_warn(LD_BUG, "Failed parsing outbound bind addresses: %s", msg); + // LCOV_EXCL_START + log_warn(LD_BUG, "Failed parsing previously validated outbound " + "bind addresses: %s", msg); tor_free(msg); return -1; + // LCOV_EXCL_STOP } config_maybe_load_geoip_files_(options, old_options); @@ -4607,6 +4654,12 @@ options_transition_allowed(const or_options_t *old, return -1; } + if (old->OwningControllerFD != new_val->OwningControllerFD) { + *msg = tor_strdup("While Tor is running, changing OwningControllerFD " + "is not allowed."); + return -1; + } + if (sandbox_is_active()) { #define SB_NOCHANGE_STR(opt) \ do { \ @@ -5019,7 +5072,8 @@ load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file) /** Read a configuration file into <b>options</b>, finding the configuration * file location based on the command line. After loading the file * call options_init_from_string() to load the config. - * Return 0 if success, -1 if failure. */ + * Return 0 if success, -1 if failure, and 1 if we succeeded but should exit + * anyway. */ int options_init_from_torrc(int argc, char **argv) { @@ -5046,22 +5100,22 @@ options_init_from_torrc(int argc, char **argv) if (config_line_find(cmdline_only_options, "-h") || config_line_find(cmdline_only_options, "--help")) { print_usage(); - exit(0); + return 1; } if (config_line_find(cmdline_only_options, "--list-torrc-options")) { /* For validating whether we've documented everything. */ list_torrc_options(); - exit(0); + return 1; } if (config_line_find(cmdline_only_options, "--list-deprecated-options")) { /* For validating whether what we have deprecated really exists. */ list_deprecated_options(); - exit(0); + return 1; } if (config_line_find(cmdline_only_options, "--version")) { printf("Tor version %s.\n",get_version()); - exit(0); + return 1; } if (config_line_find(cmdline_only_options, "--library-versions")) { @@ -5089,7 +5143,7 @@ options_init_from_torrc(int argc, char **argv) tor_compress_header_version_str(ZSTD_METHOD)); } //TODO: Hex versions? - exit(0); + return 1; } command = CMD_RUN_TOR; @@ -5150,7 +5204,8 @@ options_init_from_torrc(int argc, char **argv) get_options_mutable()->keygen_force_passphrase = FORCE_PASSPHRASE_OFF; } else { log_err(LD_CONFIG, "--no-passphrase specified without --keygen!"); - exit(1); + retval = -1; + goto err; } } @@ -5159,7 +5214,8 @@ options_init_from_torrc(int argc, char **argv) get_options_mutable()->change_key_passphrase = 1; } else { log_err(LD_CONFIG, "--newpass specified without --keygen!"); - exit(1); + retval = -1; + goto err; } } @@ -5169,17 +5225,20 @@ options_init_from_torrc(int argc, char **argv) if (fd_line) { if (get_options()->keygen_force_passphrase == FORCE_PASSPHRASE_OFF) { log_err(LD_CONFIG, "--no-passphrase specified with --passphrase-fd!"); - exit(1); + retval = -1; + goto err; } else if (command != CMD_KEYGEN) { log_err(LD_CONFIG, "--passphrase-fd specified without --keygen!"); - exit(1); + retval = -1; + goto err; } else { const char *v = fd_line->value; int ok = 1; long fd = tor_parse_long(v, 10, 0, INT_MAX, &ok, NULL); if (fd < 0 || ok == 0) { log_err(LD_CONFIG, "Invalid --passphrase-fd value %s", escaped(v)); - exit(1); + retval = -1; + goto err; } get_options_mutable()->keygen_passphrase_fd = (int)fd; get_options_mutable()->use_keygen_passphrase_fd = 1; @@ -5194,7 +5253,8 @@ options_init_from_torrc(int argc, char **argv) if (key_line) { if (command != CMD_KEYGEN) { log_err(LD_CONFIG, "--master-key without --keygen!"); - exit(1); + retval = -1; + goto err; } else { get_options_mutable()->master_key_fname = tor_strdup(key_line->value); } @@ -5242,13 +5302,16 @@ options_init_from_string(const char *cf_defaults, const char *cf, newoptions->command = command; newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL; + smartlist_t *opened_files = smartlist_new(); for (int i = 0; i < 2; ++i) { const char *body = i==0 ? cf_defaults : cf; if (!body) continue; + /* get config lines, assign them */ retval = config_get_lines_include(body, &cl, 1, - body == cf ? &cf_has_include : NULL); + body == cf ? &cf_has_include : NULL, + opened_files); if (retval < 0) { err = SETOPT_ERR_PARSE; goto err; @@ -5277,6 +5340,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, } newoptions->IncludeUsed = cf_has_include; + newoptions->FilesOpenedByIncludes = opened_files; /* If this is a testing network configuration, change defaults * for a list of dependent config options, re-initialize newoptions @@ -5316,13 +5380,16 @@ options_init_from_string(const char *cf_defaults, const char *cf, newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL; /* Assign all options a second time. */ + opened_files = smartlist_new(); for (int i = 0; i < 2; ++i) { const char *body = i==0 ? cf_defaults : cf; if (!body) continue; + /* get config lines, assign them */ retval = config_get_lines_include(body, &cl, 1, - body == cf ? &cf_has_include : NULL); + body == cf ? &cf_has_include : NULL, + opened_files); if (retval < 0) { err = SETOPT_ERR_PARSE; goto err; @@ -5347,6 +5414,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, newoptions->IncludeUsed = cf_has_include; in_option_validation = 1; + newoptions->FilesOpenedByIncludes = opened_files; /* Validate newoptions */ if (options_validate(oldoptions, newoptions, newdefaultoptions, @@ -5373,6 +5441,12 @@ options_init_from_string(const char *cf_defaults, const char *cf, err: in_option_validation = 0; + if (opened_files) { + 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); if (*msg) { @@ -7889,28 +7963,6 @@ write_to_data_subdir(const char* subdir, const char* fname, return return_val; } -/** Given a file name check to see whether the file exists but has not been - * modified for a very long time. If so, remove it. */ -void -remove_file_if_very_old(const char *fname, time_t now) -{ -#define VERY_OLD_FILE_AGE (28*24*60*60) - struct stat st; - - log_debug(LD_FS, "stat()ing %s", fname); - if (stat(sandbox_intern_string(fname), &st)==0 && - st.st_mtime < now-VERY_OLD_FILE_AGE) { - char buf[ISO_TIME_LEN+1]; - format_local_iso_time(buf, st.st_mtime); - log_notice(LD_GENERAL, "Obsolete file %s hasn't been modified since %s. " - "Removing it.", fname, buf); - if (unlink(fname) != 0) { - log_warn(LD_FS, "Failed to unlink %s: %s", - fname, strerror(errno)); - } - } -} - /** 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. */ diff --git a/src/or/connection.c b/src/or/connection.c index d2cf4fb416..92ccd3d5c8 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -118,8 +118,6 @@ static connection_t *connection_listener_new( const port_cfg_t *portcfg); static void connection_init(time_t now, connection_t *conn, int type, int socket_family); -static int connection_init_accepted_conn(connection_t *conn, - const listener_connection_t *listener); static int connection_handle_listener_read(connection_t *conn, int new_type); static int connection_bucket_should_increase(int bucket, or_connection_t *conn); @@ -1666,11 +1664,15 @@ connection_handle_listener_read(connection_t *conn, int new_type) } /** Initialize states for newly accepted connection <b>conn</b>. + * * If conn is an OR, start the TLS handshake. + * * If conn is a transparent AP, get its original destination * and place it in circuit_wait. + * + * The <b>listener</b> parameter is only used for AP connections. */ -static int +int connection_init_accepted_conn(connection_t *conn, const listener_connection_t *listener) { @@ -1750,7 +1752,11 @@ connection_connect_sockaddr,(connection_t *conn, if (get_options()->DisableNetwork) { /* We should never even try to connect anyplace if DisableNetwork is set. - * Warn if we do, and refuse to make the connection. */ + * Warn if we do, and refuse to make the connection. + * + * We only check DisableNetwork here, not we_are_hibernating(), since + * we'll still try to fulfill client requests sometimes in the latter case + * (if it is soft hibernation) */ static ratelim_t disablenet_violated = RATELIM_INIT(30*60); *socket_error = SOCK_ERRNO(ENETUNREACH); log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG, @@ -4049,6 +4055,68 @@ connection_flush(connection_t *conn) return connection_handle_write(conn, 1); } +/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf: + * + * Return true iff it is okay to queue bytes on <b>conn</b>'s outbuf for + * writing. + */ +static int +connection_may_write_to_buf(connection_t *conn) +{ + /* if it's marked for close, only allow write if we mean to flush it */ + if (conn->marked_for_close && !conn->hold_open_until_flushed) + return 0; + + return 1; +} + +/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf: + * + * Called when an attempt to add bytes on <b>conn</b>'s outbuf has failed; + * mark the connection and warn as appropriate. + */ +static void +connection_write_to_buf_failed(connection_t *conn) +{ + if (CONN_IS_EDGE(conn)) { + /* if it failed, it means we have our package/delivery windows set + wrong compared to our max outbuf size. close the whole circuit. */ + log_warn(LD_NET, + "write_to_buf failed. Closing circuit (fd %d).", (int)conn->s); + circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)), + END_CIRC_REASON_INTERNAL); + } else if (conn->type == CONN_TYPE_OR) { + or_connection_t *orconn = TO_OR_CONN(conn); + log_warn(LD_NET, + "write_to_buf failed on an orconn; notifying of error " + "(fd %d)", (int)(conn->s)); + connection_or_close_for_error(orconn, 0); + } else { + log_warn(LD_NET, + "write_to_buf failed. Closing connection (fd %d).", + (int)conn->s); + connection_mark_for_close(conn); + } +} + +/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf: + * + * Called when an attempt to add bytes on <b>conn</b>'s outbuf has succeeded: + * record the number of bytes added. + */ +static void +connection_write_to_buf_commit(connection_t *conn, size_t len) +{ + /* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING + * state, we don't want to try to write it right away, since + * conn->write_event won't be set yet. Otherwise, write data from + * this conn as the socket is available. */ + if (conn->write_event) { + connection_start_writing(conn); + } + conn->outbuf_flushlen += len; +} + /** Append <b>len</b> bytes of <b>string</b> onto <b>conn</b>'s * outbuf, and ask it to start writing. * @@ -4063,58 +4131,52 @@ connection_write_to_buf_impl_,(const char *string, size_t len, { /* XXXX This function really needs to return -1 on failure. */ int r; - size_t old_datalen; if (!len && !(zlib<0)) return; - /* if it's marked for close, only allow write if we mean to flush it */ - if (conn->marked_for_close && !conn->hold_open_until_flushed) + + if (!connection_may_write_to_buf(conn)) return; - old_datalen = buf_datalen(conn->outbuf); + size_t written; + if (zlib) { + size_t old_datalen = buf_datalen(conn->outbuf); dir_connection_t *dir_conn = TO_DIR_CONN(conn); int done = zlib < 0; CONN_LOG_PROTECT(conn, r = buf_add_compress(conn->outbuf, - dir_conn->compress_state, - string, len, done)); + dir_conn->compress_state, + string, len, done)); + written = buf_datalen(conn->outbuf) - old_datalen; } else { CONN_LOG_PROTECT(conn, r = buf_add(conn->outbuf, string, len)); + written = len; } if (r < 0) { - if (CONN_IS_EDGE(conn)) { - /* if it failed, it means we have our package/delivery windows set - wrong compared to our max outbuf size. close the whole circuit. */ - log_warn(LD_NET, - "write_to_buf failed. Closing circuit (fd %d).", (int)conn->s); - circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)), - END_CIRC_REASON_INTERNAL); - } else if (conn->type == CONN_TYPE_OR) { - or_connection_t *orconn = TO_OR_CONN(conn); - log_warn(LD_NET, - "write_to_buf failed on an orconn; notifying of error " - "(fd %d)", (int)(conn->s)); - connection_or_close_for_error(orconn, 0); - } else { - log_warn(LD_NET, - "write_to_buf failed. Closing connection (fd %d).", - (int)conn->s); - connection_mark_for_close(conn); - } + connection_write_to_buf_failed(conn); return; } + connection_write_to_buf_commit(conn, written); +} - /* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING - * state, we don't want to try to write it right away, since - * conn->write_event won't be set yet. Otherwise, write data from - * this conn as the socket is available. */ - if (conn->write_event) { - connection_start_writing(conn); - } - if (zlib) { - conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen; - } else { - conn->outbuf_flushlen += len; - } +/** + * Add all bytes from <b>buf</b> to <b>conn</b>'s outbuf, draining them + * from <b>buf</b>. (If the connection is marked and will soon be closed, + * nothing is drained.) + */ +void +connection_buf_add_buf(connection_t *conn, buf_t *buf) +{ + tor_assert(conn); + tor_assert(buf); + size_t len = buf_datalen(buf); + if (len == 0) + return; + + if (!connection_may_write_to_buf(conn)) + return; + + buf_move_all(conn->outbuf, buf); + connection_write_to_buf_commit(conn, len); } #define CONN_GET_ALL_TEMPLATE(var, test) \ diff --git a/src/or/connection.h b/src/or/connection.h index 4a5bd6971b..1d41a3c4f5 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -26,7 +26,8 @@ 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)); void connection_free_all(void); @@ -155,6 +156,7 @@ connection_buf_add_compress(const char *string, size_t len, { connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1); } +void connection_buf_add_buf(connection_t *conn, buf_t *buf); /* DOCDOC connection_get_inbuf_len */ static size_t connection_get_inbuf_len(connection_t *conn); @@ -243,7 +245,6 @@ 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 connection_dump_buffer_mem_stats(int severity); -void remove_file_if_very_old(const char *fname, time_t now); void clock_skew_warning(const connection_t *conn, long apparent_skew, int trusted, log_domain_mask_t domain, diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index f178917f0b..41f0fe6a1d 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -999,7 +999,7 @@ connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn, * So the fix is to tell it right now that it ought to finish its loop at * its next available opportunity. */ - tell_event_loop_to_finish(); + tell_event_loop_to_run_external_code(); } /** Mark <b>entry_conn</b> as no longer waiting for a circuit. */ diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 9e34063609..7af1f2b645 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -886,7 +886,7 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here) const node_t *r = node_get_by_id(id_digest); if (r && - node_supports_ed25519_link_authentication(r) && + node_supports_ed25519_link_authentication(r, 1) && ! node_ed25519_id_matches(r, ed_id)) { /* If this node is capable of proving an ed25519 ID, * we can't call this a canonical connection unless both IDs match. */ diff --git a/src/or/control.c b/src/or/control.c index 202366aaec..0d462b2d7d 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -549,6 +549,49 @@ decode_escaped_string(const char *start, size_t in_len_max, return end+1; } +/** Create and add a new controller connection on <b>sock</b>. If + * <b>CC_LOCAL_FD_IS_OWNER</b> is set in <b>flags</b>, this Tor process should + * exit when the connection closes. If <b>CC_LOCAL_FD_IS_AUTHENTICATED</b> + * is set, then the connection does not need to authenticate. + */ +int +control_connection_add_local_fd(tor_socket_t sock, unsigned flags) +{ + if (BUG(! SOCKET_OK(sock))) + return -1; + const int is_owner = !!(flags & CC_LOCAL_FD_IS_OWNER); + const int is_authenticated = !!(flags & CC_LOCAL_FD_IS_AUTHENTICATED); + control_connection_t *control_conn = control_connection_new(AF_UNSPEC); + connection_t *conn = TO_CONN(control_conn); + conn->s = sock; + tor_addr_make_unspec(&conn->addr); + conn->port = 1; + conn->address = tor_strdup("<local socket>"); + + /* We take ownership of this socket so that later, when we close it, + * we don't freak out. */ + tor_take_socket_ownership(sock); + + if (set_socket_nonblocking(sock) < 0 || + connection_add(conn) < 0) { + connection_free(conn); + return -1; + } + + control_conn->is_owning_control_connection = is_owner; + + if (connection_init_accepted_conn(conn, NULL) < 0) { + connection_mark_for_close(conn); + return -1; + } + + if (is_authenticated) { + conn->state = CONTROL_CONN_STATE_OPEN; + } + + return 0; +} + /** Acts like sprintf, but writes its formatted string to the end of * <b>conn</b>-\>outbuf. */ static void @@ -6571,8 +6614,7 @@ monitor_owning_controller_process(const char *process_spec) "owning controller: %s. Exiting.", msg); owning_controller_process_spec = NULL; - tor_cleanup(); - exit(1); + tor_shutdown_event_loop_and_exit(1); } } diff --git a/src/or/control.h b/src/or/control.h index e957b593a6..7ec182cb78 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -27,6 +27,10 @@ void control_ports_write_to_file(void); #define LOG_FN_CONN(conn, args) \ CONN_LOG_PROTECT(conn, log_fn args) +#define CC_LOCAL_FD_IS_OWNER (1u<<0) +#define CC_LOCAL_FD_IS_AUTHENTICATED (1u<<1) +int control_connection_add_local_fd(tor_socket_t sock, unsigned flags); + int connection_control_finished_flushing(control_connection_t *conn); int connection_control_reached_eof(control_connection_t *conn); void connection_control_closed(control_connection_t *conn); diff --git a/src/or/directory.c b/src/or/directory.c index 66bdef2361..0c40b2018c 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -2196,8 +2196,6 @@ load_downloaded_routers(const char *body, smartlist_t *which, return added; } -static int handle_response_fetch_consensus(dir_connection_t *, - const response_handler_args_t *); static int handle_response_fetch_certificate(dir_connection_t *, const response_handler_args_t *); static int handle_response_fetch_status_vote(dir_connection_t *, @@ -2542,7 +2540,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) * consensus document by checking the consensus, storing it, and marking * router requests as reachable. **/ -static int +STATIC int handle_response_fetch_consensus(dir_connection_t *conn, const response_handler_args_t *args) { @@ -3476,63 +3474,47 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length, long cache_lifetime) { char date[RFC1123_TIME_LEN+1]; - char tmp[1024]; - char *cp; time_t now = time(NULL); + buf_t *buf = buf_new_with_capacity(1024); tor_assert(conn); format_rfc1123_time(date, now); - cp = tmp; - tor_snprintf(cp, sizeof(tmp), - "HTTP/1.0 200 OK\r\nDate: %s\r\n", - date); - cp += strlen(tmp); + + buf_add_printf(buf, "HTTP/1.0 200 OK\r\nDate: %s\r\n", date); if (type) { - tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type); - cp += strlen(cp); + buf_add_printf(buf, "Content-Type: %s\r\n", type); } if (!is_local_addr(&conn->base_.addr)) { /* Don't report the source address for a nearby/private connection. * Otherwise we tend to mis-report in cases where incoming ports are * being forwarded to a Tor server running behind the firewall. */ - tor_snprintf(cp, sizeof(tmp)-(cp-tmp), - X_ADDRESS_HEADER "%s\r\n", conn->base_.address); - cp += strlen(cp); + buf_add_printf(buf, X_ADDRESS_HEADER "%s\r\n", conn->base_.address); } if (encoding) { - tor_snprintf(cp, sizeof(tmp)-(cp-tmp), - "Content-Encoding: %s\r\n", encoding); - cp += strlen(cp); + buf_add_printf(buf, "Content-Encoding: %s\r\n", encoding); } if (length >= 0) { - tor_snprintf(cp, sizeof(tmp)-(cp-tmp), - "Content-Length: %ld\r\n", (long)length); - cp += strlen(cp); + buf_add_printf(buf, "Content-Length: %ld\r\n", (long)length); } if (cache_lifetime > 0) { char expbuf[RFC1123_TIME_LEN+1]; format_rfc1123_time(expbuf, (time_t)(now + cache_lifetime)); /* We could say 'Cache-control: max-age=%d' here if we start doing * http/1.1 */ - tor_snprintf(cp, sizeof(tmp)-(cp-tmp), - "Expires: %s\r\n", expbuf); - cp += strlen(cp); + buf_add_printf(buf, "Expires: %s\r\n", expbuf); } else if (cache_lifetime == 0) { /* We could say 'Cache-control: no-cache' here if we start doing * http/1.1 */ - strlcpy(cp, "Pragma: no-cache\r\n", sizeof(tmp)-(cp-tmp)); - cp += strlen(cp); + buf_add_string(buf, "Pragma: no-cache\r\n"); } if (extra_headers) { - strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp)); - cp += strlen(cp); + buf_add_string(buf, extra_headers); } - if (sizeof(tmp)-(cp-tmp) > 3) - memcpy(cp, "\r\n", 3); - else - tor_assert(0); - connection_buf_add(tmp, strlen(tmp), TO_CONN(conn)); + buf_add_string(buf, "\r\n"); + + connection_buf_add_buf(TO_CONN(conn), buf); + buf_free(buf); } /** As write_http_response_header_impl, but sets encoding and content-typed diff --git a/src/or/directory.h b/src/or/directory.h index 5e6a91d3e7..3aef600716 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -238,6 +238,9 @@ STATIC int handle_response_fetch_hsdesc_v3(dir_connection_t *conn, STATIC int handle_response_fetch_microdesc(dir_connection_t *conn, const response_handler_args_t *args); +STATIC int handle_response_fetch_consensus(dir_connection_t *conn, + const response_handler_args_t *args); + #endif /* defined(DIRECTORY_PRIVATE) */ #ifdef TOR_UNIT_TESTS diff --git a/src/or/dirserv.c b/src/or/dirserv.c index ddee92da55..432fe6ae2b 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -1519,15 +1519,21 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) node->ri && node->ri->purpose != ROUTER_PURPOSE_BRIDGE) continue; + + routerinfo_t *ri = node->ri; + if (ri) { + node->is_exit = (!router_exit_policy_rejects_all(ri) && + exit_policy_is_general_exit(ri->exit_policy)); + } + if (router_counts_toward_thresholds(node, now, omit_as_sybil, require_mbw)) { - routerinfo_t *ri = node->ri; const char *id = node->identity; uint32_t bw_kb; + /* resolve spurious clang shallow analysis null pointer errors */ tor_assert(ri); - node->is_exit = (!router_exit_policy_rejects_all(ri) && - exit_policy_is_general_exit(ri->exit_policy)); + uptimes[n_active] = (uint32_t)real_uptime(ri, now); mtbfs[n_active] = rep_hist_get_stability(id, now); tks [n_active] = rep_hist_get_weighted_time_known(id, now); @@ -3284,7 +3290,7 @@ dirserv_orconn_tls_done(const tor_addr_t *addr, ri = node->ri; if (get_options()->AuthDirTestEd25519LinkKeys && - node_supports_ed25519_link_authentication(node) && + 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 * the routerinfo, but if we *HAVE* been told one in the routerinfo, it @@ -3367,7 +3373,7 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router) tor_assert(node); if (options->AuthDirTestEd25519LinkKeys && - node_supports_ed25519_link_authentication(node)) { + node_supports_ed25519_link_authentication(node, 1)) { ed_id_key = &router->cache_info.signing_key_cert->signing_key; } else { ed_id_key = NULL; diff --git a/src/or/dns.c b/src/or/dns.c index 7dc3575f53..f140051e81 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -1666,7 +1666,7 @@ launch_resolve,(cached_resolve_t *resolve)) tor_addr_t a; int r; - if (get_options()->DisableNetwork) + if (net_is_disabled()) return -1; /* What? Nameservers not configured? Sounds like a bug. */ @@ -1901,7 +1901,7 @@ launch_test_addresses(evutil_socket_t fd, short event, void *args) (void)event; (void)args; - if (options->DisableNetwork) + if (net_is_disabled()) return; log_info(LD_EXIT, "Launching checks to see whether our nameservers like to " diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index ce701a20f2..38b9c2c56f 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -2217,9 +2217,9 @@ circuit_guard_state_free(circuit_guard_state_t *state) /** Allocate and return a new circuit_guard_state_t to track the result * of using <b>guard</b> for a given operation. */ -static circuit_guard_state_t * -circuit_guard_state_new(entry_guard_t *guard, unsigned state, - entry_guard_restriction_t *rst) +MOCK_IMPL(STATIC circuit_guard_state_t *, +circuit_guard_state_new,(entry_guard_t *guard, unsigned state, + entry_guard_restriction_t *rst)) { circuit_guard_state_t *result; diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index 49bb3e55c4..3ca966bc78 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -495,6 +495,10 @@ STATIC entry_guard_t *get_sampled_guard_with_id(guard_selection_t *gs, MOCK_DECL(STATIC time_t, randomize_time, (time_t now, time_t max_backdate)); +MOCK_DECL(STATIC circuit_guard_state_t *, + circuit_guard_state_new,(entry_guard_t *guard, unsigned state, + entry_guard_restriction_t *rst)); + 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); diff --git a/src/or/geoip.c b/src/or/geoip.c index 3944b2cf69..c976b8d276 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -30,6 +30,7 @@ #define GEOIP_PRIVATE #include "or.h" #include "ht.h" +#include "buffers.h" #include "config.h" #include "control.h" #include "dnsserv.h" @@ -930,9 +931,9 @@ static char * geoip_get_dirreq_history(dirreq_type_t type) { char *result = NULL; + buf_t *buf = NULL; smartlist_t *dirreq_completed = NULL; uint32_t complete = 0, timeouts = 0, running = 0; - int bufsize = 1024, written; dirreq_map_entry_t **ptr, **next; struct timeval now; @@ -965,13 +966,9 @@ geoip_get_dirreq_history(dirreq_type_t type) DIR_REQ_GRANULARITY); running = round_uint32_to_next_multiple_of(running, DIR_REQ_GRANULARITY); - result = tor_malloc_zero(bufsize); - written = tor_snprintf(result, bufsize, "complete=%u,timeout=%u," - "running=%u", complete, timeouts, running); - if (written < 0) { - tor_free(result); - goto done; - } + buf = buf_new_with_capacity(1024); + buf_add_printf(buf, "complete=%u,timeout=%u," + "running=%u", complete, timeouts, running); #define MIN_DIR_REQ_RESPONSES 16 if (complete >= MIN_DIR_REQ_RESPONSES) { @@ -992,7 +989,7 @@ geoip_get_dirreq_history(dirreq_type_t type) dltimes[ent_sl_idx] = bytes_per_second; } SMARTLIST_FOREACH_END(ent); median_uint32(dltimes, complete); /* sorts as a side effect. */ - written = tor_snprintf(result + written, bufsize - written, + buf_add_printf(buf, ",min=%u,d1=%u,d2=%u,q1=%u,d3=%u,d4=%u,md=%u," "d6=%u,d7=%u,q3=%u,d8=%u,d9=%u,max=%u", dltimes[0], @@ -1008,14 +1005,15 @@ geoip_get_dirreq_history(dirreq_type_t type) dltimes[8*complete/10-1], dltimes[9*complete/10-1], dltimes[complete-1]); - if (written<0) - tor_free(result); tor_free(dltimes); } - done: + + result = buf_extract(buf, NULL); + SMARTLIST_FOREACH(dirreq_completed, dirreq_map_entry_t *, ent, tor_free(ent)); smartlist_free(dirreq_completed); + buf_free(buf); return result; } diff --git a/src/or/git_revision.c b/src/or/git_revision.c new file mode 100644 index 0000000000..8f326b8751 --- /dev/null +++ b/src/or/git_revision.c @@ -0,0 +1,17 @@ +/* Copyright 2001-2004 Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "git_revision.h" + +/** String describing which Tor Git repository version the source was + * built from. This string is generated by a bit of shell kludging in + * src/or/include.am, and is usually right. + */ +const char tor_git_revision[] = +#ifndef _MSC_VER +#include "micro-revision.i" +#endif + ""; + diff --git a/src/or/git_revision.h b/src/or/git_revision.h new file mode 100644 index 0000000000..1ceaeedf16 --- /dev/null +++ b/src/or/git_revision.h @@ -0,0 +1,12 @@ +/* Copyright 2001-2004 Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_GIT_REVISION_H +#define TOR_GIT_REVISION_H + +extern const char tor_git_revision[]; + +#endif + diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 74ab766468..4dc35f68d0 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -34,6 +34,7 @@ hibernating, phase 2: #include "config.h" #include "connection.h" #include "connection_edge.h" +#include "connection_or.h" #include "control.h" #include "hibernate.h" #include "main.h" @@ -818,8 +819,8 @@ hibernate_begin(hibernate_state_t new_state, time_t now) log_notice(LD_GENERAL,"SIGINT received %s; exiting now.", hibernate_state == HIBERNATE_STATE_EXITING ? "a second time" : "while hibernating"); - tor_cleanup(); - exit(0); + tor_shutdown_event_loop_and_exit(0); + return; } if (new_state == HIBERNATE_STATE_LOWBANDWIDTH && @@ -906,20 +907,23 @@ hibernate_go_dormant(time_t now) while ((conn = connection_get_by_type(CONN_TYPE_OR)) || (conn = connection_get_by_type(CONN_TYPE_AP)) || (conn = connection_get_by_type(CONN_TYPE_EXIT))) { - if (CONN_IS_EDGE(conn)) + if (CONN_IS_EDGE(conn)) { connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_HIBERNATING); + } log_info(LD_NET,"Closing conn type %d", conn->type); - if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */ + if (conn->type == CONN_TYPE_AP) { + /* send socks failure if needed */ connection_mark_unattached_ap(TO_ENTRY_CONN(conn), END_STREAM_REASON_HIBERNATING); - else if (conn->type == CONN_TYPE_OR) { + } else if (conn->type == CONN_TYPE_OR) { if (TO_OR_CONN(conn)->chan) { - channel_mark_for_close(TLS_CHAN_TO_BASE(TO_OR_CONN(conn)->chan)); + connection_or_close_normally(TO_OR_CONN(conn), 0); } else { connection_mark_for_close(conn); } - } else + } else { connection_mark_for_close(conn); + } } if (now < interval_wakeup_time) @@ -980,8 +984,7 @@ consider_hibernation(time_t now) tor_assert(shutdown_time); if (shutdown_time <= now) { log_notice(LD_GENERAL, "Clean shutdown finished. Exiting."); - tor_cleanup(); - exit(0); + tor_shutdown_event_loop_and_exit(0); } return; /* if exiting soon, don't worry about bandwidth limits */ } diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c index ee952f4d68..a232a40c80 100644 --- a/src/or/hs_circuit.c +++ b/src/or/hs_circuit.c @@ -13,6 +13,7 @@ #include "circuitlist.h" #include "circuituse.h" #include "config.h" +#include "nodelist.h" #include "policies.h" #include "relay.h" #include "rendservice.h" @@ -553,76 +554,99 @@ retry_service_rendezvous_point(const origin_circuit_t *circ) return; } -/* Using an extend info object ei, set all possible link specifiers in lspecs. - * legacy ID is mandatory thus MUST be present in ei. If IPv4 is not present, - * logs a BUG() warning, and returns an empty smartlist. Clients never make - * direct connections to rendezvous points, so they should always have an - * IPv4 address in ei. */ +/* Add all possible link specifiers in node to lspecs. + * legacy ID is mandatory thus MUST be present in node. If the primary address + * is not IPv4, log a BUG() warning, and return an empty smartlist. + * Includes ed25519 id and IPv6 link specifiers if present in the node. */ static void -get_lspecs_from_extend_info(const extend_info_t *ei, smartlist_t *lspecs) +get_lspecs_from_node(const node_t *node, smartlist_t *lspecs) { link_specifier_t *ls; + tor_addr_port_t ap; - tor_assert(ei); + tor_assert(node); tor_assert(lspecs); - /* We require IPv4, we will add IPv6 support in a later tor version */ - if (BUG(!tor_addr_is_v4(&ei->addr))) { + /* Get the relay's IPv4 address. */ + node_get_prim_orport(node, &ap); + + /* We expect the node's primary address to be a valid IPv4 address. + * This conforms to the protocol, which requires either an IPv4 or IPv6 + * address (or both). */ + if (BUG(!tor_addr_is_v4(&ap.addr)) || + BUG(!tor_addr_port_is_valid_ap(&ap, 0))) { return; } ls = link_specifier_new(); link_specifier_set_ls_type(ls, LS_IPV4); - link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ei->addr)); - link_specifier_set_un_ipv4_port(ls, ei->port); + link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ap.addr)); + link_specifier_set_un_ipv4_port(ls, ap.port); /* Four bytes IPv4 and two bytes port. */ - link_specifier_set_ls_len(ls, sizeof(ei->addr.addr.in_addr) + - sizeof(ei->port)); + link_specifier_set_ls_len(ls, sizeof(ap.addr.addr.in_addr) + + sizeof(ap.port)); smartlist_add(lspecs, ls); - /* Legacy ID is mandatory. */ + /* Legacy ID is mandatory and will always be present in node. */ ls = link_specifier_new(); link_specifier_set_ls_type(ls, LS_LEGACY_ID); - memcpy(link_specifier_getarray_un_legacy_id(ls), ei->identity_digest, + memcpy(link_specifier_getarray_un_legacy_id(ls), node->identity, link_specifier_getlen_un_legacy_id(ls)); link_specifier_set_ls_len(ls, link_specifier_getlen_un_legacy_id(ls)); smartlist_add(lspecs, ls); - /* ed25519 ID is only included if the extend_info has it. */ - if (!ed25519_public_key_is_zero(&ei->ed_identity)) { + /* ed25519 ID is only included if the node has it. */ + if (!ed25519_public_key_is_zero(&node->ed25519_id)) { ls = link_specifier_new(); link_specifier_set_ls_type(ls, LS_ED25519_ID); - memcpy(link_specifier_getarray_un_ed25519_id(ls), &ei->ed_identity, + memcpy(link_specifier_getarray_un_ed25519_id(ls), &node->ed25519_id, link_specifier_getlen_un_ed25519_id(ls)); link_specifier_set_ls_len(ls, link_specifier_getlen_un_ed25519_id(ls)); smartlist_add(lspecs, ls); } + + /* Check for IPv6. If so, include it as well. */ + if (node_has_ipv6_orport(node)) { + ls = link_specifier_new(); + node_get_pref_ipv6_orport(node, &ap); + link_specifier_set_ls_type(ls, LS_IPV6); + size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls); + const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ap.addr); + uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls); + memcpy(ipv6_array, in6_addr, addr_len); + link_specifier_set_un_ipv6_port(ls, ap.port); + /* Sixteen bytes IPv6 and two bytes port. */ + link_specifier_set_ls_len(ls, addr_len + sizeof(ap.port)); + smartlist_add(lspecs, ls); + } } -/* Using the given descriptor intro point ip, the extend information of the - * rendezvous point rp_ei and the service's subcredential, populate 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. * - * This can't fail but the ip MUST be a valid object containing the needed - * keys and authentication method. */ + * If rp_node has an invalid primary address, intro1_data->link_specifiers + * will be an empty list. Otherwise, this function can't fail. The ip + * MUST be a valid object containing the needed keys and authentication + * method. */ static void setup_introduce1_data(const hs_desc_intro_point_t *ip, - const extend_info_t *rp_ei, + const node_t *rp_node, const uint8_t *subcredential, hs_cell_introduce1_data_t *intro1_data) { smartlist_t *rp_lspecs; tor_assert(ip); - tor_assert(rp_ei); + tor_assert(rp_node); tor_assert(subcredential); tor_assert(intro1_data); /* Build the link specifiers from the extend information of the rendezvous * circuit that we've picked previously. */ rp_lspecs = smartlist_new(); - get_lspecs_from_extend_info(rp_ei, rp_lspecs); + get_lspecs_from_node(rp_node, rp_lspecs); /* Populate the introduce1 data object. */ memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t)); @@ -633,7 +657,7 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip, intro1_data->auth_pk = &ip->auth_key_cert->signed_key; intro1_data->enc_pk = &ip->enc_key; intro1_data->subcredential = subcredential; - intro1_data->onion_pk = &rp_ei->curve25519_onion_key; + intro1_data->onion_pk = node_get_curve25519_onion_key(rp_node); intro1_data->link_specifiers = rp_lspecs; } @@ -1077,11 +1101,21 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ, tor_assert(ip); tor_assert(subcredential); + /* It is undefined behavior in hs_cell_introduce1_data_clear() if intro1_data + * has been declared on the stack but not initialized. Here, we set it to 0. + */ + memset(&intro1_data, 0, sizeof(hs_cell_introduce1_data_t)); + /* This takes various objects in order to populate the introduce1 data * object which is used to build the content of the cell. */ - setup_introduce1_data(ip, rend_circ->build_state->chosen_exit, - subcredential, &intro1_data); - /* If we didn't get any link specifiers, it's because our extend info was + const node_t *exit_node = build_state_get_exit_node(rend_circ->build_state); + if (exit_node == NULL) { + log_info(LD_REND, "Unable to get rendezvous point for circuit %u. " + "Failing.", TO_CIRCUIT(intro_circ)->n_circ_id); + goto done; + } + setup_introduce1_data(ip, exit_node, subcredential, &intro1_data); + /* If we didn't get any link specifiers, it's because our node was * bad. */ if (BUG(!intro1_data.link_specifiers) || !smartlist_len(intro1_data.link_specifiers)) { diff --git a/src/or/hs_service.c b/src/or/hs_service.c index a2082b3914..8e2f52dcf0 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -1572,7 +1572,7 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) /* Let's do a basic sanity check here so that we don't end up advertising the * ed25519 identity key of relays that don't actually support the link * protocol */ - if (!node_supports_ed25519_link_authentication(node)) { + if (!node_supports_ed25519_link_authentication(node, 0)) { tor_assert_nonfatal(ed25519_public_key_is_zero(&info->ed_identity)); } else { /* Make sure we *do* have an ed key if we support the link authentication. diff --git a/src/or/include.am b/src/or/include.am index 7216aba9af..b783f4855a 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -51,6 +51,7 @@ LIBTOR_A_SOURCES = \ src/or/geoip.c \ src/or/entrynodes.c \ src/or/ext_orport.c \ + src/or/git_revision.c \ src/or/hibernate.c \ src/or/hs_cache.c \ src/or/hs_cell.c \ @@ -78,6 +79,7 @@ LIBTOR_A_SOURCES = \ src/or/parsecommon.c \ src/or/periodic.c \ src/or/protover.c \ + src/or/protover_rust.c \ src/or/proto_cell.c \ src/or/proto_control0.c \ src/or/proto_ext_or.c \ @@ -104,6 +106,7 @@ LIBTOR_A_SOURCES = \ src/or/statefile.c \ src/or/status.c \ src/or/torcert.c \ + src/or/tor_api.c \ src/or/onion_ntor.c \ $(tor_platform_source) @@ -189,6 +192,7 @@ ORHEADERS = \ src/or/fp_pair.h \ src/or/geoip.h \ src/or/entrynodes.h \ + src/or/git_revision.h \ src/or/hibernate.h \ src/or/hs_cache.h \ src/or/hs_cell.h \ @@ -243,9 +247,13 @@ ORHEADERS = \ src/or/scheduler.h \ src/or/statefile.h \ src/or/status.h \ - src/or/torcert.h + src/or/torcert.h \ + src/or/tor_api_internal.h -noinst_HEADERS+= $(ORHEADERS) micro-revision.i +# This may someday want to be an installed file? +noinst_HEADERS += src/or/tor_api.h + +noinst_HEADERS += $(ORHEADERS) micro-revision.i micro-revision.i: FORCE $(AM_V_at)rm -f micro-revision.tmp; \ diff --git a/src/or/main.c b/src/or/main.c index c340e4128b..e349703918 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -60,7 +60,6 @@ #include "circuitlist.h" #include "circuituse.h" #include "command.h" -#include "compat_rust.h" #include "compress.h" #include "config.h" #include "confparse.h" @@ -106,6 +105,8 @@ #include "shared_random.h" #include "statefile.h" #include "status.h" +#include "tor_api.h" +#include "tor_api_internal.h" #include "util_process.h" #include "ext_orport.h" #ifdef USE_DMALLOC @@ -128,6 +129,12 @@ 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 +char *rust_welcome_string(void); +#endif + /********* PROTOTYPES **********/ static void dumpmemusage(int severity); @@ -140,6 +147,8 @@ static void connection_start_reading_from_linked_conn(connection_t *conn); static int connection_should_read_from_linked_conn(connection_t *conn); static int run_main_loop_until_done(void); static void process_signal(int sig); +static void shutdown_did_not_work_callback(evutil_socket_t fd, short event, + void *arg) ATTR_NORETURN; /********* START VARIABLES **********/ int global_read_bucket; /**< Max number of bytes I can read this second. */ @@ -192,6 +201,14 @@ static smartlist_t *active_linked_connection_lst = NULL; * <b>loop_once</b>. If so, there's no need to trigger a loopexit in order * to handle linked connections. */ static int called_loop_once = 0; +/** Flag: if true, it's time to shut down, so the main loop should exit as + * soon as possible. + */ +static int main_loop_should_exit = 0; +/** The return value that the main loop should yield when it exits, if + * main_loop_should_exit is true. + */ +static int main_loop_exit_value = 0; /** We set this to 1 when we've opened a circuit, so we can print a log * entry to inform the user that Tor is working. We set it to 0 when @@ -637,9 +654,10 @@ connection_should_read_from_linked_conn(connection_t *conn) /** If we called event_base_loop() and told it to never stop until it * runs out of events, now we've changed our mind: tell it we want it to - * finish. */ + * exit once the current round of callbacks is done, so that we can + * run external code, and then return to the main loop. */ void -tell_event_loop_to_finish(void) +tell_event_loop_to_run_external_code(void) { if (!called_loop_once) { struct timeval tv = { 0, 0 }; @@ -648,6 +666,54 @@ tell_event_loop_to_finish(void) } } +/** Failsafe measure that should never actually be necessary: If + * tor_shutdown_event_loop_and_exit() somehow doesn't successfully exit the + * event loop, then this callback will kill Tor with an assertion failure + * seconds later + */ +static void +shutdown_did_not_work_callback(evutil_socket_t fd, short event, void *arg) +{ + // LCOV_EXCL_START + (void) fd; + (void) event; + (void) arg; + tor_assert_unreached(); + // LCOV_EXCL_STOP +} + +/** + * After finishing the current callback (if any), shut down the main loop, + * clean up the process, and exit with <b>exitcode</b>. + */ +void +tor_shutdown_event_loop_and_exit(int exitcode) +{ + if (main_loop_should_exit) + return; /* Ignore multiple calls to this function. */ + + main_loop_should_exit = 1; + main_loop_exit_value = exitcode; + + /* Die with an assertion failure in ten seconds, if for some reason we don't + * exit normally. */ + /* XXXX We should consider this code if it's never used. */ + struct timeval ten_seconds = { 10, 0 }; + event_base_once(tor_libevent_get_base(), -1, EV_TIMEOUT, + shutdown_did_not_work_callback, NULL, + &ten_seconds); + + /* Unlike loopexit, loopbreak prevents other callbacks from running. */ + tor_event_base_loopbreak(tor_libevent_get_base()); +} + +/** Return true iff tor_shutdown_event_loop_and_exit() has been called. */ +int +tor_event_loop_shutdown_is_pending(void) +{ + return main_loop_should_exit; +} + /** Helper: Tell the main loop to begin reading bytes into <b>conn</b> from * its linked connection, if it is not doing so already. Called by * connection_start_reading and connection_start_writing as appropriate. */ @@ -663,7 +729,7 @@ connection_start_reading_from_linked_conn(connection_t *conn) /* make sure that the event_base_loop() function exits at * the end of its run through the current connections, so we can * activate read events for linked connections. */ - tell_event_loop_to_finish(); + tell_event_loop_to_run_external_code(); } else { tor_assert(smartlist_contains(active_linked_connection_lst, conn)); } @@ -1405,7 +1471,9 @@ run_scheduled_events(time_t now) /* Maybe enough time elapsed for us to reconsider a circuit. */ circuit_upgrade_circuits_from_guard_wait(); - if (options->UseBridges && !options->DisableNetwork) { + if (options->UseBridges && !net_is_disabled()) { + /* Note: this check uses net_is_disabled(), not should_delay_dir_fetches() + * -- the latter is only for fetching consensus-derived directory info. */ fetch_bridge_descriptors(options, now); } @@ -1511,7 +1579,7 @@ rotate_onion_key_callback(time_t now, const or_options_t *options) if (router_rebuild_descriptor(1)<0) { log_info(LD_CONFIG, "Couldn't rebuild router descriptor"); } - if (advertised_server_mode() && !options->DisableNetwork) + if (advertised_server_mode() && !net_is_disabled()) router_upload_dir_desc_to_dirservers(0); return ONION_KEY_CONSENSUS_CHECK_INTERVAL; } @@ -1554,8 +1622,7 @@ check_ed_keys_callback(time_t now, const or_options_t *options) if (new_signing_key < 0 || generate_ed_link_cert(options, now, new_signing_key > 0)) { log_err(LD_OR, "Unable to update Ed25519 keys! Exiting."); - tor_cleanup(); - exit(1); + tor_shutdown_event_loop_and_exit(1); } } return 30; @@ -1877,9 +1944,11 @@ check_descriptor_callback(time_t now, const or_options_t *options) * address has changed. */ #define CHECK_DESCRIPTOR_INTERVAL (60) + (void)options; + /* 2b. Once per minute, regenerate and upload the descriptor if the old * one is inaccurate. */ - if (!options->DisableNetwork) { + if (!net_is_disabled()) { check_descriptor_bandwidth_changed(now); check_descriptor_ipaddress_changed(now); mark_my_descriptor_dirty_if_too_old(now); @@ -1911,7 +1980,7 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options) * 20 minutes of our uptime. */ if (server_mode(options) && (have_completed_a_circuit() || !any_predicted_circuits(now)) && - !we_are_hibernating()) { + !net_is_disabled()) { if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { consider_testing_reachability(1, dirport_reachability_count==0); if (++dirport_reachability_count > 5) @@ -2366,10 +2435,18 @@ do_hup(void) /* first, reload config variables, in case they've changed */ if (options->ReloadTorrcOnSIGHUP) { /* no need to provide argc/v, they've been cached in init_from_config */ - if (options_init_from_torrc(0, NULL) < 0) { + int init_rv = options_init_from_torrc(0, NULL); + if (init_rv < 0) { log_err(LD_CONFIG,"Reading config failed--see warnings above. " "For usage, try -h."); return -1; + } else if (BUG(init_rv > 0)) { + // LCOV_EXCL_START + /* This should be impossible: the only "return 1" cases in + * options_init_from_torrc are ones caused by command-line arguments; + * but they can't change while Tor is running. */ + return -1; + // LCOV_EXCL_STOP } options = get_options(); /* they have changed now */ /* Logs are only truncated the first time they are opened, but were @@ -2405,7 +2482,7 @@ do_hup(void) /* retry appropriate downloads */ router_reset_status_download_failures(); router_reset_descriptor_download_failures(); - if (!options->DisableNetwork) + if (!net_is_disabled()) update_networkstatus_downloads(time(NULL)); /* We'll retry routerstatus downloads in about 10 seconds; no need to @@ -2595,6 +2672,9 @@ do_main_loop(void) } #endif /* defined(HAVE_SYSTEMD) */ + main_loop_should_exit = 0; + main_loop_exit_value = 0; + return run_main_loop_until_done(); } @@ -2610,6 +2690,9 @@ run_main_loop_once(void) if (nt_service_is_stopping()) return 0; + if (main_loop_should_exit) + return 0; + #ifndef _WIN32 /* Make it easier to tell whether libevent failure is our fault or not. */ errno = 0; @@ -2656,6 +2739,9 @@ run_main_loop_once(void) } } + if (main_loop_should_exit) + return 0; + /* And here is where we put callbacks that happen "every time the event loop * runs." They must be very fast, or else the whole Tor process will get * slowed down. @@ -2684,7 +2770,11 @@ run_main_loop_until_done(void) do { loop_result = run_main_loop_once(); } while (loop_result == 1); - return loop_result; + + if (main_loop_should_exit) + return main_loop_exit_value; + else + return loop_result; } /** Libevent callback: invoked when we get a signal. @@ -2708,14 +2798,13 @@ process_signal(int sig) { case SIGTERM: log_notice(LD_GENERAL,"Catching signal TERM, exiting cleanly."); - tor_cleanup(); - exit(0); + tor_shutdown_event_loop_and_exit(0); break; case SIGINT: if (!server_mode(get_options())) { /* do it now */ log_notice(LD_GENERAL,"Interrupt: exiting cleanly."); - tor_cleanup(); - exit(0); + tor_shutdown_event_loop_and_exit(0); + return; } #ifdef HAVE_SYSTEMD sd_notify(0, "STOPPING=1"); @@ -2744,8 +2833,8 @@ process_signal(int sig) #endif if (do_hup() < 0) { log_warn(LD_CONFIG,"Restart failed (config error?). Exiting."); - tor_cleanup(); - exit(1); + tor_shutdown_event_loop_and_exit(1); + return; } #ifdef HAVE_SYSTEMD sd_notify(0, "READY=1"); @@ -3019,7 +3108,8 @@ activate_signal(int signal_num) } } -/** Main entry point for the Tor command-line client. +/** Main entry point for the Tor command-line client. Return 0 on "success", + * negative on "failure", and positive on "success and exit". */ int tor_init(int argc, char *argv[]) @@ -3111,14 +3201,13 @@ tor_init(int argc, char *argv[]) "Expect more bugs than usual."); } - { - rust_str_t rust_str = rust_welcome_string(); - const char *s = rust_str_get(rust_str); - if (strlen(s) > 0) { - log_notice(LD_GENERAL, "%s", s); - } - rust_str_free(rust_str); +#ifdef HAVE_RUST + char *rust_str = rust_welcome_string(); + if (rust_str != NULL && strlen(rust_str) > 0) { + log_notice(LD_GENERAL, "%s", rust_str); } + tor_free(rust_str); +#endif if (network_init()<0) { log_err(LD_BUG,"Error initializing network; exiting."); @@ -3126,9 +3215,14 @@ tor_init(int argc, char *argv[]) } atexit(exit_function); - if (options_init_from_torrc(argc,argv) < 0) { + int init_rv = options_init_from_torrc(argc,argv); + if (init_rv < 0) { log_err(LD_CONFIG,"Reading config failed--see warnings above."); return -1; + } else if (init_rv > 0) { + // We succeeded, and should exit anyway -- probably the user just said + // "--version" or something like that. + return 1; } /* The options are now initialised */ @@ -3198,7 +3292,7 @@ try_locking(const or_options_t *options, int err_if_locked) r = try_locking(options, 0); if (r<0) { log_err(LD_GENERAL, "No, it's still there. Exiting."); - exit(1); + return -1; } return r; } @@ -3521,6 +3615,10 @@ sandbox_init_filter(void) } } + SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, { + OPEN(f); + }); + #define RENAME_SUFFIX(name, suffix) \ sandbox_cfg_allow_rename(&cfg, \ get_datadir_fname(name suffix), \ @@ -3703,14 +3801,16 @@ sandbox_init_filter(void) return cfg; } -/** Main entry point for the Tor process. Called from main(). */ -/* This function is distinct from main() only so we can link main.c into - * the unittest binary without conflicting with the unittests' main. */ +/* Main entry point for the Tor process. Called from tor_main(), and by + * anybody embedding Tor. */ int -tor_main(int argc, char *argv[]) +tor_run_main(const tor_main_configuration_t *tor_cfg) { int result = 0; + int argc = tor_cfg->argc; + char **argv = tor_cfg->argv; + #ifdef _WIN32 #ifndef HeapEnableTerminationOnCorruption #define HeapEnableTerminationOnCorruption 1 @@ -3754,8 +3854,13 @@ tor_main(int argc, char *argv[]) if (done) return result; } #endif /* defined(NT_SERVICE) */ - if (tor_init(argc, argv)<0) - return -1; + { + int init_rv = tor_init(argc, argv); + if (init_rv < 0) + return -1; + else if (init_rv > 0) + return 0; + } if (get_options()->Sandbox && get_options()->command == CMD_RUN_TOR) { sandbox_cfg_t* cfg = sandbox_init_filter(); diff --git a/src/or/main.h b/src/or/main.h index 132ab12bbb..8eb977575e 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -45,7 +45,9 @@ int connection_is_writing(connection_t *conn); MOCK_DECL(void,connection_stop_writing,(connection_t *conn)); MOCK_DECL(void,connection_start_writing,(connection_t *conn)); -void tell_event_loop_to_finish(void); +void tell_event_loop_to_run_external_code(void); +void tor_shutdown_event_loop_and_exit(int exitcode); +int tor_event_loop_shutdown_is_pending(void); void connection_stop_reading_from_linked_conn(connection_t *conn); @@ -74,8 +76,6 @@ void release_lockfile(void); void tor_cleanup(void); void tor_free_all(int postfork); -int tor_main(int argc, char *argv[]); - int do_main_loop(void); int tor_init(int argc, char **argv); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index f31529733d..10d9b7542a 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -52,6 +52,7 @@ #include "dirserv.h" #include "dirvote.h" #include "entrynodes.h" +#include "hibernate.h" #include "main.h" #include "microdesc.h" #include "networkstatus.h" @@ -1208,6 +1209,14 @@ should_delay_dir_fetches(const or_options_t *options, const char **msg_out) return 1; } + if (we_are_hibernating()) { + if (msg_out) { + *msg_out = "We are hibernating or shutting down."; + } + log_info(LD_DIR, "Delaying dir fetches (Hibernating or shutting down)"); + return 1; + } + if (options->UseBridges) { if (!any_bridge_descriptors_known()) { if (msg_out) { @@ -1671,7 +1680,7 @@ handle_missing_protocol_warning_impl(const networkstatus_t *c, } tor_free(protocol_warning); if (should_exit) - exit(1); + exit(1); // XXXX bad exit: should return from main. } /** Called when we have received a networkstatus <b>c</b>. If there are @@ -1720,7 +1729,7 @@ networkstatus_set_current_consensus(const char *consensus, { networkstatus_t *c=NULL; int r, result = -1; - time_t now = time(NULL); + time_t now = approx_time(); const or_options_t *options = get_options(); char *unverified_fname = NULL, *consensus_fname = NULL; int flav = networkstatus_parse_flavor_name(flavor); diff --git a/src/or/nodelist.c b/src/or/nodelist.c index f2e979be8b..1ab385cd35 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -951,23 +951,29 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id) } /** Return true iff <b>node</b> supports authenticating itself - * by ed25519 ID during the link handshake in a way that we can understand - * when we probe it. */ + * 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) +node_supports_ed25519_link_authentication(const node_t *node, + int compatible_with_us) { - /* XXXX Oh hm. What if some day in the future there are link handshake - * versions that aren't 3 but which are ed25519 */ if (! node_get_ed25519_id(node)) return 0; if (node->ri) { const char *protos = node->ri->protocol_list; if (protos == NULL) return 0; - return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3); + if (compatible_with_us) + return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3); + else + return protocol_list_supports_protocol_or_later(protos, PRT_LINKAUTH, 3); } if (node->rs) { - return node->rs->supports_ed25519_link_handshake; + if (compatible_with_us) + return node->rs->supports_ed25519_link_handshake_compat; + else + return node->rs->supports_ed25519_link_handshake_any; } tor_assert_nonfatal_unreached_once(); return 0; @@ -1633,6 +1639,18 @@ node_has_curve25519_onion_key(const node_t *node) return 0; } +/** Return the curve25519 key of <b>node</b>, or NULL if none. */ +const curve25519_public_key_t * +node_get_curve25519_onion_key(const node_t *node) +{ + if (node->ri) + return node->ri->onion_curve25519_pkey; + else if (node->md) + return node->md->onion_curve25519_pkey; + else + return NULL; +} + /** Refresh the country code of <b>ri</b>. This function MUST be called on * each router when the GeoIP database is reloaded, and on all new routers. */ void diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 754990ac8d..e879b4e8ff 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -65,7 +65,8 @@ const smartlist_t *node_get_declared_family(const node_t *node); const ed25519_public_key_t *node_get_ed25519_id(const node_t *node); int node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id); -int node_supports_ed25519_link_authentication(const node_t *node); +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); @@ -85,6 +86,8 @@ int node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out); int node_has_curve25519_onion_key(const node_t *node); +const curve25519_public_key_t *node_get_curve25519_onion_key( + const node_t *node); MOCK_DECL(smartlist_t *, nodelist_get_list, (void)); diff --git a/src/or/ntmain.c b/src/or/ntmain.c index 508e5844eb..ebbe0018bd 100644 --- a/src/or/ntmain.c +++ b/src/or/ntmain.c @@ -195,7 +195,7 @@ nt_service_loadlibrary(void) return; err: printf("Unable to load library support for NT services: exiting.\n"); - exit(1); + exit(1); // exit ok: ntmain can't read libraries } /** If we're compiled to run as an NT service, and the service wants to @@ -318,7 +318,7 @@ nt_service_main(void) printf("Service error %d : %s\n", (int) result, errmsg); tor_free(errmsg); if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { - if (tor_init(backup_argc, backup_argv) < 0) + if (tor_init(backup_argc, backup_argv)) return; switch (get_options()->command) { case CMD_RUN_TOR: diff --git a/src/or/or.h b/src/or/or.h index 809714b5e2..fa5268ac59 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2234,18 +2234,18 @@ typedef struct { * uploaded it. */ #define ROUTER_PURPOSE_GENERAL 0 /** Tor should avoid using this router for circuit-building: we got it - * from a crontroller. If the controller wants to use it, it'll have to + * from a controller. If the controller wants to use it, it'll have to * ask for it by identity. */ #define ROUTER_PURPOSE_CONTROLLER 1 /** Tor should use this router only for bridge positions in circuits: we got * it via a directory request from the bridge itself, or a bridge - * authority. x*/ + * authority. */ #define ROUTER_PURPOSE_BRIDGE 2 /** Tor should not use this router; it was marked in cached-descriptors with * a purpose we didn't recognize. */ #define ROUTER_PURPOSE_UNKNOWN 255 - /* In what way did we find out about this router? One of ROUTER_PURPOSE_*. + /** In what way did we find out about this router? One of ROUTER_PURPOSE_*. * Routers of different purposes are kept segregated and used for different * things; see notes on ROUTER_PURPOSE_* macros above. */ @@ -2316,8 +2316,12 @@ typedef struct routerstatus_t { unsigned int supports_extend2_cells:1; /** True iff this router has a protocol list that allows it to negotiate - * ed25519 identity keys on a link handshake. */ - unsigned int supports_ed25519_link_handshake:1; + * ed25519 identity keys on a link handshake with us. */ + unsigned int supports_ed25519_link_handshake_compat:1; + + /** True iff this router has a protocol list that allows it to negotiate + * ed25519 identity keys on a link handshake, at all. */ + unsigned int supports_ed25519_link_handshake_any:1; /** True iff this router has a protocol list that allows it to be an * introduction point supporting ed25519 authentication key which is part of @@ -3674,6 +3678,7 @@ typedef struct { * interface addresses? * Includes OutboundBindAddresses and * configured ports. */ + int ReducedExitPolicy; /**<Should we use the Reduced Exit Policy? */ config_line_t *SocksPolicy; /**< Lists of socks policy components */ config_line_t *DirPolicy; /**< Lists of dir policy components */ /** Local address to bind outbound sockets */ @@ -4070,6 +4075,8 @@ typedef struct { /** Process specifier for a controller that ‘owns’ this Tor * instance. Tor will terminate if its owning controller does. */ char *OwningControllerProcess; + /** FD specifier for a controller that owns this Tor instance. */ + int OwningControllerFD; int ShutdownWaitLength; /**< When we get a SIGINT and we're a server, how * long do we wait before exiting? */ @@ -4627,6 +4634,9 @@ typedef struct { smartlist_t *Schedulers; /* An ordered list of scheduler_types mapped from Schedulers. */ smartlist_t *SchedulerTypes_; + + /** List of files that were opened by %include in torrc and torrc-defaults */ + smartlist_t *FilesOpenedByIncludes; } or_options_t; #define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level()) diff --git a/src/or/policies.c b/src/or/policies.c index 78451db8fc..1f80130710 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -81,7 +81,8 @@ static int policies_parse_exit_policy_internal( const smartlist_t *configured_addresses, int reject_interface_addresses, int reject_configured_port_addresses, - int add_default_policy); + int add_default_policy, + int add_reduced_policy); /** Replace all "private" entries in *<b>policy</b> with their expanded * equivalents. */ @@ -1144,7 +1145,7 @@ validate_addr_policies(const or_options_t *options, char **msg) "to 1 to disable this warning, and for forward compatibility.", options->ExitPolicy == NULL ? " with the default exit policy" : ""); - if (options->ExitPolicy == NULL) { + if (options->ExitPolicy == NULL && options->ReducedExitPolicy == 0) { log_warn(LD_CONFIG, "In a future version of Tor, ExitRelay 0 may become the " "default when no ExitPolicy is given."); @@ -1877,6 +1878,24 @@ policies_log_first_redundant_entry(const smartlist_t *policy) "reject *:563,reject *:1214,reject *:4661-4666," \ "reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*" +#define REDUCED_EXIT_POLICY \ + "accept *:20-23,accept *:43,accept *:53,accept *:79-81,accept *:88," \ + "accept *:110,accept *:143,accept *:194,accept *:220,accept *:389," \ + "accept *:443,accept *:464,accept *:465,accept *:531,accept *:543-544," \ + "accept *:554,accept *:563,accept *:587,accept *:636,accept *:706," \ + "accept *:749,accept *:873,accept *:902-904,accept *:981,accept *:989-995," \ + "accept *:1194,accept *:1220,accept *:1293,accept *:1500,accept *:1533," \ + "accept *:1677,accept *:1723,accept *:1755,accept *:1863," \ + "accept *:2082-2083,accept *:2086-2087,accept *:2095-2096," \ + "accept *:2102-2104,accept *:3128,accept *:3389,accept *:3690," \ + "accept *:4321,accept *:4643,accept *:5050,accept *:5190," \ + "accept *:5222-5223,accept *:5228,accept *:5900,accept *:6660-6669," \ + "accept *:6679,accept *:6697,accept *:8000,accept *:8008,accept *:8074," \ + "accept *:8080,accept *:8082,accept *:8087-8088,accept *:8232-8233," \ + "accept *:8332-8333,accept *:8443,accept *:8888,accept *:9418," \ + "accept *:9999,accept *:10000,accept *:11371,accept *:19294," \ + "accept *:19638,accept *:50002,accept *:64738,reject *:*" + /** Parse the exit policy <b>cfg</b> into the linked list *<b>dest</b>. * * If <b>ipv6_exit</b> is false, prepend "reject *6:*" to the policy. @@ -1912,7 +1931,8 @@ policies_parse_exit_policy_internal(config_line_t *cfg, const smartlist_t *configured_addresses, int reject_interface_addresses, int reject_configured_port_addresses, - int add_default_policy) + int add_default_policy, + int add_reduced_policy) { if (!ipv6_exit) { append_exit_policy_string(dest, "reject *6:*"); @@ -1938,7 +1958,9 @@ policies_parse_exit_policy_internal(config_line_t *cfg, * effect, and are most likely an error. */ policies_log_first_redundant_entry(*dest); - if (add_default_policy) { + if (add_reduced_policy) { + append_exit_policy_string(dest, REDUCED_EXIT_POLICY); + } else if (add_default_policy) { append_exit_policy_string(dest, DEFAULT_EXIT_POLICY); } else { append_exit_policy_string(dest, "reject *4:*"); @@ -1979,13 +2001,15 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, int add_default = (options & EXIT_POLICY_ADD_DEFAULT) ? 1 : 0; int reject_local_interfaces = (options & EXIT_POLICY_REJECT_LOCAL_INTERFACES) ? 1 : 0; + int add_reduced = (options & EXIT_POLICY_ADD_REDUCED) ? 1 : 0; return policies_parse_exit_policy_internal(cfg,dest,ipv6_enabled, reject_private, configured_addresses, reject_local_interfaces, reject_local_interfaces, - add_default); + add_default, + add_reduced); } /** Helper function that adds a copy of addr to a smartlist as long as it is @@ -2095,7 +2119,10 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options, } if (!or_options->BridgeRelay) { - parser_cfg |= EXIT_POLICY_ADD_DEFAULT; + if (or_options->ReducedExitPolicy) + parser_cfg |= EXIT_POLICY_ADD_REDUCED; + else + parser_cfg |= EXIT_POLICY_ADD_DEFAULT; } if (or_options->ExitPolicyRejectLocalInterfaces) { diff --git a/src/or/policies.h b/src/or/policies.h index 52ff4e2f99..cd97ee7f59 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -22,7 +22,8 @@ #define EXIT_POLICY_REJECT_PRIVATE (1 << 1) #define EXIT_POLICY_ADD_DEFAULT (1 << 2) #define EXIT_POLICY_REJECT_LOCAL_INTERFACES (1 << 3) -#define EXIT_POLICY_OPTION_MAX EXIT_POLICY_REJECT_LOCAL_INTERFACES +#define EXIT_POLICY_ADD_REDUCED (1 << 4) +#define EXIT_POLICY_OPTION_MAX EXIT_POLICY_ADD_REDUCED /* All options set: used for unit testing */ #define EXIT_POLICY_OPTION_ALL ((EXIT_POLICY_OPTION_MAX << 1) - 1) diff --git a/src/or/protover.c b/src/or/protover.c index 1a3e69be10..ae955296e6 100644 --- a/src/or/protover.c +++ b/src/or/protover.c @@ -27,11 +27,14 @@ #include "protover.h" #include "routerparse.h" +#ifndef HAVE_RUST + static const smartlist_t *get_supported_protocol_list(void); static int protocol_list_contains(const smartlist_t *protos, protocol_type_t pr, uint32_t ver); /** Mapping between protocol type string and protocol type. */ +/// C_RUST_COUPLED: src/rust/protover/protover.rs `PROTOCOL_NAMES` static const struct { protocol_type_t protover_type; const char *name; @@ -280,8 +283,45 @@ protocol_list_supports_protocol(const char *list, protocol_type_t tp, return contains; } +/** + * Return true iff "list" encodes a protocol list that includes support for + * the indicated protocol and version, or some later version. + */ +int +protocol_list_supports_protocol_or_later(const char *list, + protocol_type_t tp, + uint32_t version) +{ + /* NOTE: This is a pretty inefficient implementation. If it ever shows + * up in profiles, we should memoize it. + */ + smartlist_t *protocols = parse_protocol_list(list); + if (!protocols) { + return 0; + } + const char *pr_name = protocol_type_to_str(tp); + + int contains = 0; + SMARTLIST_FOREACH_BEGIN(protocols, proto_entry_t *, proto) { + if (strcasecmp(proto->name, pr_name)) + continue; + SMARTLIST_FOREACH_BEGIN(proto->ranges, const proto_range_t *, range) { + if (range->high >= version) { + contains = 1; + goto found; + } + } SMARTLIST_FOREACH_END(range); + } SMARTLIST_FOREACH_END(proto); + + found: + SMARTLIST_FOREACH(protocols, proto_entry_t *, ent, proto_entry_free(ent)); + smartlist_free(protocols); + return contains; +} + /** Return the canonical string containing the list of protocols * that we support. */ +/// C_RUST_COUPLED: src/rust/protover/protover.rs `SUPPORTED_PROTOCOLS` const char * protover_get_supported_protocols(void) { @@ -365,6 +405,8 @@ encode_protocol_list(const smartlist_t *sl) /* We treat any protocol list with more than this many subprotocols in it * as a DoS attempt. */ +/// C_RUST_COUPLED: src/rust/protover/protover.rs +/// `MAX_PROTOCOLS_TO_EXPAND` static const int MAX_PROTOCOLS_TO_EXPAND = (1<<16); /** Voting helper: Given a list of proto_entry_t, return a newly allocated @@ -691,6 +733,7 @@ protocol_list_contains(const smartlist_t *protos, * Note that this is only used to infer protocols for Tor versions that * can't declare their own. **/ +/// C_RUST_COUPLED: src/rust/protover/protover.rs `compute_for_old_tor` const char * protover_compute_for_old_tor(const char *version) { @@ -735,3 +778,5 @@ protover_free_all(void) } } +#endif + diff --git a/src/or/protover.h b/src/or/protover.h index 657977279e..a4dbc8bfc2 100644 --- a/src/or/protover.h +++ b/src/or/protover.h @@ -15,6 +15,8 @@ * descriptors. Authorities should use this to decide whether to * guess proto lines. */ /* This is a guess. */ +/// C_RUST_COUPLED: src/rust/protover/protover.rs +/// `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS` #define FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS "0.2.9.3-alpha" /** The protover version number that signifies HSDir support for HSv3 */ @@ -25,6 +27,8 @@ #define PROTOVER_HS_RENDEZVOUS_POINT_V3 2 /** List of recognized subprotocols. */ +/// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust` +/// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto` typedef enum protocol_type_t { PRT_LINK, PRT_LINKAUTH, @@ -47,6 +51,9 @@ char *protover_compute_vote(const smartlist_t *list_of_proto_strings, const char *protover_compute_for_old_tor(const char *version); int protocol_list_supports_protocol(const char *list, protocol_type_t tp, uint32_t version); +int protocol_list_supports_protocol_or_later(const char *list, + protocol_type_t tp, + uint32_t version); void protover_free_all(void); @@ -70,11 +77,15 @@ typedef struct proto_entry_t { smartlist_t *ranges; } proto_entry_t; +#if !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) STATIC smartlist_t *parse_protocol_list(const char *s); -STATIC void proto_entry_free(proto_entry_t *entry); STATIC char *encode_protocol_list(const smartlist_t *sl); STATIC const char *protocol_type_to_str(protocol_type_t pr); STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out); +STATIC void proto_entry_free(proto_entry_t *entry); + +#endif + #endif /* defined(PROTOVER_PRIVATE) */ #endif /* !defined(TOR_PROTOVER_H) */ diff --git a/src/or/protover_rust.c b/src/or/protover_rust.c new file mode 100644 index 0000000000..0c409b1681 --- /dev/null +++ b/src/or/protover_rust.c @@ -0,0 +1,19 @@ +/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* + * \file protover_rust.c + * \brief Provide a C wrapper for functions exposed in /src/rust/protover, + * and safe translation/handling between the Rust/C boundary. + */ + +#include "or.h" +#include "protover.h" + +#ifdef HAVE_RUST + +/* Define for compatibility, used in main.c */ +void protover_free_all(void) {} + +#endif + diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 355f8e0fa0..fb8225e0d6 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -3096,7 +3096,7 @@ signed_descriptor_get_body_impl(const signed_descriptor_t *desc, log_err(LD_DIR, "We couldn't read a descriptor that is supposedly " "mmaped in our cache. Is another process running in our data " "directory? Exiting."); - exit(1); + exit(1); // XXXX bad exit: should recover. } } if (!r) /* no mmap, or not in cache. */ @@ -3110,7 +3110,7 @@ signed_descriptor_get_body_impl(const signed_descriptor_t *desc, log_err(LD_DIR, "descriptor at %p begins with unexpected string %s. " "Is another process running in our data directory? Exiting.", desc, escaped(cp)); - exit(1); + exit(1); // XXXX bad exit: should recover. } } @@ -4545,7 +4545,7 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc) void update_all_descriptor_downloads(time_t now) { - if (get_options()->DisableNetwork) + if (should_delay_dir_fetches(get_options(), NULL)) return; update_router_descriptor_downloads(now); update_microdesc_downloads(now); @@ -5377,8 +5377,10 @@ update_extrainfo_downloads(time_t now) smartlist_free(wanted); } -/** Reset the descriptor download failure count on all routers, so that we - * can retry any long-failed routers immediately. +/** Reset the consensus and extra-info download failure count on all routers. + * When we get a new consensus, + * routers_update_status_from_consensus_networkstatus() will reset the + * download statuses on the descriptors in that consensus. */ void router_reset_descriptor_download_failures(void) @@ -5390,6 +5392,8 @@ router_reset_descriptor_download_failures(void) last_descriptor_download_attempted = 0; if (!routerlist) return; + /* We want to download *all* extra-info descriptors, not just those in + * the consensus we currently have (or are about to have) */ SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri, { download_status_reset(&ri->cache_info.ei_dl_status); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 15cdb0bbde..f1895ce313 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -2701,8 +2701,10 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->protocols_known = 1; rs->supports_extend2_cells = protocol_list_supports_protocol(tok->args[0], PRT_RELAY, 2); - rs->supports_ed25519_link_handshake = + rs->supports_ed25519_link_handshake_compat = protocol_list_supports_protocol(tok->args[0], PRT_LINKAUTH, 3); + rs->supports_ed25519_link_handshake_any = + protocol_list_supports_protocol_or_later(tok->args[0], PRT_LINKAUTH, 3); rs->supports_ed25519_hs_intro = protocol_list_supports_protocol(tok->args[0], PRT_HSINTRO, 4); rs->supports_v3_hsdir = @@ -4027,7 +4029,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, /** Return the common_digests_t that holds the digests of the * <b>flavor_name</b>-flavored networkstatus according to the detached * signatures document <b>sigs</b>, allocating a new common_digests_t as - * neeeded. */ + * needed. */ static common_digests_t * detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name) { @@ -4041,7 +4043,7 @@ detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name) /** Return the list of signatures of the <b>flavor_name</b>-flavored * networkstatus according to the detached signatures document <b>sigs</b>, - * allocating a new common_digests_t as neeeded. */ + * allocating a new common_digests_t as needed. */ static smartlist_t * detached_get_signatures(ns_detached_signatures_t *sigs, const char *flavor_name) diff --git a/src/or/scheduler.c b/src/or/scheduler.c index cbf51447bf..cd047d5a75 100644 --- a/src/or/scheduler.c +++ b/src/or/scheduler.c @@ -305,7 +305,7 @@ select_scheduler(void) * wishes of using what it has been configured and don't do a sneaky * fallback. Because this can be changed at runtime, we have to stop tor * right now. */ - exit(1); + exit(1); // XXXX bad exit } /* Set the chosen scheduler. */ diff --git a/src/or/tor_api.c b/src/or/tor_api.c new file mode 100644 index 0000000000..4260cc88f4 --- /dev/null +++ b/src/or/tor_api.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file tor_api.c + **/ + +#include "tor_api.h" +#include "tor_api_internal.h" + +// Include this after the above headers, to insure that they don't +// depend on anything else. +#include "orconfig.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// We don't want to use tor_malloc and tor_free here, since this needs +// to run before anything is initialized at all, and ought to run when +// we're not linked to anything at all. + +#define raw_malloc malloc +#define raw_free free + +tor_main_configuration_t * +tor_main_configuration_new(void) +{ + static const char *fake_argv[] = { "tor" }; + tor_main_configuration_t *cfg = raw_malloc(sizeof(*cfg)); + if (cfg == NULL) + return NULL; + + memset(cfg, 0, sizeof(*cfg)); + + cfg->argc = 1; + cfg->argv = (char **) fake_argv; + + return cfg; +} + +int +tor_main_configuration_set_command_line(tor_main_configuration_t *cfg, + int argc, char *argv[]) +{ + if (cfg == NULL) + return -1; + cfg->argc = argc; + cfg->argv = argv; + return 0; +} + +void +tor_main_configuration_free(tor_main_configuration_t *cfg) +{ + if (cfg == NULL) + return; + raw_free(cfg); +} + +/* Main entry point for the Tor process. Called from main(). + * + * This function is distinct from main() only so we can link main.c into + * the unittest binary without conflicting with the unittests' main. + * + * Some embedders have historically called this function; but that usage is + * deprecated: they should use tor_run_main() instead. + */ +int +tor_main(int argc, char *argv[]) +{ + tor_main_configuration_t *cfg = tor_main_configuration_new(); + if (!cfg) { + puts("INTERNAL ERROR: Allocation failure. Cannot proceed"); + return 1; + } + if (tor_main_configuration_set_command_line(cfg, argc, argv) < 0) { + puts("INTERNAL ERROR: Can't set command line. Cannot proceed."); + return 1; + } + int rv = tor_run_main(cfg); + tor_main_configuration_free(cfg); + return rv; +} + diff --git a/src/or/tor_api.h b/src/or/tor_api.h new file mode 100644 index 0000000000..b12ed718c1 --- /dev/null +++ b/src/or/tor_api.h @@ -0,0 +1,102 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file tor_api.h + * \brief Public C API for the Tor network service. + * + * This interface is intended for use by programs that need to link Tor as + * a library, and launch it in a separate thread. If you have the ability + * to run Tor as a separate executable, you should probably do that instead + * of embedding it as a library. + * + * To use this API, first construct a tor_main_configuration_t object using + * tor_main_configuration_new(). Then, you use one or more other function + * calls (such as tor_main_configuration_set_command_line() to configure how + * Tor should be run. Finally, you pass the configuration object to + * tor_run_main(). + * + * At this point, tor_run_main() will block its thread to run a Tor daemon; + * when the Tor daemon exits, it will return. See notes on bugs and + * limitations below. + * + * There is no other public C API to Tor: calling any C Tor function not + * documented in this file is not guaranteed to be stable. + **/ + +#ifndef TOR_API_H +#define TOR_API_H + +typedef struct tor_main_configuration_t tor_main_configuration_t; + +/** + * Create and return a new tor_main_configuration(). + */ +tor_main_configuration_t *tor_main_configuration_new(void); + +/** + * Set the command-line arguments in <b>cfg</b>. + * + * The <b>argc</b> and <b>argv</b> values here are as for main(). The + * contents of the argv pointer must remain unchanged until tor_run_main() has + * finished and you call tor_main_configuration_free(). + * + * Return 0 on success, -1 on failure. + */ +int tor_main_configuration_set_command_line(tor_main_configuration_t *cfg, + int argc, char *argv[]); + +/** + * Release all storage held in <b>cfg</b>. + * + * Once you have passed a tor_main_configuration_t to tor_run_main(), you + * must not free it until tor_run_main() has finished. + */ +void tor_main_configuration_free(tor_main_configuration_t *cfg); + +/** + * Run the tor process, as if from the command line. + * + * The command line arguments from tor_main_configuration_set_command_line() + * are taken as if they had been passed to main(). + * + * This function will not return until Tor is done running. It returns zero + * on success, and nonzero on failure. + * + * BUG 23848: In many cases, tor_main will call exit() or abort() instead of + * returning. This is not the intended long-term behavior; we are trying to + * fix it. + * + * BUG 23847: You can only call tor_main() once in a single process; if it + * returns and you call it again, you may crash. This is not intended + * long-term behavior; we are trying to fix it. + * + * LIMITATION: You cannot run more than one instance of Tor in the same + * process at the same time. Concurrent calls will cause undefined behavior. + * We do not currently have plans to change this. + * + * LIMITATION: While we will try to fix any problems found here, you + * should be aware that Tor was originally written to run as its own + * process, and that the functionality of this file was added later. If + * you find any bugs or strange behavior, please report them, and we'll + * try to straighten them out. + */ +int tor_run_main(const tor_main_configuration_t *); + +/** + * Run the tor process, as if from the command line. + * + * @deprecated Using this function from outside Tor is deprecated; you should + * use tor_run_main() instead. + * + * BUGS: This function has all the same bugs as tor_run_main(). + * + * LIMITATIONS: This function has all the limitations of tor_run_main(). + */ +int tor_main(int argc, char **argv); + +#endif /* !defined(TOR_API_H) */ + diff --git a/src/or/tor_api_internal.h b/src/or/tor_api_internal.h new file mode 100644 index 0000000000..a69ba76420 --- /dev/null +++ b/src/or/tor_api_internal.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_API_INTERNAL_H +#define TOR_API_INTERNAL_H + +/* The contents of this type are private; don't mess with them from outside + * Tor. */ +struct tor_main_configuration_t { + /** As in main() */ + int argc; + /** As in main(). This pointer is owned by the caller */ + char **argv; +}; + +#endif + diff --git a/src/or/tor_main.c b/src/or/tor_main.c index a3a8838602..c203d8248f 100644 --- a/src/or/tor_main.c +++ b/src/or/tor_main.c @@ -3,18 +3,6 @@ * Copyright (c) 2007-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -extern const char tor_git_revision[]; - -/** String describing which Tor Git repository version the source was - * built from. This string is generated by a bit of shell kludging in - * src/or/include.am, and is usually right. - */ -const char tor_git_revision[] = -#ifndef _MSC_VER -#include "micro-revision.i" -#endif - ""; - /** * \file tor_main.c * \brief Stub module containing a main() function. @@ -26,7 +14,7 @@ const char tor_git_revision[] = int tor_main(int argc, char *argv[]); /** We keep main() in a separate file so that our unit tests can use - * functions from main.c) + * functions from main.c. */ int main(int argc, char *argv[]) |