use std::{borrow::Cow, collections::BTreeMap};
use crate::path::{
ScionPath,
policy::{acl::AclPolicy, hop_pattern::HopPatternPolicy},
};
pub mod acl;
pub mod hop_pattern;
pub mod types;
pub trait PathPolicy: Send + Sync + 'static {
fn path_allowed(&self, path: &ScionPath) -> Result<bool, Cow<'static, str>>;
}
#[derive(Debug, Clone)]
pub struct Policy {
pub acl: Option<AclPolicy>,
pub hop_pattern: Option<HopPatternPolicy>,
}
impl Policy {
#[inline]
pub const fn new(acl: Option<AclPolicy>, hop_pattern: Option<HopPatternPolicy>) -> Self {
Self { acl, hop_pattern }
}
#[inline]
pub fn merge_from(mut self, other: Policy) -> Self {
Self {
acl: self.acl.take().or(other.acl),
hop_pattern: self.hop_pattern.take().or(other.hop_pattern),
}
}
#[inline]
pub fn matches(&self, path: &[types::PathPolicyHop]) -> bool {
self.hop_pattern
.as_ref()
.map(|seq| seq.matches(path))
.unwrap_or(true)
&& self
.acl
.as_ref()
.map(|acl| acl.matches(path))
.unwrap_or(true)
}
}
impl PathPolicy for Policy {
#[inline]
fn path_allowed(&self, path: &ScionPath) -> Result<bool, Cow<'static, str>> {
let path_hops = types::PathPolicyHop::hops_from_path(path).map_err(Cow::from)?;
Ok(self.matches(&path_hops))
}
}
#[derive(Debug, Clone)]
pub struct WeightedPolicies {
pub policies: BTreeMap<u8, Policy>,
}
impl WeightedPolicies {
#[inline]
pub fn new(policies: impl IntoIterator<Item = (u8, Policy)>) -> Self {
Self {
policies: policies.into_iter().collect(),
}
}
#[inline]
pub fn add_policy(&mut self, policy: Policy, weight: u8) -> Option<Policy> {
self.policies.insert(weight, policy)
}
#[inline]
pub fn match_highest(&self, path: &[types::PathPolicyHop]) -> Option<&Policy> {
self.policies
.values()
.rev()
.find(|&policy| policy.matches(path))
}
}