1
//! Implement GuardFilter and related types.
2

            
3
use educe::Educe;
4

            
5
use tor_linkspec::ChanTarget;
6

            
7
/// An object specifying which relays are eligible to be guards.
8
///
9
/// We _always_ restrict the set of possible guards to be the set of
10
/// relays currently listed in the consensus directory document, and
11
/// tagged with the `Guard` flag.  But clients may narrow the eligible set
12
/// even further—for example, to those supporting only a given set of ports,
13
/// or to those in a given country.
14
///
15
/// # Limitations
16
///
17
/// Right now, only the `Unrestricted` filter is implemented or available.
18
/// This enumeration is just a place-holder, however, to make sure we're
19
/// checking our filter in the right places.
20
38
#[derive(Debug, Clone, Educe)]
21
#[educe(Default)]
22
#[non_exhaustive]
23
pub enum GuardFilter {
24
    /// A filter representing no restrictions on the permissible guards
25
    /// at all.
26
    #[educe(Default)]
27
    Unfiltered,
28

            
29
    /// Testing only: checks whether the first byte of the rsa key is 0 modulo 4.
30
    ///
31
    /// TODO: remove this once real filters are implemented.
32
    #[cfg(test)]
33
    #[allow(dead_code)]
34
    TestingLimitKeys,
35
}
36

            
37
impl GuardFilter {
38
    /// Create a new [`GuardFilter`] that doesn't restrict the set of
39
    /// permissible guards at all.
40
    pub fn unfiltered() -> Self {
41
        GuardFilter::Unfiltered
42
    }
43

            
44
    /// Return true if this filter permits the provided `target`.
45
71723
    pub(crate) fn permits<C: ChanTarget>(&self, target: &C) -> bool {
46
71723
        let _ = target; // ignored for now, since only Unfiltered exists.
47
71723
        match self {
48
71594
            GuardFilter::Unfiltered => true,
49
70845
            #[cfg(test)]
50
70974
            GuardFilter::TestingLimitKeys => target.rsa_identity().as_bytes()[0] & 3 == 0,
51
70845
        }
52
71723
    }
53

            
54
    /// Return true if this filter excludes no guards at all.
55
143
    pub(crate) fn is_unfiltered(&self) -> bool {
56
143
        matches!(self, GuardFilter::Unfiltered)
57
143
    }
58
}