From 5bcd8dc5c482da4da71402cd06b0ecc709f05493 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 18 Oct 2017 12:13:26 -0400 Subject: [PATCH 1/4] Make the mark_socket_open() no-op treat the socket as used. This is preliminary for extracting the "take socket ownership" code into its own function. --- src/common/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/compat.c b/src/common/compat.c index 7fe97488e3..97eab94e04 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -1186,7 +1186,7 @@ mark_socket_open(tor_socket_t s) bitarray_set(open_sockets, s); } #else /* !(defined(DEBUG_SOCKET_COUNTING)) */ -#define mark_socket_open(s) STMT_NIL +#define mark_socket_open(s) ((void) (s)) #endif /* defined(DEBUG_SOCKET_COUNTING) */ /** @} */ From 4eb5753bd29b24fd5a523499add35a6214293cd9 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 18 Oct 2017 12:14:30 -0400 Subject: [PATCH 2/4] New function for Tor to treat itself as the "owner" of a socket Our socket accounting functions assumed that we'd never be asked to close a socket that we didn't open ourselves. But now we want to support taking control sockets that we inherit -- so we need a way of taking ownership of them, so we don't freak out later on when we close them. --- src/common/compat.c | 18 +++++++++++++----- src/common/compat.h | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/common/compat.c b/src/common/compat.c index 97eab94e04..38693b21fe 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -1273,11 +1273,22 @@ tor_open_socket_with_extensions(int domain, int type, int protocol, goto socket_ok; /* So that socket_ok will not be unused. */ socket_ok: + tor_take_socket_ownership(s); + return s; +} + +/** + * For socket accounting: remember that we are the owner of the socket + * s. This will prevent us from overallocating sockets, and prevent us + * from asserting later when we close the socket s. + */ +void +tor_take_socket_ownership(tor_socket_t s) +{ socket_accounting_lock(); ++n_sockets_open; mark_socket_open(s); socket_accounting_unlock(); - return s; } /** As accept(), but counts the number of open sockets. */ @@ -1358,10 +1369,7 @@ tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr, goto socket_ok; /* So that socket_ok will not be unused. */ socket_ok: - socket_accounting_lock(); - ++n_sockets_open; - mark_socket_open(s); - socket_accounting_unlock(); + tor_take_socket_ownership(s); return s; } diff --git a/src/common/compat.h b/src/common/compat.h index fee9e6587d..0aabee68c8 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -483,6 +483,7 @@ typedef int socklen_t; int tor_close_socket_simple(tor_socket_t s); MOCK_DECL(int, tor_close_socket, (tor_socket_t s)); +void tor_take_socket_ownership(tor_socket_t s); tor_socket_t tor_open_socket_with_extensions( int domain, int type, int protocol, int cloexec, int nonblock); From f0daaf8d60be8bfcfaa99e3a878cd90967a84bb0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 18 Oct 2017 12:55:09 -0400 Subject: [PATCH 3/4] Expose connection_init_accepted_conn. --- src/or/connection.c | 8 +++++--- src/or/connection.h | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/or/connection.c b/src/or/connection.c index 632a833652..431ab3a3a0 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); @@ -1662,11 +1660,15 @@ connection_handle_listener_read(connection_t *conn, int new_type) } /** Initialize states for newly accepted connection conn. + * * 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 listener parameter is only used for AP connections. */ -static int +int connection_init_accepted_conn(connection_t *conn, const listener_connection_t *listener) { diff --git a/src/or/connection.h b/src/or/connection.h index 4a5bd6971b..7f488676ed 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); From f1bf9bf8198fcfaf078fdc12eb2ad5adf1901d29 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 18 Oct 2017 13:36:53 -0400 Subject: [PATCH 4/4] Add __OwningControllerFD to allow controllers without controlports This feature should help programs that want to launch and manage a Tor process, as well as programs that want to launch and manage a Tor instance in a separate thread. Right now, they have to open a controlport, and then connect to it, with attendant authentication issues. This feature allows them to just start with an authenticated connection. Bug 23900. --- changes/ticket23900 | 7 +++++++ src/or/config.c | 25 +++++++++++++++++++++++++ src/or/control.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/or/control.h | 4 ++++ src/or/or.h | 2 ++ 5 files changed, 81 insertions(+) create mode 100644 changes/ticket23900 diff --git a/changes/ticket23900 b/changes/ticket23900 new file mode 100644 index 0000000000..0f949f4f4e --- /dev/null +++ b/changes/ticket23900 @@ -0,0 +1,7 @@ + o Minor features (API, embedding): + - Tor can now start with a preauthenticated control connection + created by the process that launched it. This feature is meant + for use by programs that want to launch and manage a Tor process + without allowing other programs to manage it as well. + For more information, see the __OwningControllerFD option + documented in control-spec.txt. Closes ticket 23900. diff --git a/src/or/config.c b/src/or/config.c index 832a7c9674..acc31c0111 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -562,6 +562,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"), @@ -1730,6 +1731,24 @@ options_act(const or_options_t *old_options) return -1; } + if (running_tor && !old_options && options->OwningControllerFD != -1) { +#ifdef _WIN32 + log_warn(LD_CONFIG, "OwningControllerFD is not supported on Windows. " + "If you neeed 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 */ if (! or_state_loaded() && running_tor) { if (or_state_load()) @@ -4572,6 +4591,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 { \ diff --git a/src/or/control.c b/src/or/control.c index 8173cb1e56..2e4bae2dbf 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 sock. If + * CC_LOCAL_FD_IS_OWNER is set in flags, this Tor process should + * exit when the connection closes. If CC_LOCAL_FD_IS_AUTHENTICATED + * 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(""); + + /* 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 * conn-\>outbuf. */ static void 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/or.h b/src/or/or.h index 5bd07ba6a3..048dbc591c 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -4066,6 +4066,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? */