summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/addressmap.c3
-rw-r--r--src/or/circuitbuild.c4
-rw-r--r--src/or/config.c140
-rw-r--r--src/or/connection.c144
-rw-r--r--src/or/connection.h5
-rw-r--r--src/or/connection_edge.c2
-rw-r--r--src/or/connection_or.c2
-rw-r--r--src/or/control.c46
-rw-r--r--src/or/control.h4
-rw-r--r--src/or/directory.c48
-rw-r--r--src/or/directory.h3
-rw-r--r--src/or/dirserv.c16
-rw-r--r--src/or/dns.c4
-rw-r--r--src/or/entrynodes.c6
-rw-r--r--src/or/entrynodes.h4
-rw-r--r--src/or/geoip.c22
-rw-r--r--src/or/git_revision.c17
-rw-r--r--src/or/git_revision.h12
-rw-r--r--src/or/hibernate.c21
-rw-r--r--src/or/hs_circuit.c92
-rw-r--r--src/or/hs_service.c2
-rw-r--r--src/or/include.am12
-rw-r--r--src/or/main.c175
-rw-r--r--src/or/main.h6
-rw-r--r--src/or/networkstatus.c13
-rw-r--r--src/or/nodelist.c32
-rw-r--r--src/or/nodelist.h5
-rw-r--r--src/or/ntmain.c4
-rw-r--r--src/or/or.h20
-rw-r--r--src/or/policies.c39
-rw-r--r--src/or/policies.h3
-rw-r--r--src/or/protover.c45
-rw-r--r--src/or/protover.h13
-rw-r--r--src/or/protover_rust.c19
-rw-r--r--src/or/routerlist.c14
-rw-r--r--src/or/routerparse.c8
-rw-r--r--src/or/scheduler.c2
-rw-r--r--src/or/tor_api.c88
-rw-r--r--src/or/tor_api.h102
-rw-r--r--src/or/tor_api_internal.h20
-rw-r--r--src/or/tor_main.c14
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[])