pub fn judge_ufw(status: &str, plan: &FirewallPlan) -> FirewallObservationExpand description
Judge ufw status output against the plan. Pure.
A rule is admitted when, for each of its sources (or once, for any source), a line
allows its port/proto inbound from that network or from anywhere, to its group when
it has one.
use std::net::Ipv4Addr;
use majordomus_cli::mesh::firewall::{judge_ufw, plan, FirewallObservationState};
use majordomus_cli::mesh::MeshConfig;
let config: MeshConfig = serde_json::from_value(serde_json::json!({
"schema": "mesh/v1", "kind": "mesh-declaration", "id": "doc", "enabled": true,
"rendezvous": { "endpoints": ["http://192.168.7.10:8791", "http://100.64.1.2:8791"] },
})).unwrap();
let p = plan(Some(&config), &[Ipv4Addr::new(192, 168, 7, 10)], None);
let before = "Status: active\n\nTo Action From\n-- ------ ----\n22/tcp ALLOW IN Anywhere\n";
let o = judge_ufw(before, &p);
assert_eq!(o.state, FirewallObservationState::Missing);
assert_eq!(o.missing.len(), 2);
let after = "Status: active\n\nTo Action From\n-- ------ ----\n22/tcp ALLOW IN Anywhere\n239.255.77.77 7741/udp ALLOW IN Anywhere # majordomus mesh: multicast discovery\n8791/tcp ALLOW IN 192.168.7.0/24 # majordomus mesh: rendezvous hub\n8791/tcp ALLOW IN 100.64.0.0/10 # majordomus mesh: rendezvous hub\n";
assert_eq!(judge_ufw(after, &p).state, FirewallObservationState::Present);
// `ufw status` without `verbose` prints the action as `ALLOW`; it is the same rule
let terse = "Status: active\n239.255.77.77 7741/udp ALLOW Anywhere\n8791/tcp ALLOW 192.168.7.0/24\n8791/tcp ALLOW 100.64.0.0/10\n";
assert_eq!(judge_ufw(terse, &p).state, FirewallObservationState::Present);
// a wider admission counts: anywhere covers every network
let wide = "Status: active\n239.255.77.77 7741/udp ALLOW IN Anywhere\n8791/tcp ALLOW IN Anywhere\n";
assert_eq!(judge_ufw(wide, &p).state, FirewallObservationState::Present);
assert_eq!(judge_ufw("Status: inactive\n", &p).state, FirewallObservationState::Inactive);
assert_eq!(judge_ufw("ERROR: You need to be root to run this script\n", &p).state, FirewallObservationState::Unobservable);