///|
/// A rectangular query domain; has no action and cannot reorder a policy.
pub struct Scope {
rule : Rule
} derive(Eq, Debug)
///|
pub fn Scope::new(
protocol : Protocol?,
source : String,
destination : String,
source_ports : Ports,
destination_ports : Ports,
) -> Scope raise PolicyError {
{
rule: Rule::new(
"scope",
Allow,
protocol,
source,
destination,
source_ports,
destination_ports,
),
}
}
///|
pub fn Scope::parse(text : String) -> Scope raise PolicyError {
if text.length() > 256 {
raise Invalid("scope too long")
}
let words = text
.trim()
.to_owned()
.split(" ")
.filter(s => s.length() > 0)
.map(s => s.to_owned())
.to_array()
match words {
[p, s, d, sp, dp] =>
Scope::new(parse_protocol(p), s, d, Ports::parse(sp), Ports::parse(dp))
_ =>
raise Invalid(
"scope requires protocol source-CIDR destination-CIDR source-ports destination-ports",
)
}
}
///|
pub fn Scope::contains(self : Scope, packet : Packet) -> Bool {
self.rule.matches(packet)
}
///|
pub fn Scope::render(self : Scope) -> String {
let r = self.rule
let proto = match r.protocol {
Some(p) => p.render()
None => "any"
}
"\{proto} \{r.source.to_string()} \{r.destination.to_string()} \{r.source_ports.render()} \{r.destination_ports.render()}"
}
///|
pub fn compare_scoped(
before : Policy,
after : Policy,
scope : Scope,
max_nodes? : Int = 100000,
) -> DiffReport raise PolicyError {
let e = Engine::new(max_nodes)
let old = e.compile(before).allowed
let next = e.compile(after).allowed
let domain = e.predicate(scope.rule)
let newly_allowed = replay_change(
e.witness(e.both(domain, e.both(e.not(old), next))),
before,
after,
Deny,
Allow,
)
let newly_denied = replay_change(
e.witness(e.both(domain, e.both(old, e.not(next)))),
before,
after,
Allow,
Deny,
)
for w in [newly_allowed, newly_denied] {
if w is Some(w) {
if !scope.contains(w.packet) {
raise Internal("internal scoped witness mismatch")
}
}
}
{
newly_allowed,
newly_denied,
retained_nodes: e.manager.retained_node_count(),
}
}
///|
pub fn Policy::find_scoped(
self : Policy,
action : Action,
scope : Scope,
max_nodes? : Int = 100000,
) -> Packet? raise PolicyError {
let e = Engine::new(max_nodes)
let c = e.compile(self)
let root = e.both(
e.predicate(scope.rule),
if action == Allow {
c.allowed
} else {
e.not(c.allowed)
},
)
let w = e.witness(root)
if w is Some(p) {
if !scope.contains(p) || self.evaluate(p).action != action {
raise Internal("internal scoped query mismatch")
}
}
w
}