aboutsummaryrefslogtreecommitdiff
path: root/spec/guard-spec/algorithm.md
blob: ba1c725f61e9cee602240becdf81afd3d32815a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
<a id="guard-spec.txt-4"></a>

# The algorithm

<a id="guard-spec.txt-4.0"></a>

## The guards listed in the current consensus. {#GUARDS}

By {set:GUARDS} we mean the set of all guards in the current
consensus that are usable for all circuits and directory
requests. (They must have the flags: Stable, Fast, V2Dir, Guard.)

**Rationale**

We require all guards to have the flags that we potentially need
from any guard, so that all guards are usable for all circuits.

<a id="guard-spec.txt-4.1"></a>

## The Sampled Guard Set. {#SAMPLED}

We maintain a set, {set:SAMPLED_GUARDS}, that persists across
invocations of Tor. It is a subset of the nodes ordered by a sample idx that
we have seen listed as a guard in the consensus at some point.
For each such guard, we record persistently:

```text
      - {pvar:ADDED_ON_DATE}: The date on which it was added to
        sampled_guards.

        We set this value to a point in the past, using
        RAND(now, {GUARD_LIFETIME}/10). See
        Appendix [RANDOM] below.

      - {pvar:ADDED_BY_VERSION}: The version of Tor that added it to
        sampled_guards.

      - {pvar:IS_LISTED}: Whether it was listed as a usable Guard in
        the _most recent_ consensus we have seen.

      - {pvar:FIRST_UNLISTED_AT}: If IS_LISTED is false, the publication date
        of the earliest consensus in which this guard was listed such that we
        have not seen it listed in any later consensus.  Otherwise "None."
        We randomize this to a point in the past, based on
          RAND(added_at_time, {REMOVE_UNLISTED_GUARDS_AFTER} / 5)
```

For each guard in {SAMPLED_GUARDS}, we also record this data,
non-persistently:

```text
      - {tvar:last_tried_connect}: A 'last tried to connect at'
        time.  Default 'never'.

      - {tvar:is_reachable}: an "is reachable" tristate, with
        possible values { <state:yes>, <state:no>, <state:maybe> }.
        Default '<maybe>.'

               [Note: "yes" is not strictly necessary, but I'm
                making it distinct from "maybe" anyway, to make our
                logic clearer.  A guard is "maybe" reachable if it's
                worth trying. A guard is "yes" reachable if we tried
                it and succeeded.]

               [Note 2: This variable is, in fact, a combination
               of different context-sensitive variables depending
               on the _purpose_ for which we are selecting a guard.
               When we are selecing a guard for an ordinary
               circuit, we look at the regular {is_reachable}.
               But when we are selecting the guard for a one-hop
               directory circuit, we also look at an instance
	       of {is_reachable} that tracks whether
	       downloads of the types we are making have failed
	       recently.]

      - {tvar:failing_since}: The first time when we failed to
        connect to this guard. Defaults to "never".  Reset to
        "never" when we successfully connect to this guard.

      - {tvar:is_pending} A "pending" flag.  This indicates that we
        are trying to build an exploratory circuit through the
        guard, and we don't know whether it will succeed.

      - {tvar:pending_since}: A timestamp.  Set whenever we set
        {tvar:is_pending} to true; cleared whenever we set
        {tvar:is_pending} to false. NOTE
```

We require that {SAMPLED_GUARDS} contain at least
{MIN_FILTERED_SAMPLE} guards from the consensus (if possible),
but not more than {MAX_SAMPLE_THRESHOLD} of the number of guards
in the consensus, and not more than {MAX_SAMPLE_SIZE} in total.
(But if the maximum would be smaller than {MIN_FILTERED_SAMPLE}, we
set the maximum at {MIN_FILTERED_SAMPLE}.)

To add a new guard to {SAMPLED_GUARDS}, pick an entry at random from
({GUARDS} - {SAMPLED_GUARDS}), according to the path selection rules.

We remove an entry from {SAMPLED_GUARDS} if:

```text
      * We have a live consensus, and {IS_LISTED} is false, and
        {FIRST_UNLISTED_AT} is over {REMOVE_UNLISTED_GUARDS_AFTER}
        days in the past.

     OR

      * We have a live consensus, and {ADDED_ON_DATE} is over
        {GUARD_LIFETIME} ago, *and* {CONFIRMED_ON_DATE} is either
        "never", or over {GUARD_CONFIRMED_MIN_LIFETIME} ago.
```

Note that {SAMPLED_GUARDS} does not depend on our configuration.
It is possible that we can't actually connect to any of these
guards.

**Rationale**

The {SAMPLED_GUARDS} set is meant to limit the total number of
guards that a client will connect to in a given period.  The
upper limit on its size prevents us from considering too many
guards.

The first expiration mechanism is there so that our
{SAMPLED_GUARDS} list does not accumulate so many dead
guards that we cannot add new ones.

The second expiration mechanism makes us rotate our guards slowly
over time.

Ordering the {SAMPLED_GUARDS} set in the order in which we sampled those
guards and picking guards from that set according to this ordering improves
load-balancing. It is closer to offer the expected usage of the guard nodes
as per the path selection rules.

The ordering also improves on another objective of this proposal: trying to
resist an adversary pushing clients over compromised guards, since the
adversary would need the clients to exhaust all their initial
{SAMPLED_GUARDS} set before having a chance to use a newly deployed
adversary node.

<a id="guard-spec.txt-4.2"></a>

## The Usable Sample {#FILTERED}

We maintain another set, {set:FILTERED_GUARDS}, that does not
persist. It is derived from:

```text
       - {SAMPLED_GUARDS}
       - our current configuration,
       - the path bias information.
```

A guard is a member of {set:FILTERED_GUARDS} if and only if all
of the following are true:

```text
       - It is a member of {SAMPLED_GUARDS}, with {IS_LISTED} set to
         true.
       - It is not disabled because of path bias issues.
       - It is not disabled because of ReachableAddresses policy,
         the ClientUseIPv4 setting, the ClientUseIPv6 setting,
         the FascistFirewall setting, or some other
         option that prevents using some addresses.
       - It is not disabled because of ExcludeNodes.
       - It is a bridge if UseBridges is true; or it is not a
         bridge if UseBridges is false.
       - Is included in EntryNodes if EntryNodes is set and
         UseBridges is not. (But see 2.B above).
```

We have an additional subset, {set:USABLE_FILTERED_GUARDS}, which
is defined to be the subset of {FILTERED_GUARDS} where
{is_reachable} is `<yes>` or `<maybe>`.

We try to maintain a requirement that {USABLE_FILTERED_GUARDS}
contain at least {MIN_FILTERED_SAMPLE} elements:

```text
     Whenever we are going to sample from {USABLE_FILTERED_GUARDS},
     and it contains fewer than {MIN_FILTERED_SAMPLE} elements, we
     add new elements to {SAMPLED_GUARDS} until one of the following
     is true:

       * {USABLE_FILTERED_GUARDS} is large enough,
     OR
       * {SAMPLED_GUARDS} is at its maximum size.

     ** Rationale **
```

These filters are applied _after_ sampling: if we applied them
before the sampling, then our sample would reflect the set of
filtering restrictions that we had in the past.

<a id="guard-spec.txt-4.3"></a>

## The confirmed-guard list. {#CONFIRMED}

\[formerly USED_GUARDS\]

We maintain a persistent ordered list, {list:CONFIRMED_GUARDS}.
It contains guards that we have used before, in our preference
order of using them.  It is a subset of {SAMPLED_GUARDS}.  For
each guard in this list, we store persistently:

- {pvar:IDENTITY} Its fingerprint.

```text
      - {pvar:CONFIRMED_ON_DATE} When we added this guard to
        {CONFIRMED_GUARDS}.

        Randomized to a point in the past as RAND(now, {GUARD_LIFETIME}/10).
```

We append new members to {CONFIRMED_GUARDS} when we mark a circuit
built through a guard as "for user traffic."

Whenever we remove a member from {SAMPLED_GUARDS}, we also remove
it from {CONFIRMED_GUARDS}.

```text
      [Note: You can also regard the {CONFIRMED_GUARDS} list as a
      total ordering defined over a subset of {SAMPLED_GUARDS}.]
```

Definition: we call Guard A "higher priority" than another Guard B
if, when A and B are both reachable, we would rather use A.  We
define priority as follows:

```text
     * Every guard in {CONFIRMED_GUARDS} has a higher priority
       than every guard not in {CONFIRMED_GUARDS}.

     * Among guards in {CONFIRMED_GUARDS}, the one appearing earlier
       on the {CONFIRMED_GUARDS} list has a higher priority.

     * Among guards that do not appear in {CONFIRMED_GUARDS},
       {is_pending}==true guards have higher priority.

     * Among those, the guard with earlier {last_tried_connect} time
       has higher priority.

     * Finally, among guards that do not appear in
       {CONFIRMED_GUARDS} with {is_pending==false}, all have equal
       priority.

   ** Rationale **
```

We add elements to this ordering when we have actually used them
for building a usable circuit.  We could mark them at some other
time (such as when we attempt to connect to them, or when we
actually connect to them), but this approach keeps us from
committing to a guard before we actually use it for sensitive
traffic.

<a id="guard-spec.txt-4.4"></a>

## The Primary guards {#PRIMARY}

We keep a run-time non-persistent ordered list of
{list:PRIMARY_GUARDS}.  It is a subset of {FILTERED_GUARDS}.  It
contains {N_PRIMARY_GUARDS} elements.

To compute primary guards, take the ordered intersection of
{CONFIRMED_GUARDS} and {FILTERED_GUARDS}, and take the first
{N_PRIMARY_GUARDS} elements.  If there are fewer than
{N_PRIMARY_GUARDS} elements, append additional elements to
PRIMARY_GUARDS chosen from ({FILTERED_GUARDS} - {CONFIRMED_GUARDS}),
ordered in "sample order" (that is, by {ADDED_ON_DATE}).

Once an element has been added to {PRIMARY_GUARDS}, we do not remove it
until it is replaced by some element from {CONFIRMED_GUARDS}.
That is: if a non-primary guard becomes confirmed and not every primary
guard is confirmed, then the list of primary guards list is regenerated,
first from the confirmed guards (as before), and then from any
non-confirmed primary guards.

Note that {PRIMARY_GUARDS} do not have to be in
{USABLE_FILTERED_GUARDS}: they might be unreachable.

**Rationale**

These guards are treated differently from other guards.  If one of
them is usable, then we use it right away. For other guards
{FILTERED_GUARDS}, if it's usable, then before using it we might
first double-check whether perhaps one of the primary guards is
usable after all.

<a id="guard-spec.txt-4.5"></a>

## Retrying guards. {#RETRYING}

(We run this process as frequently as needed. It can be done once
a second, or just-in-time.)

If a primary sampled guard's {is_reachable} status is `<no>`, then
we decide whether to update its {is_reachable} status to `<maybe>`
based on its {last_tried_connect} time, its {failing_since} time,
and the {PRIMARY_GUARDS_RETRY_SCHED} schedule.

If a non-primary sampled guard's {is_reachable} status is `<no>`, then
we decide whether to update its {is_reachable} status to `<maybe>`
based on its {last_tried_connect} time, its {failing_since} time,
and the {GUARDS_RETRY_SCHED} schedule.

**Rationale**

An observation that a guard has been 'unreachable' only lasts for
a given amount of time, since we can't infer that it's unreachable
now from the fact that it was unreachable a few minutes ago.

## Circuit status {#CIRC-STATUS}

Sometimes the guard selection algorithm will return a guard that we
would always be happy to use; but in other cases, the guard
selection algorithm can return a guard that we shouldn't use
without gathering additional information.

From the point of view of guard selection,
every circuit we build is considered to be in one of these states:

 * `<state:usable_on_completion>`
 * `<state:usable_if_no_better_guard>`
 * `<state:waiting_for_better_guard>`
 * `<state:complete>`

You may only attach streams to `<complete>` circuits.
(Additionally, you may only send RENDEZVOUS messages, ESTABLISH_INTRO
messages, and INTRODUCE messages on `<complete>` circuits.)

The per-circuit state machine is:

 * New circuits are `<usable_on_completion>` or
   `<usable_if_no_better_guard>`.

 * A `<usable_on_completion>` circuit may become `<complete>`, or may
   fail.

 * A `<usable_if_no_better_guard>` circuit may become
   `<usable_on_completion>`; may become `<waiting_for_better_guard>`; or may
   fail.

 * A `<waiting_for_better_guard>` circuit will become `<complete>`, or will
   be closed, or will fail.

 * A `<complete>` circuit remains `<complete>` until it fails or is
   closed.

```mermaid
stateDiagram-v2
  [*] --> usable_on_completion
  [*] --> usable_if_no_better_guard
  usable_on_completion --> complete
  usable_on_completion --> failed
  usable_if_no_better_guard --> usable_on_completion
  usable_if_no_better_guard --> waiting_for_better_guard
  usable_if_no_better_guard --> failed
  waiting_for_better_guard --> complete
  waiting_for_better_guard --> failed
  waiting_for_better_guard --> closed
  complete --> failed
  complete --> closed
  failed --> [*]
  closed --> [*]
```
<!-- TODO: The above diagram does not yet render. Fix that. -->

Each of these transitions is described in sections below.

<a id="guard-spec.txt-4.6"></a>

## Selecting guards for circuits. \[Section:SELECTING\] {#SELECTING}

Now that we have described the various lists of guards, we can explain how
guards are chosen for each circuit.

We keep, as global transient state:

 * {tvar:last_time_on_internet} -- the last time at which we
   successfully used a circuit or connected to a guard.  At
   startup we set this to "infinitely far in the past."

As an input to the algorithm, we take a list of _restrictions_.
These may include specific relays or families that we need to avoid.

Here is the algorithm.  It is given as a series of sub-algorithms,
in decreasing order of preference from best case to worst case.
When we want to build a circuit, and we need to pick a guard:

 * In the base case, if any entry in PRIMARY_GUARDS has {is_reachable} status of
   `<maybe>` or `<yes>`, consider only such guards.  Call them the
   "reachable primary guards".

   Start by considering the the first {NUM_USABLE_PRIMARY_GUARDS} (or
   {NUM_USABLE_PRIMARY_DIRECTORY_GUARDS}) reachable primary guards.
   Remove any guards that do not follow our path selection
   restrictions, to build a temporary list. If that temporary list contains at
   least one guard, choose a guard from that list uniformly at
   random.

   If the temporary list contains no guards, return the first guard
   from our reachable primary guard that does obey the path restriction.

   When selecting a guard according to this approach, its circuit
   is `<usable_on_completion>`.

   \[Note: We do not use {is_pending} on primary guards, since we
   are willing to try to build multiple circuits through them
   before we know for sure whether they work, and since we will
   not use any non-primary guards until we are sure that the
   primary guards are all down.  (XX is this good?)\]

 * Otherwise, if the ordered intersection of {CONFIRMED_GUARDS}
   and {USABLE_FILTERED_GUARDS} is nonempty, return the first
   entry in that intersection that has {is_pending} set to
   false. Set its value of {is_pending} to true,
   and set its {pending_since} to the current time.
   The circuit
   is now `<usable_if_no_better_guard>`.  (If all entries have
   {is_pending} true, pick the first one.)

 * Otherwise, if there is no such entry, select a member from
   {USABLE_FILTERED_GUARDS} in sample order. Set its {is_pending} field to
   true, and set its {pending_since} to the current time.
   The circuit is `<usable_if_no_better_guard>`.

 * Otherwise, in the worst case, if USABLE_FILTERED_GUARDS is empty, we have exhausted
   all the sampled guards.  In this case we proceed by marking all guards
   as `<maybe>` reachable so that we can keep on trying circuits.

Whenever we select a guard for a new circuit attempt, we update the
{last_tried_connect} time for the guard to 'now.'

In some cases (for example, when we need a certain directory feature,
or when we need to avoid using a certain exit as a guard), we need to
restrict the guards that we use for a single circuit. When this happens, we
remember the restrictions that applied when choosing the guard for
that circuit, since we will need them later (see \[UPDATE_WAITING\].).

**Rationale**

We're getting to the core of the algorithm here.  Our main goals are to
make sure that

 1. If it's possible to use a primary guard, we do.
 2. We probably use the first primary guard.

So we only try non-primary guards if we're pretty sure that all
the primary guards are down, and we only try a given primary guard
if the earlier primary guards seem down.

When we _do_ try non-primary guards, however, we only build one
circuit through each, to give it a chance to succeed or fail.  If
ever such a circuit succeeds, we don't use it until we're pretty
sure that it's the best guard we're getting. (see below).

\[XXX timeout.\]

<a id="guard-spec.txt-4.7"></a>

## When a circuit fails. {#ON_FAIL}

When a circuit fails in a way that makes us conclude that a guard
is not reachable, we take the following steps:

```text
      * Set the guard's {is_reachable} status to <no>.  If it had
        {is_pending} set to true, we make it non-pending and clear
        {pending_since}.

      * Close the circuit, of course.  (This removes it from
        consideration by the algorithm in [UPDATE_WAITING].)

      * Update the list of waiting circuits.  (See [UPDATE_WAITING]
        below.)
```

\[Note: the existing Tor logic will cause us to create more
circuits in response to some of these steps; and also see
\[ON_CONSENSUS\].\]

\[Note 2: In the case of a one-hop circuit made for a directory
request, it is possible for the request to fail _after_ the circuit
is built: for example, if we ask for the latest consensus and we are
told "404". In this case, we mark the appropriate directory-specific
`{is_reachable}` instance for that guard to `<no>`.\]

> C tor implements the above "note 2" by treating requests for
> directory guards for as if they had an
> extra type of restriction, rather than a separate instance of
> `{is_reachable}`.  (For more on restrictions, see ["Selecting
> Guards"](#SELECTING) above.)  This requires the C tor
> impementation to special-case this restriction type, so that
> it is treated the same way as an `{is_reachable}` variable.


**Rationale**

See \[SELECTING\] above for rationale.

<a id="guard-spec.txt-4.8"></a>

## When a circuit succeeds {#ON_SUCCESS}

When a circuit succeeds in a way that makes us conclude that a
guard _was_ reachable, we take these steps:

```text
      * We set its {is_reachable} status to <yes>.
      * We set its {failing_since} to "never".
      * If the guard was {is_pending}, we clear the {is_pending} flag
        and set {pending_since} to false.
      * If the guard was not a member of {CONFIRMED_GUARDS}, we add
        it to the end of {CONFIRMED_GUARDS}.

      * If this circuit was <usable_on_completion>, this circuit is
        now <complete>. You may attach streams to this circuit,
        and use it for hidden services.

      * If this circuit was <usable_if_no_better_guard>, it is now
        <waiting_for_better_guard>.  You may not yet attach streams to it.
        Then check whether the {last_time_on_internet} is more than
        {INTERNET_LIKELY_DOWN_INTERVAL} seconds ago:

           * If it is, then mark all {PRIMARY_GUARDS} as "maybe"
             reachable.

           * If it is not, update the list of waiting circuits. (See
             [UPDATE_WAITING] below)
```

\[Note: the existing Tor logic will cause us to create more
circuits in response to some of these steps; and see
\[ON_CONSENSUS\].\]

**Rationale**

See \[SELECTING\] above for rationale.

<a id="guard-spec.txt-4.9"></a>

## Updating the list of waiting circuits {#UPDATE_WAITING}

We run this procedure whenever it's possible that a
`<waiting_for_better_guard>` circuit might be ready to be called
`<complete>`.

```text
   * If any circuit C1 is <waiting_for_better_guard>, AND:
       * All primary guards have reachable status of <no>.
       * There is no circuit C2 that "blocks" C1.
     Then, upgrade C1 to <complete>.

   Definition: In the algorithm above, C2 "blocks" C1 if:
       * C2 obeys all the restrictions that C1 had to obey, AND
       * C2 has higher priority than C1, AND
       * Either C2 is <complete>, or C2 is <waiting_for_better_guard>,
         or C2 has been <usable_if_no_better_guard> for no more than
         {NONPRIMARY_GUARD_CONNECT_TIMEOUT} seconds.

   We run this procedure periodically:

   * If any circuit stays in <waiting_for_better_guard>
     for more than {NONPRIMARY_GUARD_IDLE_TIMEOUT} seconds,
     time it out.

      **Rationale**
```

If we open a connection to a guard, we might want to use it
immediately (if we're sure that it's the best we can do), or we
might want to wait a little while to see if some other circuit
which we like better will finish.

When we mark a circuit `<complete>`, we don't close the
lower-priority circuits immediately: we might decide to use
them after all if the `<complete>` circuit goes down before
{NONPRIMARY_GUARD_IDLE_TIMEOUT} seconds.

<a id="guard-spec.txt-4.9.1"></a>

### Without a list of waiting circuits {#NO_CIRCLIST}

As an alternative to the section \[SECTION:UPDATE_WAITING\] above,
this section presents a new way to maintain guard status
independently of tracking individual circuit status.  This
formulation gives a result equivalent or similar to the approach
above, but simplifies the necessary communications between the
guard and circuit subsystems.

As before, when all primary guards are Unreachable, we need to
try non-primary guards.  We select the first such guard (in
preference order) that is neither Unreachable nor Pending.
Whenever we give out such a guard, if the guard's status is
Unknown, then we call that guard "Pending" with its {is_pending}
flag, until the attempt to use it succeeds or fails.  We remember
when the guard became Pending with the {pending_since variable}.

After completing a circuit, the implementation must check whether
its guard is usable.  A guard's usability status may be "usable",
"unusable", or "unknown".  A guard is usable according to
these rules:

1. Primary guards are always usable.

1. Non-primary guards are usable _for a given circuit_ if every
   guard earlier in the preference list is either unsuitable for
   that circuit (e.g. because of family restrictions), or marked as
   Unreachable, or has been pending for at least
   `{NONPRIMARY_GUARD_CONNECT_TIMEOUT}`.

   Non-primary guards are not usable _for a given circuit_ if some
   guard earlier in the preference list is suitable for the circuit
   _and_ Reachable.

   Non-primary guards are unusable if they have not become
   usable after `{NONPRIMARY_GUARD_IDLE_TIMEOUT}` seconds.

1. If a circuit's guard is not usable or unusable immediately, the
   circuit is not discarded; instead, it is kept (but not used) until the
   guard becomes usable or unusable.

<a id="guard-spec.txt-4.10"></a>

## Whenever we get a new consensus. {#ON_CONSENSUS}

We update {GUARDS}.

For every guard in {SAMPLED_GUARDS}, we update {IS_LISTED} and
{FIRST_UNLISTED_AT}.

\[\*\*\] We remove entries from {SAMPLED_GUARDS} if appropriate,
according to the sampled-guards expiration rules.  If they were
in {CONFIRMED_GUARDS}, we also remove them from
{CONFIRMED_GUARDS}.

We recompute {FILTERED_GUARDS}, and everything that derives from
it, including {USABLE_FILTERED_GUARDS}, and {PRIMARY_GUARDS}.

(Whenever one of the configuration options that affects the
filter is updated, we repeat the process above, starting at the
\[\*\*\] line.)

```text
4.11. Deciding whether to generate a new circuit.
  [Section:NEW_CIRCUIT_NEEDED]
```

We generate a new circuit when we don't have
enough circuits either built or in-progress to handle a given
stream, or an expected stream.

For the purpose of this rule, we say that `<waiting_for_better_guard>`
circuits are neither built nor in-progress; that `<complete>`
circuits are built; and that the other states are in-progress.

```text
4.12. When we are missing descriptors.
   [Section:MISSING_DESCRIPTORS]
```

We need either a router descriptor or a microdescriptor in order
to build a circuit through a guard.  If we do not have such a
descriptor for a guard, we can still use the guard for one-hop
directory fetches, but not for longer circuits.

(Also, when we are missing descriptors for our first
{NUM_USABLE_PRIMARY_GUARDS} primary guards, we don't build
circuits at all until we have fetched them.)