aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/feature30763
-rw-r--r--doc/tor.1.txt5
-rw-r--r--src/or/config.c1
-rw-r--r--src/or/connection.c3
-rw-r--r--src/or/control.c39
-rw-r--r--src/or/control.h2
-rw-r--r--src/or/main.c6
-rw-r--r--src/or/or.h3
8 files changed, 60 insertions, 2 deletions
diff --git a/changes/feature3076 b/changes/feature3076
index aadd29627..ed42e4595 100644
--- a/changes/feature3076
+++ b/changes/feature3076
@@ -6,3 +6,6 @@
and ports that are bound for listeners for a given connection
type. This is useful for if the user has selected SocksPort
"auto", and you need to know which port got chosen.
+ - There is a ControlPortWriteToFile option that tells Tor to write
+ its actual control port or ports to a chosen file.
+
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index e48342e16..606580db5 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -191,6 +191,11 @@ Other options can be specified either on the command-line (--option
the default GID. [Making the file readable by other groups is not yet
implemented; let us know if you need this for some reason.] (Default: 0).
+**ControlPortWriteToFile** __Path__::
+ If set, Tor writes the address and port of any control port it opens to
+ this address. Usable by controllers to learn the actual control port
+ when ControlPort is set to "auto".
+
**DataDirectory** __DIR__::
Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor)
diff --git a/src/or/config.c b/src/or/config.c
index b06c8c95c..5eb62291b 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -206,6 +206,7 @@ static config_var_t _option_vars[] = {
V(ContactInfo, STRING, NULL),
V(ControlListenAddress, LINELIST, NULL),
V(ControlPort, PORT, "0"),
+ V(ControlPortWriteToFile, FILENAME, NULL),
V(ControlSocket, LINELIST, NULL),
V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"),
diff --git a/src/or/connection.c b/src/or/connection.c
index bc18dab1e..01b533d9b 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -998,6 +998,9 @@ connection_create_listener(const struct sockaddr *listensockaddr,
"%s listening on port %u.",
conn_type_to_string(type), gotPort);
+ if (type == CONN_TYPE_CONTROL_LISTENER)
+ control_ports_write_to_file();
+
conn->state = LISTENER_STATE_READY;
if (start_reading) {
connection_start_reading(conn);
diff --git a/src/or/control.c b/src/or/control.c
index 19e8539a2..634674233 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -508,6 +508,45 @@ connection_printf_to_buf(control_connection_t *conn, const char *format, ...)
connection_write_to_buf(buf, len, TO_CONN(conn));
}
+/** Write all of the open control ports to ControlPortWriteToFile */
+void
+control_ports_write_to_file(void)
+{
+ smartlist_t *lines;
+ char *joined = NULL;
+ or_options_t *options = get_options();
+
+ if (!options->ControlPortWriteToFile)
+ return;
+
+ lines = smartlist_create();
+
+ SMARTLIST_FOREACH_BEGIN(get_connection_array(), const connection_t *, conn) {
+ char *port_str = NULL;
+ if (conn->type != CONN_TYPE_CONTROL_LISTENER || conn->marked_for_close)
+ continue;
+#ifdef AF_UNIX
+ if (conn->socket_family == AF_UNIX) {
+ tor_asprintf(&port_str, "UNIX_PORT=%s\n", conn->address);
+ smartlist_add(lines, port_str);
+ continue;
+ }
+#endif
+ tor_asprintf(&port_str, "PORT=%s:%d\n", conn->address, conn->port);
+ smartlist_add(lines, port_str);
+ } SMARTLIST_FOREACH_END(conn);
+
+ joined = smartlist_join_strings(lines, "", 0, NULL);
+
+ if (write_str_to_file(options->ControlPortWriteToFile, joined, 0) < 0) {
+ log_warn(LD_CONTROL, "Writing %s failed: %s",
+ options->ControlPortWriteToFile, strerror(errno));
+ }
+ tor_free(joined);
+ SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
+ smartlist_free(lines);
+}
+
/** Send a "DONE" message down the control connection <b>conn</b>. */
static void
send_control_done(control_connection_t *conn)
diff --git a/src/or/control.h b/src/or/control.h
index 2ae96b4b8..a73ed5d3c 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -15,6 +15,8 @@
void control_update_global_event_mask(void);
void control_adjust_event_log_severity(void);
+void control_ports_write_to_file(void);
+
/** Log information about the connection <b>conn</b>, protecting it as with
* CONN_LOG_PROTECT. Example:
*
diff --git a/src/or/main.c b/src/or/main.c
index 7bae59ce0..15682d540 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -2046,12 +2046,14 @@ void
tor_cleanup(void)
{
or_options_t *options = get_options();
- /* Remove our pid file. We don't care if there was an error when we
- * unlink, nothing we could do about it anyways. */
if (options->command == CMD_RUN_TOR) {
time_t now = time(NULL);
+ /* Remove our pid file. We don't care if there was an error when we
+ * unlink, nothing we could do about it anyways. */
if (options->PidFile)
unlink(options->PidFile);
+ if (options->ControlPortWriteToFile)
+ unlink(options->ControlPortWriteToFile);
if (accounting_is_enabled(options))
accounting_record_bandwidth_usage(now, get_or_state());
or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */
diff --git a/src/or/or.h b/src/or/or.h
index 0a089f774..412aac982 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2874,6 +2874,9 @@ typedef struct {
* the defaults have changed. */
int _UsingTestNetworkDefaults;
+ /** File where we should write the ControlPort. */
+ char *ControlPortWriteToFile;
+
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */