use crate::value::Value;
use alloc::string::ToString as _;
use super::common;
use super::evaluator::RbacBuiltinError;
#[cfg(feature = "net")]
use core::net::IpAddr;
#[cfg(feature = "net")]
use ipnet::IpNet;
pub(super) fn ip_match(
left: &Value,
right: &Value,
name: &'static str,
) -> Result<bool, RbacBuiltinError> {
let ip_str = common::value_as_string(left, name)?;
let cidr_str = common::value_as_string(right, name)?;
#[cfg(feature = "net")]
{
let net = cidr_str
.parse::<IpNet>()
.map_err(|err| RbacBuiltinError::new(err.to_string()))?;
let ip = ip_str
.parse::<IpAddr>()
.map_err(|err| RbacBuiltinError::new(err.to_string()))?;
Ok(net.contains(&ip))
}
#[cfg(not(feature = "net"))]
{
Err(RbacBuiltinError::new("IP builtins have not been enabled"))
}
}
pub(super) fn ip_in_range(
left: &Value,
right: &Value,
name: &'static str,
) -> Result<bool, RbacBuiltinError> {
match *right {
Value::Array(ref list) if list.len() == 2 => {
let start = list
.first()
.ok_or_else(|| RbacBuiltinError::new("IpInRange expects 2 values"))?;
let end = list
.get(1)
.ok_or_else(|| RbacBuiltinError::new("IpInRange expects 2 values"))?;
let start = common::value_as_string(start, name)?;
let end = common::value_as_string(end, name)?;
ip_between(left, &start, &end, name)
}
_ => ip_match(left, right, name),
}
}
fn ip_between(
left: &Value,
start: &str,
end: &str,
name: &'static str,
) -> Result<bool, RbacBuiltinError> {
let ip_str = common::value_as_string(left, name)?;
#[cfg(feature = "net")]
{
let ip = ip_str
.parse::<IpAddr>()
.map_err(|err| RbacBuiltinError::new(err.to_string()))?;
let start_ip = start
.parse::<IpAddr>()
.map_err(|err| RbacBuiltinError::new(err.to_string()))?;
let end_ip = end
.parse::<IpAddr>()
.map_err(|err| RbacBuiltinError::new(err.to_string()))?;
Ok(start_ip <= ip && ip <= end_ip)
}
#[cfg(not(feature = "net"))]
{
Err(RbacBuiltinError::new("IP builtins have not been enabled"))
}
}