use std::net::IpAddr;
pub fn ip_allowed(ip: IpAddr, allow: &[ipnet::IpNet], deny: &[ipnet::IpNet]) -> bool {
if !allow.is_empty() && !allow.iter().any(|net| net.contains(&ip)) {
return false;
}
if deny.iter().any(|net| net.contains(&ip)) {
return false;
}
true
}
#[cfg(test)]
mod tests {
use super::*;
fn ip(s: &str) -> IpAddr {
s.parse().unwrap()
}
fn net(s: &str) -> ipnet::IpNet {
s.parse().unwrap()
}
#[test]
fn empty_allow_empty_deny_permits_all() {
assert!(ip_allowed(ip("10.0.0.1"), &[], &[]));
assert!(ip_allowed(ip("198.51.100.1"), &[], &[]));
}
#[test]
fn deny_cidr_blocks_ip() {
let deny = vec![net("10.0.0.0/8")];
assert!(!ip_allowed(ip("10.0.0.1"), &[], &deny));
assert!(ip_allowed(ip("198.51.100.1"), &[], &deny));
}
#[test]
fn allow_cidr_restricts_to_subnet() {
let allow = vec![net("10.0.0.0/8")];
assert!(ip_allowed(ip("10.0.0.1"), &allow, &[]));
assert!(!ip_allowed(ip("198.51.100.1"), &allow, &[]));
}
#[test]
fn deny_takes_precedence_over_allow() {
let allow = vec![net("10.0.0.0/8")];
let deny = vec![net("10.0.0.0/24")];
assert!(!ip_allowed(ip("10.0.0.1"), &allow, &deny));
assert!(ip_allowed(ip("10.1.0.1"), &allow, &deny));
}
}