Browse Source

Merge remote-tracking branch 'public/owning_control_fd'

Nick Mathewson 6 years ago
parent
commit
cd606d5ad3
9 changed files with 103 additions and 10 deletions
  1. 7 0
      changes/ticket23900
  2. 14 6
      src/common/compat.c
  3. 1 0
      src/common/compat.h
  4. 25 0
      src/or/config.c
  5. 5 3
      src/or/connection.c
  6. 2 1
      src/or/connection.h
  7. 43 0
      src/or/control.c
  8. 4 0
      src/or/control.h
  9. 2 0
      src/or/or.h

+ 7 - 0
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.

+ 14 - 6
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) */
 /** @} */
 
@@ -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
+ * <b>s</b>. This will prevent us from overallocating sockets, and prevent us
+ * from asserting later when we close the socket <b>s</b>.
+ */
+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;
 }
 

+ 1 - 0
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);

+ 25 - 0
src/or/config.c

@@ -565,6 +565,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"),
@@ -1773,6 +1774,24 @@ options_act(const or_options_t *old_options)
     // 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 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())
@@ -4634,6 +4653,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 {                                                                \

+ 5 - 3
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 <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)
 {

+ 2 - 1
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);

+ 43 - 0
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

+ 4 - 0
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);

+ 2 - 0
src/or/or.h

@@ -4071,6 +4071,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? */