aboutsummaryrefslogtreecommitdiff
path: root/spec/path-spec/when-we-build.md
diff options
context:
space:
mode:
Diffstat (limited to 'spec/path-spec/when-we-build.md')
-rw-r--r--spec/path-spec/when-we-build.md177
1 files changed, 177 insertions, 0 deletions
diff --git a/spec/path-spec/when-we-build.md b/spec/path-spec/when-we-build.md
new file mode 100644
index 0000000..7130978
--- /dev/null
+++ b/spec/path-spec/when-we-build.md
@@ -0,0 +1,177 @@
+<a id="path-spec.txt-2.1"></a>
+
+# When we build
+
+<a id="path-spec.txt-2.1.0"></a>
+
+## We don't build circuits until we have enough directory info
+
+There's a class of possible attacks where our directory servers
+only give us information about the relays that they would like us
+to use. To prevent this attack, we don't build multi-hop
+circuits
+(including
+[preemptive circuits](#preemptive),
+[on-demand circuits(#on-demand),
+[onion-service circuits](#onion-service)]
+or [self-testing testing circuits](#self-test))
+for real traffic
+until we have enough directory information to be
+reasonably confident this attack isn't being done to us.
+
+Here, "enough" directory information is defined as:
+
+```text
+ * Having a consensus that's been valid at some point in the
+ last REASONABLY_LIVE_TIME interval (24 hours).
+
+ * Having enough descriptors that we could build at least some
+ fraction F of all bandwidth-weighted paths, without taking
+ ExitNodes/EntryNodes/etc into account.
+
+ (F is set by the PathsNeededToBuildCircuits option,
+ defaulting to the 'min_paths_for_circs_pct' consensus
+ parameter, with a final default value of 60%.)
+
+ * Having enough descriptors that we could build at least some
+ fraction F of all bandwidth-weighted paths, _while_ taking
+ ExitNodes/EntryNodes/etc into account.
+
+ (F is as above.)
+
+ * Having a descriptor for every one of the first
+ NUM_USABLE_PRIMARY_GUARDS guards among our primary guards. (see
+ guard-spec.txt)
+```
+
+We define the "fraction of bandwidth-weighted paths" as the product of
+these three fractions.
+
+```text
+ * The fraction of descriptors that we have for nodes with the Guard
+ flag, weighted by their bandwidth for the guard position.
+ * The fraction of descriptors that we have for all nodes,
+ weighted by their bandwidth for the middle position.
+ * The fraction of descriptors that we have for nodes with the Exit
+ flag, weighted by their bandwidth for the exit position.
+```
+
+If the consensus has zero weighted bandwidth for a given kind of
+relay (Guard, Middle, or Exit), Tor instead uses the fraction of relays
+for which it has the descriptor (not weighted by bandwidth at all).
+
+If the consensus lists zero exit-flagged relays, Tor instead uses the
+fraction of middle relays.
+
+<a id="path-spec.txt-2.1.1"></a>
+
+## Clients build circuits preemptively {#preemptive}
+
+When running as a client, Tor tries to maintain at least a certain
+number of clean circuits, so that new streams can be handled
+quickly. To increase the likelihood of success, Tor tries to
+predict what circuits will be useful by choosing from among nodes
+that support the ports we have used in the recent past (by default
+one hour). Specifically, on startup Tor tries to maintain one clean
+fast exit circuit that allows connections to port 80, and at least
+two fast clean stable internal circuits in case we get a resolve
+request or hidden service request (at least three if we _run_ a
+hidden service).
+
+After that, Tor will adapt the circuits that it preemptively builds
+based on the requests it sees from the user: it tries to have two fast
+clean exit circuits available for every port seen within the past hour
+(each circuit can be adequate for many predicted ports -- it doesn't
+need two separate circuits for each port), and it tries to have the
+above internal circuits available if we've seen resolves or hidden
+service activity within the past hour. If there are 12 or more clean
+circuits open, it doesn't open more even if it has more predictions.
+
+Only stable circuits can "cover" a port that is listed in the
+LongLivedPorts config option. Similarly, hidden service requests
+to ports listed in LongLivedPorts make us create stable internal
+circuits.
+
+Note that if there are no requests from the user for an hour, Tor
+will predict no use and build no preemptive circuits.
+
+The Tor client SHOULD NOT store its list of predicted requests to a
+persistent medium.
+
+<a id="path-spec.txt-2.1.2"></a>
+
+## Clients build circuits on demand {#on-demand}
+
+Additionally, when a client request exists that no circuit (built or
+pending) might support, we create a new circuit to support the request.
+For exit connections, we pick an exit node that will handle the
+most pending requests (choosing arbitrarily among ties), launch a
+circuit to end there, and repeat until every unattached request
+might be supported by a pending or built circuit. For internal
+circuits, we pick an arbitrary acceptable path, repeating as needed.
+
+Clients consider a circuit to become "dirty" as soon as a stream is
+attached to it, or some other request is performed over the circuit.
+If a circuit has been "dirty" for at least MaxCircuitDirtiness seconds,
+new circuits may not be attached to it.
+
+In some cases we can reuse an already established circuit if it's
+clean; see ["cannibalizing circuits"](./cannibalizing-circuits.md)
+
+for details.
+
+<a id="path-spec.txt-2.1.3"></a>
+
+## Relays build circuits for testing reachability and bandwidth {#self-test}
+
+Tor relays test reachability of their ORPort once they have
+successfully built a circuit (on startup and whenever their IP address
+changes). They build an ordinary fast internal circuit with themselves
+as the last hop. As soon as any testing circuit succeeds, the Tor
+relay decides it's reachable and is willing to publish a descriptor.
+
+We launch multiple testing circuits (one at a time), until we
+have NUM_PARALLEL_TESTING_CIRC (4) such circuits open. Then we
+do a "bandwidth test" by sending a certain number of relay drop
+cells down each circuit: BandwidthRate * 10 / CELL_NETWORK_SIZE
+total cells divided across the four circuits, but never more than
+CIRCWINDOW_START (1000) cells total. This exercises both outgoing and
+incoming bandwidth, and helps to jumpstart the observed bandwidth
+(see dir-spec.txt).
+
+Tor relays also test reachability of their DirPort once they have
+established a circuit, but they use an ordinary exit circuit for
+this purpose.
+
+<a id="path-spec.txt-2.1.4"></a>
+
+## Hidden-service circuits {#onion-service}
+
+See section 4 below.
+
+<a id="path-spec.txt-2.1.5"></a>
+
+## Rate limiting of failed circuits
+
+If we fail to build a circuit N times in a X second period
+(see ["Handling failure"](./handling-failure.md)
+for how this works), we stop building circuits until the X seconds
+have elapsed.
+XXXX
+
+<a id="path-spec.txt-2.1.6"></a>
+
+## When to tear down circuits
+
+Clients should tear down circuits (in general) only when those circuits
+have no streams on them. Additionally, clients should tear-down
+stream-less circuits only under one of the following conditions:
+
+```text
+ - The circuit has never had a stream attached, and it was created too
+ long in the past (based on CircuitsAvailableTimeout or
+ cbtlearntimeout, depending on timeout estimate status).
+
+ - The circuit is dirty (has had a stream attached), and it has been
+ dirty for at least MaxCircuitDirtiness.
+```