commit f1bf9bf8198fcfaf078fdc12eb2ad5adf1901d29 Author: Nick Mathewson nickm@torproject.org Date: Wed Oct 18 13:36:53 2017 -0400
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(+)
diff --git a/changes/ticket23900 b/changes/ticket23900 new file mode 100644 index 000000000..0f949f4f4 --- /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 832a7c967..acc31c011 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 8173cb1e5..2e4bae2db 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 diff --git a/src/or/control.h b/src/or/control.h index e957b593a..7ec182cb7 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 5bd07ba6a..048dbc591 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? */