commit d93a131b550554230456c3b466aa4eb3ea65d2d6
parent 1a6a8e4da9d75a1af0935707630393cc9aee3102
Author: David Goulet <dgoulet@torproject.org>
Date: Tue, 11 Nov 2025 19:41:49 +0000
Merge branch 'prop368_minimal' into 'main'
Implement prop368: Expire circuits based on time of last use.
Closes #41157
See merge request tpo/core/tor!948
Diffstat:
2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/changes/ticket41157 b/changes/ticket41157
@@ -0,0 +1,6 @@
+ o Minor features (security, reliability):
+ - When KeepaliveIsolateSOCKSAuth is keeping a circuit alive,
+ expire the circuit based on when it was last in use for any stream,
+ not (as we did before) based on when a stream was last attached to it.
+ Closes ticket 41157. Implements a minimal version of
+ Proposal 368.
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
@@ -79,6 +79,8 @@
STATIC void circuit_expire_old_circuits_clientside(void);
static void circuit_increment_failure_count(void);
+static bool connection_ap_socks_iso_keepalive_enabled(
+ const entry_connection_t *);
/** Check whether the hidden service destination of the stream at
* <b>edge_conn</b> is the same as the destination of the circuit at
@@ -1357,6 +1359,7 @@ void
circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
{
edge_connection_t *prevconn;
+ bool update_dirty = false;
tor_assert(circ);
tor_assert(conn);
@@ -1364,6 +1367,9 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
if (conn->base_.type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
entry_conn->may_use_optimistic_data = 0;
+ // When KeepAliveIsolateSOCKSAuth is in effect, we update the dirty
+ // time on close as well as on open.
+ update_dirty = connection_ap_socks_iso_keepalive_enabled(entry_conn);
}
conn->cpath_layer = NULL; /* don't keep a stale pointer */
conn->on_circuit = NULL;
@@ -1389,6 +1395,10 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
log_debug(LD_APP, "Removing stream %d from circ %u",
conn->stream_id, (unsigned)circ->n_circ_id);
+ if (update_dirty) {
+ circ->timestamp_dirty = approx_time();
+ }
+
/* If the stream was removed, and it was a rend stream, decrement the
* number of streams on the circuit associated with the rend service.
*/
@@ -2745,6 +2755,20 @@ consider_recording_trackhost(const entry_connection_t *conn,
ADDRMAPSRC_TRACKEXIT, 0, 0, stream_id);
}
+/**
+ * Return true if <b>conn</b> is configured with KeepaliveIsolateSOCKSAuth,
+ * and it has its socks isolation set.
+ */
+static bool
+connection_ap_socks_iso_keepalive_enabled(const entry_connection_t *conn)
+{
+ return conn &&
+ conn->socks_request &&
+ (conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) &&
+ (conn->entry_cfg.socks_iso_keep_alive) &&
+ (conn->socks_request->usernamelen || conn->socks_request->passwordlen);
+}
+
/** Attempt to attach the connection <b>conn</b> to <b>circ</b>, and send a
* begin or resolve cell as appropriate. Return values are as for
* connection_ap_handshake_attach_circuit. The stream will exit from the hop
@@ -2766,10 +2790,7 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn,
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
if (!circ->base_.timestamp_dirty ||
- ((conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) &&
- (conn->entry_cfg.socks_iso_keep_alive) &&
- (conn->socks_request->usernamelen ||
- conn->socks_request->passwordlen))) {
+ connection_ap_socks_iso_keepalive_enabled(conn)) {
/* When stream isolation is in use and controlled by an application
* we are willing to keep using the stream. */
circ->base_.timestamp_dirty = approx_time();