Guardmgr: Change the GuardFilter API.

The guard filter is now a set of restrictions that can be placed on
allowable guards.
This commit is contained in:
Nick Mathewson 2022-06-01 09:26:43 -04:00
parent 60eaabfb37
commit 801b6bec5f
3 changed files with 46 additions and 19 deletions

View File

@ -0,0 +1 @@
BREAKING: GuardFilter is no longer an enum.

View File

@ -1,7 +1,5 @@
//! Implement GuardFilter and related types.
use educe::Educe;
use tor_linkspec::ChanTarget;
/// An object specifying which relays are eligible to be guards.
@ -17,15 +15,17 @@ use tor_linkspec::ChanTarget;
/// Right now, only the `Unrestricted` filter is implemented or available.
/// This enumeration is just a place-holder, however, to make sure we're
/// checking our filter in the right places.
#[derive(Debug, Clone, Educe)]
#[educe(Default)]
#[non_exhaustive]
pub enum GuardFilter {
/// A filter representing no restrictions on the permissible guards
/// at all.
#[educe(Default)]
Unfiltered,
#[derive(Debug, Clone, Default)]
pub struct GuardFilter {
/// A list of filters to apply to guard or fallback selection. Each filter
/// restricts which guards may be used, and possibly how those guards may be
/// contacted.
filters: Vec<SingleFilter>,
}
/// A single restriction places upon usable guards.
#[derive(Debug, Clone)]
enum SingleFilter {
/// Testing only: checks whether the first byte of the rsa key is 0 modulo 4.
///
/// TODO: remove this once real filters are implemented.
@ -38,21 +38,42 @@ impl GuardFilter {
/// Create a new [`GuardFilter`] that doesn't restrict the set of
/// permissible guards at all.
pub fn unfiltered() -> Self {
GuardFilter::Unfiltered
GuardFilter::default()
}
/// Return true if this filter permits the provided `target`.
pub(crate) fn permits<C: ChanTarget>(&self, target: &C) -> bool {
let _ = target; // ignored for now, since only Unfiltered exists.
match self {
GuardFilter::Unfiltered => true,
#[cfg(test)]
GuardFilter::TestingLimitKeys => target.rsa_identity().as_bytes()[0] & 3 == 0,
}
self.filters.iter().all(|filt| filt.permits(target))
}
/// Return true if this filter excludes no guards at all.
pub(crate) fn is_unfiltered(&self) -> bool {
matches!(self, GuardFilter::Unfiltered)
self.filters.is_empty()
}
/// Add a restriction to this filter that keys must have their final two
/// bits of their first byte are set to 0.
///
/// TODO: this testing-only, and is getting killed off once we have real filter
#[cfg(test)]
pub(crate) fn push_key_limit(&mut self) {
self.filters.push(SingleFilter::TestingLimitKeys);
}
}
impl SingleFilter {
/// Return true if this filter permits the provided target.
fn permits<C: ChanTarget>(&self, target: &C) -> bool {
// TODO: This is ugly, but the whole function will get rewritten once we
// have a real filter.
#[cfg(test)]
match self {
SingleFilter::TestingLimitKeys => target.rsa_identity().as_bytes()[0] & 3 == 0,
}
#[cfg(not(test))]
{
let _ = target;
true
}
}
}

View File

@ -1481,7 +1481,12 @@ mod test {
let (guardmgr, _statemgr, netdir) = init(rt);
let u = GuardUsage::default();
guardmgr.update_network(&netdir);
guardmgr.set_filter(GuardFilter::TestingLimitKeys, &netdir);
let filter = {
let mut f = GuardFilter::default();
f.push_key_limit();
f
};
guardmgr.set_filter(filter, &netdir);
let (guard, _mon, _usable) = guardmgr.select_guard(u, Some(&netdir)).unwrap();
// Make sure that the filter worked.