GuardMgr: Add a new filter type based on reachable addresses.

This commit is contained in:
Nick Mathewson 2022-06-01 10:00:49 -04:00
parent 801b6bec5f
commit 9c4f31edc1
2 changed files with 24 additions and 8 deletions

View File

@ -39,6 +39,7 @@ tor-error = { path = "../tor-error", version = "0.3.1" }
tor-linkspec = { path = "../tor-linkspec", version = "0.3.0" }
tor-llcrypto = { path = "../tor-llcrypto", version = "0.3.0" }
tor-netdir = { path = "../tor-netdir", version = "0.3.0" }
tor-netdoc = { path = "../tor-netdoc", version = "0.4.0" } # for address pattern
tor-persist = { path = "../tor-persist", version = "0.4.0" }
tor-proto = { path = "../tor-proto", version = "0.3.1" }
tor-rtcompat = { path = "../tor-rtcompat", version = "0.4.0" }

View File

@ -1,6 +1,9 @@
//! Implement GuardFilter and related types.
use tor_linkspec::ChanTarget;
// TODO(nickm): Conceivably, this type should be exposed from a lower-level crate than
// tor-netdoc.
use tor_netdoc::types::policy::AddrPortPattern;
/// An object specifying which relays are eligible to be guards.
///
@ -20,12 +23,21 @@ 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.
///
/// This list of filters has "and" semantics: a relay is permitted by this
/// filter if ALL patterns in this list permit that first hop.
filters: Vec<SingleFilter>,
}
/// A single restriction places upon usable guards.
#[derive(Debug, Clone)]
enum SingleFilter {
/// A set of allowable addresses that we are willing to try to connect to.
///
/// This list of patterns has "or" semantics: a guard is permitted by this filter
/// if ANY pattern in this list permits one of the guard's addresses.
ReachableAddrs(Vec<AddrPortPattern>),
/// Testing only: checks whether the first byte of the rsa key is 0 modulo 4.
///
/// TODO: remove this once real filters are implemented.
@ -41,6 +53,13 @@ impl GuardFilter {
GuardFilter::default()
}
/// Restrict this filter to only permit connections to an address permitted
/// by one of the patterns in `addrs`.
pub fn push_reachable_addresses(&mut self, addrs: impl IntoIterator<Item = AddrPortPattern>) {
self.filters
.push(SingleFilter::ReachableAddrs(addrs.into_iter().collect()));
}
/// Return true if this filter permits the provided `target`.
pub(crate) fn permits<C: ChanTarget>(&self, target: &C) -> bool {
self.filters.iter().all(|filt| filt.permits(target))
@ -64,16 +83,12 @@ impl GuardFilter {
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::ReachableAddrs(patterns) => patterns
.iter()
.any(|pat| target.addrs().iter().any(|addr| pat.matches_sockaddr(addr))),
#[cfg(test)]
SingleFilter::TestingLimitKeys => target.rsa_identity().as_bytes()[0] & 3 == 0,
}
#[cfg(not(test))]
{
let _ = target;
true
}
}
}