1
//! Logic for filtering and selecting channels in order to find suitable channels for a target.
2

            
3
use crate::mgr::state::{ChannelState, OpenEntry, PendingEntry};
4
use crate::mgr::AbstractChannel;
5
use tor_linkspec::{HasRelayIds, RelayIds};
6

            
7
/// Returns `true` if the open channel is allowed to be used for a new channel request to the
8
/// target.
9
36
pub(crate) fn open_channel_is_allowed<C: AbstractChannel>(
10
36
    chan: &OpenEntry<C>,
11
36
    target: &impl HasRelayIds,
12
36
) -> bool {
13
36
    Some(chan)
14
36
        // only usable channels
15
36
        .filter(|entry| entry.channel.is_usable())
16
36
        // only channels which have *all* the relay ids of `target`
17
36
        .filter(|entry| entry.channel.has_all_relay_ids_from(target))
18
36
        // TODO: only channels which are canonical or have the same address as `target`
19
36
        .filter(|_entry| true)
20
36
        .is_some()
21
36
}
22

            
23
/// Returns `true` if the pending channel could possibly be used for a new channel request to the
24
/// target. You still need to verify the final built channel with [`open_channel_is_allowed`] before
25
/// using it.
26
24
pub(crate) fn pending_channel_maybe_allowed(
27
24
    chan: &PendingEntry,
28
24
    target: &impl HasRelayIds,
29
24
) -> bool {
30
    /// An empty [`RelayIds`].
31
    const EMPTY_IDS: RelayIds = RelayIds::empty();
32

            
33
    // TODO RELAY: The comments and behaviour below assume that it's better to create a new channel
34
    // than to wait around for a channel which may or may not end up being usable for `target`. This
35
    // has the benefit that malicious circuit extension requests won't delay legitimate circuit
36
    // extension requests, but also means that we could end up creating more channels than
37
    // necessary. This is different from C-tor, which will wait for a channel even if that channel
38
    // might not end up being usable for `target`. For example in tor's `channel_get_for_extend`,
39
    // tor will wait for an "in progress" channel if all of the following are true:
40
    //
41
    // - The requested ids are a subset of the channel's ids. (Note that in the comments below we
42
    //   require it to be a superset, not a subset.)
43
    // - The requested IPv4 or IPv6 address matches either the channel's IPv4 or IPv6 address. (Note
44
    //   that in the comments below, we require `target`s addresses to exactly match.)
45
    //
46
    // It might be good to re-evaluate what behaviour we want as we implement more channel code.
47
    //
48
    // NOTE (opara): It has been decided that C-tor's approach would be better. See the thread at:
49
    // https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/2544#note_3094696
50

            
51
    // We want to avoid returning pending channels that were initially created from malicious
52
    // channel requests (for example from malicious relay-extend requests) that build channels which
53
    // will never complete successfully. Two cases where this can happen are:
54
    // 1. A malicious channel request asks us to build a channel to a target with a correct relay id
55
    //    and address, but also an additional incorrect relay id. Later when the target sends its
56
    //    CERTS cell, all of the relay ids won't match and the channel will fail to build. We don't
57
    //    want to assign non-malicious channel requests to this pending channel that will eventually
58
    //    fail to build.
59
    // 2. A malicious channel request asks us to build a channel to a target with an incorrect
60
    //    address. This pending channel may stall. We don't want to assign non-malicious channel
61
    //    requests to this pending channel that will stall for potentially a long time.
62
24
    Some(chan)
63
24
        // Only channels where `target`s relay ids are a superset of `entry`s relay ids.
64
24
        // - Hopefully the built channel will gain the additional ids that are requested by
65
24
        //   `target`. This should happen in most cases where none of the channels are made
66
24
        //   maliciously, since the `target` should return all of its relay ids in its CERTS cell.
67
24
        // - (Addressing 1. above) By only returning pending channels that have a subset of
68
24
        //   `target`s relay ids, we ensure that the returned pending channel does not have
69
24
        //   additional incorrect relay ids that will intentionally cause the pending channel to
70
24
        //   fail.
71
24
        // - If the built channel does not gain the remaining ids required by `target, then we won't
72
24
        //   be able to use this channel for the channel request to `target`. But we won't be able
73
24
        //   to create a new channel either, since we know that that a new channel also won't have
74
24
        //   all of the relay ids. So this channel request was doomed from the start.
75
24
        // - If the built channel gains additional ids that `target` doesn't have, that's fine and
76
24
        //   we can still use the channel for `target`.
77
24
        .filter(|entry| target.has_all_relay_ids_from(&entry.ids))
78
24
        // TODO: Only channels which have the exact same address list as `target` (the two sets of
79
24
        // addresses must match exactly).
80
24
        // - While an EXTEND2 message usually only contains one IPv4 and IPv6 address, `target`
81
24
        //   (which is a `HasAddrs`) may have more addresses. According to tor-spec, an EXTEND2
82
24
        //   message can contain multiple IPv4 and IPv6 addresses:
83
24
        //   > Nodes MUST ignore unrecognized specifiers, and MUST accept multiple instances of
84
24
        //   > specifiers other than 'legacy identity' and 'Ed25519 identity'. (Nodes SHOULD reject
85
24
        //   > link specifier lists that include multiple instances of either one of those
86
24
        //   > specifiers.)
87
24
        // - (Addressing 2. above) By only returning pending channels that have exactly the same
88
24
        //   addresses, we ensure that the returned pending channel does not have any incorrect
89
24
        //   addresses that will cause the pending channel to stall.
90
24
        // - If the pending channel had additional addresses compared to `target`, the channel could
91
24
        //   get built using an address that is not valid for `target` and we wouldn't be able to
92
24
        //   use the built channel.
93
24
        // - If the pending channel had fewer addresses compared to `target`, the channel would have
94
24
        //   a lower possibility of building successfully compared to a newly created channel to
95
24
        //   `target`, so this would not be a good channel for us to return.
96
24
        .filter(|_entry| true)
97
24
        // Don't allow a pending channel that has no relay ids. I don't have a good reason for
98
24
        // excluding this, other than "it seems weird".
99
24
        .filter(|entry| entry.ids != EMPTY_IDS)
100
24
        .is_some()
101
24
}
102

            
103
/// Returns the best channel for `target`.
104
// TODO: remove me when the below TODOs are implemented
105
#[allow(clippy::only_used_in_recursion)]
106
104
pub(crate) fn choose_best_channel<'a, C: AbstractChannel>(
107
104
    channels: impl IntoIterator<Item = &'a ChannelState<C>>,
108
104
    target: &impl HasRelayIds,
109
104
) -> Option<&'a ChannelState<C>> {
110
    use std::cmp::Ordering;
111
    use ChannelState::*;
112

            
113
104
    let channels = channels.into_iter();
114

            
115
    /// Compare two channels to determine the better channel for `target`.
116
216
    fn choose_channel<C: AbstractChannel>(
117
216
        a: &&ChannelState<C>,
118
216
        b: &&ChannelState<C>,
119
216
        target: &impl HasRelayIds,
120
216
    ) -> Choice {
121
216
        // TODO: follow `channel_is_better` in C tor
122
216
        match (a, b) {
123
            // if the open channel is not usable, prefer the pending channel
124
108
            (Open(a), Building(_b)) if !a.channel.is_usable() => Choice::Second,
125
            // otherwise prefer the open channel
126
84
            (Open(_a), Building(_b)) => Choice::First,
127

            
128
            // the logic above, but reversed
129
60
            (Building(_), Open(_)) => choose_channel(b, a, target).reverse(),
130

            
131
            // not much info to help choose when both channels are pending, but this should be rare
132
16
            (Building(_a), Building(_b)) => Choice::Either,
133

            
134
            // both channels are open
135
32
            (Open(a), Open(b)) => {
136
32
                let a_is_usable = a.channel.is_usable();
137
32
                let b_is_usable = b.channel.is_usable();
138
32

            
139
32
                // if neither open channel is usable, don't take preference
140
32
                if !a_is_usable && !b_is_usable {
141
                    return Choice::Either;
142
32
                }
143
32

            
144
32
                // prefer a channel that is usable
145
32
                if !a_is_usable {
146
26
                    return Choice::Second;
147
6
                }
148
6
                if !b_is_usable {
149
6
                    return Choice::First;
150
                }
151

            
152
                // TODO: prefer canonical channels
153

            
154
                // TODO: prefer a channel where the address matches the target
155

            
156
                // TODO: prefer the one we think the peer will think is canonical
157

            
158
                // TODO: prefer older channels
159

            
160
                // TODO: use number of circuits as tie-breaker?
161

            
162
                Choice::Either
163
            }
164
        }
165
216
    }
166

            
167
    // preferred channels will be ordered higher, and we choose the max
168
156
    channels.max_by(|a, b| match choose_channel(a, b, target) {
169
50
        Choice::First => Ordering::Greater,
170
90
        Choice::Second => Ordering::Less,
171
16
        Choice::Either => Ordering::Equal,
172
156
    })
173
104
}
174

            
175
/// Similar to [`Ordering`](std::cmp::Ordering), but is easier to reason about when comparing two
176
/// objects that don't have a numeric sense of ordering (ex: returning `Greater` is confusing if the
177
/// ordering isn't numeric).
178
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
179
enum Choice {
180
    /// Choose the first.
181
    First,
182
    /// Choose the second.
183
    Second,
184
    /// Choose either.
185
    Either,
186
}
187

            
188
impl Choice {
189
    /// Reverses the `Choice`.
190
    ///
191
    /// - `First` becomes `Second`.
192
    /// - `Second` becomes `First`.
193
    /// - `Either` becomes `Either`.
194
60
    fn reverse(self) -> Self {
195
60
        match self {
196
50
            Self::First => Self::Second,
197
10
            Self::Second => Self::First,
198
            Self::Either => Self::Either,
199
        }
200
60
    }
201
}
202

            
203
#[cfg(test)]
204
mod test {
205
    // @@ begin test lint list maintained by maint/add_warning @@
206
    #![allow(clippy::bool_assert_comparison)]
207
    #![allow(clippy::clone_on_copy)]
208
    #![allow(clippy::dbg_macro)]
209
    #![allow(clippy::mixed_attributes_style)]
210
    #![allow(clippy::print_stderr)]
211
    #![allow(clippy::print_stdout)]
212
    #![allow(clippy::single_char_pattern)]
213
    #![allow(clippy::unwrap_used)]
214
    #![allow(clippy::unchecked_duration_subtraction)]
215
    #![allow(clippy::useless_vec)]
216
    #![allow(clippy::needless_pass_by_value)]
217
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
218

            
219
    use super::*;
220

            
221
    use std::sync::Arc;
222
    use std::time::Duration;
223

            
224
    use tor_linkspec::RelayIds;
225
    use tor_llcrypto::pk::ed25519::Ed25519Identity;
226
    use tor_llcrypto::pk::rsa::RsaIdentity;
227
    use tor_proto::channel::kist::KistParams;
228
    use tor_proto::channel::ChannelPaddingInstructionsUpdates;
229

            
230
    #[derive(Debug)]
231
    struct FakeChannel {
232
        usable: bool,
233
        ids: RelayIds,
234
    }
235

            
236
    impl AbstractChannel for FakeChannel {
237
        fn is_usable(&self) -> bool {
238
            self.usable
239
        }
240
        fn duration_unused(&self) -> Option<Duration> {
241
            None
242
        }
243
        fn reparameterize(
244
            &self,
245
            _updates: Arc<ChannelPaddingInstructionsUpdates>,
246
        ) -> tor_proto::Result<()> {
247
            Ok(())
248
        }
249
        fn reparameterize_kist(&self, _kist_params: KistParams) -> tor_proto::Result<()> {
250
            Ok(())
251
        }
252
        fn engage_padding_activities(&self) {}
253
    }
254

            
255
    impl HasRelayIds for FakeChannel {
256
        fn identity(
257
            &self,
258
            key_type: tor_linkspec::RelayIdType,
259
        ) -> Option<tor_linkspec::RelayIdRef<'_>> {
260
            self.ids.identity(key_type)
261
        }
262
    }
263

            
264
    #[derive(Clone, Debug)]
265
    struct FakeBuildSpec {
266
        ids: RelayIds,
267
    }
268

            
269
    impl FakeBuildSpec {
270
        fn new(ids: RelayIds) -> Self {
271
            Self { ids }
272
        }
273
    }
274

            
275
    impl HasRelayIds for FakeBuildSpec {
276
        fn identity(
277
            &self,
278
            key_type: tor_linkspec::RelayIdType,
279
        ) -> Option<tor_linkspec::RelayIdRef<'_>> {
280
            self.ids.identity(key_type)
281
        }
282
    }
283

            
284
    /// Assert that two `Option<&T>` point to the same data.
285
    macro_rules! assert_opt_ptr_eq {
286
        ($a:expr, $b:expr) => {
287
            assert_opt_ptr_eq!($a, $b,);
288
        };
289
        ($a:expr, $b:expr, $($x:tt)*) => {
290
            assert_eq!($a.map(std::ptr::from_ref), $b.map(std::ptr::from_ref), $($x)*);
291
        };
292
    }
293

            
294
    /// Calls `f` with every permutation of `list`. Don't use with large lists :)
295
    fn with_permutations<T>(list: &[T], mut f: impl FnMut(Vec<&T>)) {
296
        use itertools::Itertools;
297
        for new_list in list.iter().permutations(list.len()) {
298
            f(new_list);
299
        }
300
    }
301

            
302
    /// Helper to make a fake Ed identity from some bytes.
303
    fn ed(a: &[u8]) -> Ed25519Identity {
304
        let mut bytes = [0; 32];
305
        bytes[0..a.len()].copy_from_slice(a);
306
        bytes.into()
307
    }
308

            
309
    /// Helper to make a fake rsa identity from some bytes.
310
    fn rsa(a: &[u8]) -> RsaIdentity {
311
        let mut bytes = [0; 20];
312
        bytes[0..a.len()].copy_from_slice(a);
313
        bytes.into()
314
    }
315

            
316
    /// Helper to build a `RelayIds` to make tests shorter.
317
    fn ids(
318
        rsa: impl Into<Option<RsaIdentity>>,
319
        ed: impl Into<Option<Ed25519Identity>>,
320
    ) -> RelayIds {
321
        let mut ids = tor_linkspec::RelayIdsBuilder::default();
322
        if let Some(rsa) = rsa.into() {
323
            ids.rsa_identity(rsa);
324
        }
325
        if let Some(ed) = ed.into() {
326
            ids.ed_identity(ed);
327
        }
328
        ids.build().unwrap()
329
    }
330

            
331
    /// Create an open channel entry.
332
    fn open_channel<C>(chan: C) -> OpenEntry<C> {
333
        OpenEntry {
334
            channel: Arc::new(chan),
335
            max_unused_duration: Duration::from_secs(0),
336
        }
337
    }
338

            
339
    /// Create a pending channel entry with the given IDs.
340
    fn pending_channel(ids: RelayIds) -> PendingEntry {
341
        use crate::mgr::state::UniqPendingChanId;
342
        use futures::FutureExt;
343
        use oneshot_fused_workaround as oneshot;
344

            
345
        PendingEntry {
346
            ids,
347
            pending: oneshot::channel().1.shared(),
348
            unique_id: UniqPendingChanId::new(),
349
        }
350
    }
351

            
352
    #[test]
353
    fn best_channel_usable_unusable() {
354
        // two channels where only the first is usable
355
        let channels = [
356
            ChannelState::Open(open_channel(FakeChannel {
357
                usable: true,
358
                ids: ids(None, ed(b"A")),
359
            })),
360
            ChannelState::Open(open_channel(FakeChannel {
361
                usable: false,
362
                ids: ids(None, ed(b"A")),
363
            })),
364
        ];
365

            
366
        // should return the usable channel
367
        let target = FakeBuildSpec::new(ids(None, ed(b"A")));
368
        with_permutations(&channels, |x| {
369
            assert_opt_ptr_eq!(choose_best_channel(x, &target), Some(&channels[0]));
370
        });
371
    }
372

            
373
    #[test]
374
    fn best_channel_open_pending() {
375
        // a usable open channel and a pending channel
376
        let channels = [
377
            ChannelState::Open(open_channel(FakeChannel {
378
                usable: true,
379
                ids: ids(None, ed(b"A")),
380
            })),
381
            ChannelState::Building(pending_channel(ids(None, ed(b"A")))),
382
        ];
383

            
384
        // should return the open channel
385
        let target = FakeBuildSpec::new(ids(None, ed(b"A")));
386
        with_permutations(&channels, |x| {
387
            assert_opt_ptr_eq!(choose_best_channel(x, &target), Some(&channels[0]));
388
        });
389

            
390
        // an unusable open channel and a pending channel
391
        let channels = [
392
            ChannelState::Open(open_channel(FakeChannel {
393
                usable: false,
394
                ids: ids(None, ed(b"A")),
395
            })),
396
            ChannelState::Building(pending_channel(ids(None, ed(b"A")))),
397
        ];
398

            
399
        // should return the pending channel
400
        let target = FakeBuildSpec::new(ids(None, ed(b"A")));
401
        with_permutations(&channels, |x| {
402
            assert_opt_ptr_eq!(choose_best_channel(x, &target), Some(&channels[1]));
403
        });
404
    }
405

            
406
    #[test]
407
    fn best_channel_many() {
408
        // some misc channels (as we make `choose_best_channel` more complex, hopeful we can add
409
        // more channels here)
410
        let channels = [
411
            ChannelState::Open(open_channel(FakeChannel {
412
                usable: false,
413
                ids: ids(None, ed(b"A")),
414
            })),
415
            ChannelState::Open(open_channel(FakeChannel {
416
                usable: true,
417
                ids: ids(None, ed(b"A")),
418
            })),
419
            ChannelState::Building(pending_channel(ids(None, ed(b"A")))),
420
            ChannelState::Building(pending_channel(ids(None, None))),
421
        ];
422

            
423
        // should return the open+usable channel
424
        let target = FakeBuildSpec::new(ids(None, ed(b"A")));
425
        with_permutations(&channels, |x| {
426
            assert_opt_ptr_eq!(choose_best_channel(x, &target), Some(&channels[1]));
427
        });
428
    }
429

            
430
    #[test]
431
    fn test_open_channel_is_allowed() {
432
        // target with an ed relay id
433
        let target = FakeBuildSpec::new(ids(None, ed(b"A")));
434

            
435
        // not allowed: unusable channel
436
        assert!(!open_channel_is_allowed(
437
            &open_channel(FakeChannel {
438
                usable: false,
439
                ids: ids(None, ed(b"A")),
440
            }),
441
            &target,
442
        ));
443

            
444
        // allowed: usable channel with correct relay id
445
        assert!(open_channel_is_allowed(
446
            &open_channel(FakeChannel {
447
                usable: true,
448
                ids: ids(None, ed(b"A")),
449
            }),
450
            &target,
451
        ));
452

            
453
        // not allowed: usable channel with incorrect relay id
454
        assert!(!open_channel_is_allowed(
455
            &open_channel(FakeChannel {
456
                usable: true,
457
                ids: ids(None, ed(b"B")),
458
            }),
459
            &target,
460
        ));
461

            
462
        // not allowed: usable channel with no relay ids
463
        assert!(!open_channel_is_allowed(
464
            &open_channel(FakeChannel {
465
                usable: true,
466
                ids: ids(None, None),
467
            }),
468
            &target,
469
        ));
470

            
471
        // allowed: usable channel with additional relay id
472
        assert!(open_channel_is_allowed(
473
            &open_channel(FakeChannel {
474
                usable: true,
475
                ids: ids(rsa(b"X"), ed(b"A")),
476
            }),
477
            &target,
478
        ));
479

            
480
        // not allowed: usable channel with missing ed relay id
481
        assert!(!open_channel_is_allowed(
482
            &open_channel(FakeChannel {
483
                usable: true,
484
                ids: ids(rsa(b"X"), None),
485
            }),
486
            &target,
487
        ));
488

            
489
        // target with no relay id
490
        let target = FakeBuildSpec::new(ids(None, None));
491

            
492
        // not allowed: unusable channel
493
        assert!(!open_channel_is_allowed(
494
            &open_channel(FakeChannel {
495
                usable: false,
496
                ids: ids(None, None),
497
            }),
498
            &target,
499
        ));
500

            
501
        // allowed: usable channel with no relay ids
502
        assert!(open_channel_is_allowed(
503
            &open_channel(FakeChannel {
504
                usable: true,
505
                ids: ids(None, None),
506
            }),
507
            &target,
508
        ));
509

            
510
        // target with multiple relay ids
511
        let target = FakeBuildSpec::new(ids(rsa(b"X"), ed(b"A")));
512

            
513
        // not allowed: unusable channel
514
        assert!(!open_channel_is_allowed(
515
            &open_channel(FakeChannel {
516
                usable: false,
517
                ids: ids(rsa(b"X"), ed(b"A")),
518
            }),
519
            &target,
520
        ));
521

            
522
        // allowed: usable channel with correct relay ids
523
        assert!(open_channel_is_allowed(
524
            &open_channel(FakeChannel {
525
                usable: true,
526
                ids: ids(rsa(b"X"), ed(b"A")),
527
            }),
528
            &target,
529
        ));
530

            
531
        // not allowed: usable channel with partial relay ids
532
        assert!(!open_channel_is_allowed(
533
            &open_channel(FakeChannel {
534
                usable: true,
535
                ids: ids(None, ed(b"A")),
536
            }),
537
            &target,
538
        ));
539
        assert!(!open_channel_is_allowed(
540
            &open_channel(FakeChannel {
541
                usable: true,
542
                ids: ids(rsa(b"X"), None),
543
            }),
544
            &target,
545
        ));
546

            
547
        // not allowed: usable channel with one incorrect relay id
548
        assert!(!open_channel_is_allowed(
549
            &open_channel(FakeChannel {
550
                usable: true,
551
                ids: ids(rsa(b"X"), ed(b"B")),
552
            }),
553
            &target,
554
        ));
555
        assert!(!open_channel_is_allowed(
556
            &open_channel(FakeChannel {
557
                usable: true,
558
                ids: ids(rsa(b"Y"), ed(b"A")),
559
            }),
560
            &target,
561
        ));
562
    }
563

            
564
    #[test]
565
    fn test_pending_channel_maybe_allowed() {
566
        // target with an ed relay id
567
        let target = FakeBuildSpec::new(ids(None, ed(b"A")));
568

            
569
        // allowed: channel with same relay id
570
        assert!(pending_channel_maybe_allowed(
571
            &pending_channel(ids(None, ed(b"A"))),
572
            &target,
573
        ));
574

            
575
        // not allowed: channel with additional relay id
576
        assert!(!pending_channel_maybe_allowed(
577
            &pending_channel(ids(rsa(b"X"), ed(b"A"))),
578
            &target,
579
        ));
580

            
581
        // target with multiple relay ids
582
        let target = FakeBuildSpec::new(ids(rsa(b"X"), ed(b"A")));
583

            
584
        // allowed: channel with same relay ids
585
        assert!(pending_channel_maybe_allowed(
586
            &pending_channel(ids(rsa(b"X"), ed(b"A"))),
587
            &target,
588
        ));
589

            
590
        // allowed: channel with fewer relay ids
591
        assert!(pending_channel_maybe_allowed(
592
            &pending_channel(ids(None, ed(b"A"))),
593
            &target,
594
        ));
595
        assert!(pending_channel_maybe_allowed(
596
            &pending_channel(ids(rsa(b"X"), None)),
597
            &target,
598
        ));
599

            
600
        // not allowed: channel with no relay ids
601
        assert!(!pending_channel_maybe_allowed(
602
            &pending_channel(ids(None, None)),
603
            &target,
604
        ));
605

            
606
        // target with no relay ids
607
        let target = FakeBuildSpec::new(ids(None, None));
608

            
609
        // not allowed: channel with a relay id
610
        assert!(!pending_channel_maybe_allowed(
611
            &pending_channel(ids(None, ed(b"A"))),
612
            &target,
613
        ));
614

            
615
        // not allowed: channel with no relay ids
616
        assert!(!pending_channel_maybe_allowed(
617
            &pending_channel(ids(None, None)),
618
            &target,
619
        ));
620
    }
621
}