v0.26.6
This commit is contained in:
1 parent
464ff42cfd
commit
f07429c267
53 files changed
+1049
-283
No files matched your search
+62
-9
@@ -13,6 +13,18 @@ pub enum Action {
|
||||
fn deny() -> Action {
|
||||
Action::Deny
|
||||
}
|
||||
fn parse_network(value: &str) -> Result<IpNet> {
|
||||
if let Ok(network) = value.parse::<IpNet>() {
|
||||
return Ok(network);
|
||||
}
|
||||
let ip: IpAddr = value
|
||||
.parse()
|
||||
.context("ACL requires an IPv4/IPv6 address or CIDR")?;
|
||||
let prefix = if ip.is_ipv4() { 32 } else { 128 };
|
||||
format!("{ip}/{prefix}")
|
||||
.parse::<IpNet>()
|
||||
.context("ACL requires an IPv4/IPv6 address or CIDR")
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Rule {
|
||||
@@ -38,10 +50,7 @@ impl Acl {
|
||||
let mut rules = Vec::with_capacity(self.rules.len());
|
||||
for rule in &self.rules {
|
||||
ensure!(rule.network.len() <= 64, "ACL network is too long");
|
||||
let network: IpNet = rule
|
||||
.network
|
||||
.parse()
|
||||
.context("ACL requires an IPv4/IPv6 CIDR")?;
|
||||
let network = parse_network(&rule.network)?;
|
||||
if let IpNet::V6(net) = network {
|
||||
ensure!(
|
||||
net.addr().to_ipv4_mapped().is_none(),
|
||||
@@ -57,9 +66,7 @@ impl Acl {
|
||||
}
|
||||
}
|
||||
impl CompiledAcl {
|
||||
/// Explicit deny beats all matching allow rules. Otherwise, allow or the default applies.
|
||||
/// Host policy and route policy are both evaluated, so route allow cannot override host deny.
|
||||
pub fn allows(&self, peer: IpAddr) -> bool {
|
||||
fn explicit_action(&self, peer: IpAddr) -> Option<Action> {
|
||||
let peer = match peer {
|
||||
IpAddr::V6(v6) => v6.to_ipv4_mapped().map(IpAddr::V4).unwrap_or(peer),
|
||||
_ => peer,
|
||||
@@ -68,12 +75,58 @@ impl CompiledAcl {
|
||||
for (network, action) in &self.rules {
|
||||
if network.contains(&peer) {
|
||||
if *action == Action::Deny {
|
||||
return false;
|
||||
return Some(Action::Deny);
|
||||
}
|
||||
allowed = true;
|
||||
}
|
||||
}
|
||||
allowed || self.default == Action::Allow
|
||||
allowed.then_some(Action::Allow)
|
||||
}
|
||||
|
||||
/// Explicit deny beats all matching allow rules. Otherwise, allow or the default applies.
|
||||
/// Host policy and route policy are both evaluated, so route allow cannot override host deny.
|
||||
pub fn allows(&self, peer: IpAddr) -> bool {
|
||||
match self.explicit_action(peer) {
|
||||
Some(Action::Deny) => false,
|
||||
Some(Action::Allow) => true,
|
||||
None => self.default == Action::Allow,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate the IP and country controls that belong to one access-policy scope.
|
||||
/// Explicit IP denies and blocked countries always deny. In allow-only country mode,
|
||||
/// a listed country or an explicit IP allow is sufficient; this lets a default-deny
|
||||
/// policy express e.g. "private networks OR PL/DE" without weakening other scopes.
|
||||
pub fn allows_with_country(
|
||||
acl: Option<&CompiledAcl>,
|
||||
countries: &crate::rate_limit::CountryAccess,
|
||||
peer: IpAddr,
|
||||
country: Option<&str>,
|
||||
) -> bool {
|
||||
let ip_action = acl.and_then(|value| value.explicit_action(peer));
|
||||
if ip_action == Some(Action::Deny) {
|
||||
return false;
|
||||
}
|
||||
let country_listed = country.is_some_and(|code| {
|
||||
countries
|
||||
.countries
|
||||
.iter()
|
||||
.any(|item| item.eq_ignore_ascii_case(code))
|
||||
});
|
||||
match countries.mode {
|
||||
crate::rate_limit::CountryMode::Off => {
|
||||
ip_action == Some(Action::Allow)
|
||||
|| acl.is_none_or(|value| value.default == Action::Allow)
|
||||
}
|
||||
crate::rate_limit::CountryMode::Block => {
|
||||
!country_listed
|
||||
&& (ip_action == Some(Action::Allow)
|
||||
|| acl.is_none_or(|value| value.default == Action::Allow))
|
||||
}
|
||||
crate::rate_limit::CountryMode::Allow => {
|
||||
ip_action == Some(Action::Allow) || country_listed
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Validate the already-decoded routing representation used internally after
|
||||
|
||||
Reference in new issue
Block a user