mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
feat: implement net.cidr_expand builtin
Signed-off-by: tjons <tylerschade99@gmail.com>
This commit is contained in:
@@ -304,7 +304,6 @@ The following test suites don't pass fully due to missing builtins:
|
|||||||
- `jwtverifyhs512`
|
- `jwtverifyhs512`
|
||||||
- `jwtverifyrsa`
|
- `jwtverifyrsa`
|
||||||
- `netcidrcontainsmatches`
|
- `netcidrcontainsmatches`
|
||||||
- `netcidrexpand`
|
|
||||||
- `netcidrintersects`
|
- `netcidrintersects`
|
||||||
- `netcidrmerge`
|
- `netcidrmerge`
|
||||||
- `netcidroverlap`
|
- `netcidroverlap`
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use core::net::IpAddr;
|
use core::net::IpAddr;
|
||||||
use ipnet::IpNet;
|
use ipnet::IpNet;
|
||||||
use std::format;
|
use std::format;
|
||||||
|
use std::string::ToString;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
use crate::ast::{Expr, Ref};
|
use crate::ast::{Expr, Ref};
|
||||||
use crate::builtins;
|
use crate::builtins;
|
||||||
@@ -16,6 +18,7 @@ use super::utils::ensure_string;
|
|||||||
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
||||||
m.insert("net.cidr_is_valid", (cidr_is_valid, 1));
|
m.insert("net.cidr_is_valid", (cidr_is_valid, 1));
|
||||||
m.insert("net.cidr_contains", (cidr_contains, 2));
|
m.insert("net.cidr_contains", (cidr_contains, 2));
|
||||||
|
m.insert("net.cidr_expand", (cidr_expand, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a CIDR string is valid or invalid. Uses the
|
/// Checks if a CIDR string is valid or invalid. Uses the
|
||||||
@@ -62,6 +65,7 @@ fn is_valid_cidr(cidr: Arc<str>) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if a CIDR string contains a given CIDR or individual network address.
|
||||||
pub fn cidr_contains(
|
pub fn cidr_contains(
|
||||||
span: &Span,
|
span: &Span,
|
||||||
params: &[Ref<Expr>],
|
params: &[Ref<Expr>],
|
||||||
@@ -106,10 +110,42 @@ fn _cidr_contains(cidr: Arc<str>, cidr_or_ip: Arc<str>) -> Result<bool> {
|
|||||||
Ok(net.contains(&subnet))
|
Ok(net.contains(&subnet))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cidr_expand(
|
||||||
|
span: &Span,
|
||||||
|
params: &[Ref<Expr>],
|
||||||
|
args: &[Value],
|
||||||
|
_strict: bool,
|
||||||
|
) -> Result<Value> {
|
||||||
|
ensure_args_count(span, "cidr_expand", params, args, 1)?;
|
||||||
|
let cidr = ensure_string("cidr_expand", ¶ms[0], &args[0])?;
|
||||||
|
|
||||||
|
_cidr_expand(cidr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _cidr_expand(cidr: Arc<str>) -> Result<Value> {
|
||||||
|
let net = cidr
|
||||||
|
.parse::<IpNet>()
|
||||||
|
.map_err(|e| anyhow!("Error parsing {cidr}: {e}"))?;
|
||||||
|
|
||||||
|
let mut hosts: Vec<Value> = net
|
||||||
|
.hosts()
|
||||||
|
.map(|h| Value::String(h.to_string().into()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// the IpNet library has some different behavior regarding CIDR expansion from the go implementation
|
||||||
|
// that OPA uses; it will exclude the IPv4 CIDR network address and broadcast address when the netmask < 31.
|
||||||
|
// Adjust accordingly for parity.
|
||||||
|
if matches!(net, IpNet::V4(_) if net.prefix_len() < 31) {
|
||||||
|
hosts.push(net.broadcast().to_string().into());
|
||||||
|
hosts.insert(0, net.network().to_string().into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Array(Arc::from(hosts)))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod net_tests {
|
mod net_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cidr_is_valid() {
|
fn test_cidr_is_valid() {
|
||||||
@@ -184,4 +220,24 @@ mod net_tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cidr_expand() {
|
||||||
|
let cases = Vec::from([
|
||||||
|
("127.0.0.1/32", Vec::from(["127.0.0.1"])),
|
||||||
|
(
|
||||||
|
"10.0.0.0/29",
|
||||||
|
Vec::from([
|
||||||
|
"10.0.0.0", "10.0.0.1", "10.0.0.2", "10.0.0.3", "10.0.0.4", "10.0.0.5",
|
||||||
|
"10.0.0.6", "10.0.0.7",
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (cidr, exp) in cases {
|
||||||
|
let cidrs = _cidr_expand(cidr.into()).expect("CIDRs should be returned");
|
||||||
|
let expv = Value::from(exp.iter().map(|s| Value::from(*s)).collect::<Vec<Value>>());
|
||||||
|
assert_eq!(cidrs, expv);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ v0/negation
|
|||||||
v0/nestedreferences
|
v0/nestedreferences
|
||||||
v0/netcidrisvalid
|
v0/netcidrisvalid
|
||||||
v0/netcidrcontains
|
v0/netcidrcontains
|
||||||
|
v0/netcidrexpand
|
||||||
v0/numbersrange
|
v0/numbersrange
|
||||||
v0/numbersrangestep
|
v0/numbersrangestep
|
||||||
v0/objectfilter
|
v0/objectfilter
|
||||||
@@ -153,6 +154,7 @@ v1/negation
|
|||||||
v1/nestedreferences
|
v1/nestedreferences
|
||||||
v1/netcidrcontains
|
v1/netcidrcontains
|
||||||
v1/netcidrisvalid
|
v1/netcidrisvalid
|
||||||
|
v1/netcidrexpand
|
||||||
v1/numbersrange
|
v1/numbersrange
|
||||||
v1/numbersrangestep
|
v1/numbersrangestep
|
||||||
v1/objectfilter
|
v1/objectfilter
|
||||||
|
|||||||
Reference in New Issue
Block a user