From a720f4f667d25dc82386baf5233f34ac84113469 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 8 Jun 2022 09:05:38 -0400 Subject: [PATCH] GuardMgr: Function to tell how permissive a filter is. When we're filtering guards, we have to check whether the filter is "restrictive": if it forbids most of the guards (by bandwidth), we keep its guards separated from the main set. If it is super-restrictive, we also warn. This functionality is specified in guard-spec.txt. --- crates/tor-guardmgr/src/filter.rs | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/crates/tor-guardmgr/src/filter.rs b/crates/tor-guardmgr/src/filter.rs index d630bfffb..680b5a624 100644 --- a/crates/tor-guardmgr/src/filter.rs +++ b/crates/tor-guardmgr/src/filter.rs @@ -79,6 +79,26 @@ impl GuardFilter { pub(crate) fn is_unfiltered(&self) -> bool { self.filters.is_empty() } + + /// Return a fraction between 0.0 and 1.0 describing what fraction of the + /// guard bandwidth this filter permits. + #[allow(dead_code)] + pub(crate) fn frac_bw_permitted(&self, netdir: &tor_netdir::NetDir) -> f64 { + use tor_netdir::{RelayWeight, WeightRole}; + let mut guard_bw: RelayWeight = 0.into(); + let mut permitted_bw: RelayWeight = 0.into(); + for relay in netdir.relays() { + if relay.is_flagged_guard() { + let w = netdir.relay_weight(&relay, WeightRole::Guard); + guard_bw += w; + if self.permits(&relay) { + permitted_bw += w; + } + } + } + + permitted_bw.checked_div(guard_bw).unwrap_or(1.0) + } } impl SingleFilter { @@ -112,3 +132,33 @@ impl SingleFilter { Ok(first_hop) } } + +#[cfg(test)] +mod test { + #![allow(clippy::unwrap_used)] + use super::*; + use float_eq::assert_float_eq; + use tor_netdir::testnet; + + #[test] + fn permissiveness() { + let nd = testnet::construct_netdir().unwrap_if_sufficient().unwrap(); + const TOL: f64 = 0.01; + + let non_filter = GuardFilter::default(); + assert_float_eq!(non_filter.frac_bw_permitted(&nd), 1.0, abs <= TOL); + + let forbid_all = { + let mut f = GuardFilter::default(); + f.push_reachable_addresses(vec!["*:1".parse().unwrap()]); + f + }; + assert_float_eq!(forbid_all.frac_bw_permitted(&nd), 0.0, abs <= TOL); + let net_1_only = { + let mut f = GuardFilter::default(); + f.push_reachable_addresses(vec!["1.0.0.0/8:*".parse().unwrap()]); + f + }; + assert_float_eq!(net_1_only.frac_bw_permitted(&nd), 54.0 / 330.0, abs <= TOL); + } +}