diff --git a/changes/feature15482 b/changes/feature15482 new file mode 100644 index 0000000000..4e32d394b9 --- /dev/null +++ b/changes/feature15482 @@ -0,0 +1,5 @@ + o Minor features (client-side privacy) + - Indefinitely extend circuit lifespan by resetting dirtyness, if + IsolateSOCKSAuth is in use, the new `KeepAliveIsolateSOCKSAuth` + option is set, and streams with SOCKS authentication are attached + to the circuit. Implements feature 15482. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index af99570bd4..803fd187c9 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -934,7 +934,9 @@ The following options are useful only for clients (that is, if Feel free to reuse a circuit that was first used at most NUM seconds ago, but never attach a new stream to a circuit that is too old. For hidden services, this applies to the __last__ time a circuit was used, not the - first. (Default: 10 minutes) + first. Circuits with streams constructed with SOCKS authentication via + SocksPorts that have **KeepAliveIsolateSOCKSAuth** ignore this value. + (Default: 10 minutes) [[MaxClientCircuitsPending]] **MaxClientCircuitsPending** __NUM__:: Do not allow more than NUM circuits to be pending at a time for handling @@ -991,6 +993,9 @@ The following options are useful only for clients (that is, if **IsolateDestAddr**;; Don't share circuits with streams targeting a different destination address. + **KeepAliveIsolateSOCKSAuth**;; + If **IsolateSOCKSAuth** is enabled, keep alive circuits that have + streams with SOCKS authentication set indefinitely. **SessionGroup=**__INT__;; If no other isolation rules would prevent it, allow streams on this port to share circuits with streams from every other diff --git a/src/or/circuituse.c b/src/or/circuituse.c index e10bb82641..00340fd689 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -2284,11 +2284,11 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn, base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - if (!circ->base_.timestamp_dirty) { - circ->base_.timestamp_dirty = approx_time(); - } else if ((conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) && - (conn->socks_request->usernamelen || - conn->socks_request->passwordlen)) { + 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))) { /* 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(); diff --git a/src/or/config.c b/src/or/config.c index 6e782de0e0..aca956cf34 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -6022,6 +6022,7 @@ parse_port_config(smartlist_t *out, int sessiongroup = SESSION_GROUP_UNSET; unsigned isolation = ISO_DEFAULT; int prefer_no_auth = 0; + int socks_iso_keep_alive = 0; char *addrport; uint16_t ptmp=0; @@ -6246,6 +6247,8 @@ parse_port_config(smartlist_t *out, isoflag = ISO_CLIENTPROTO; } else if (!strcasecmp(elt, "IsolateClientAddr")) { isoflag = ISO_CLIENTADDR; + } else if (!strcasecmp(elt, "KeepAliveIsolateSOCKSAuth")) { + socks_iso_keep_alive = 1; } else { log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'", portname, escaped(elt_orig)); @@ -6276,6 +6279,13 @@ parse_port_config(smartlist_t *out, goto err; } + if (!(isolation & ISO_SOCKSAUTH) && socks_iso_keep_alive) { + log_warn(LD_CONFIG, "You have a %sPort entry with both " + "NoIsolateSOCKSAuth and KeepAliveIsolateSOCKSAuth set.", + portname); + goto err; + } + if (out && port) { size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0; port_cfg_t *cfg = port_cfg_new(namelen); @@ -6309,6 +6319,7 @@ parse_port_config(smartlist_t *out, cfg->entry_cfg.socks_prefer_no_auth = prefer_no_auth; if (! (isolation & ISO_SOCKSAUTH)) cfg->entry_cfg.socks_prefer_no_auth = 1; + cfg->entry_cfg.socks_iso_keep_alive = socks_iso_keep_alive; smartlist_add(out, cfg); } diff --git a/src/or/or.h b/src/or/or.h index 8c40f1ab67..6660a0dcdc 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1155,6 +1155,8 @@ typedef struct entry_port_cfg_t { /** When both no-auth and user/pass are advertised by a SOCKS client, select * no-auth. */ unsigned int socks_prefer_no_auth : 1; + /** When ISO_SOCKSAUTH is in use, Keep-Alive circuits indefinitely. */ + unsigned int socks_iso_keep_alive : 1; /* Client port types only: */ unsigned int ipv4_traffic : 1; @@ -2877,6 +2879,11 @@ typedef struct circuit_t { * circuits entered certain states. This usage probably won't * interfere with this field's primary purpose, but we should * document it more thoroughly to make sure of that. + * + * XXX027 The SocksPort option KeepaliveIsolateSOCKSAuth will artificially + * adjust this value forward each time a suitable stream is attached to an + * already constructed circuit, potentially keeping the circuit alive + * indefinitely. */ time_t timestamp_dirty;