1use std::net::Ipv4Addr;
8
9pub const DISCOVERY_PORT: u16 = 58199;
10pub const RECEIVER_PORT: u16 = 58200;
11
12#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
14pub struct FirewallStatus {
15 pub os: String,
16 pub active: bool,
17 pub ports_open: bool,
18 pub commands: Vec<String>,
19}
20
21pub fn ufw_ports_open(status: &str) -> (bool, bool) {
33 let active = status.lines().any(|l| l.trim().starts_with("Status: active"));
34 let mut udp = false;
35 let mut tcp = false;
36 for l in status.lines() {
37 let t = l.trim();
38 if let Some(rest) = t.strip_prefix("58199/udp") {
39 udp = rest.trim_start().starts_with("ALLOW");
40 } else if let Some(rest) = t.strip_prefix("58200/udp") {
41 tcp = rest.trim_start().starts_with("ALLOW");
42 }
43 }
44 (active, udp && tcp)
45}
46
47pub fn firewalld_ports_open(ports: &str) -> bool {
50 let mut discovery = false;
51 let mut receiver = false;
52 for p in ports.split_whitespace() {
53 if p == format!("{DISCOVERY_PORT}/udp") {
54 discovery = true;
55 } else if p == format!("{RECEIVER_PORT}/udp") {
56 receiver = true;
57 }
58 }
59 discovery && receiver
60}
61
62pub fn commands_for(fw: &str) -> Vec<String> {
65 match fw {
66 "ufw" => vec![
67 format!("sudo ufw allow {DISCOVERY_PORT}/udp"),
68 format!("sudo ufw allow {RECEIVER_PORT}/udp"),
69 ],
70 "firewalld" => vec![
71 format!("sudo firewall-cmd --permanent --add-port={DISCOVERY_PORT}/udp"),
72 format!("sudo firewall-cmd --permanent --add-port={RECEIVER_PORT}/udp"),
73 "sudo firewall-cmd --reload".to_string(),
74 ],
75 "windows" => vec![
76 format!(
77 "netsh advfirewall firewall add rule name=\"Toolé UDP\" dir=in action=allow protocol=UDP localport={DISCOVERY_PORT},{RECEIVER_PORT} profile=private,domain"
78 ),
79 ],
80 _ => vec![],
81 }
82}
83
84pub fn linux_status(ufw_active: bool, ufw_open: bool, fw_active: bool, fw_open: bool) -> FirewallStatus {
90 let active = ufw_active || fw_active;
91 let ports_open = if !active {
94 true
95 } else if ufw_active {
96 ufw_open
97 } else {
98 fw_open
99 };
100 let commands = if ufw_active {
101 commands_for("ufw")
102 } else if fw_active {
103 commands_for("firewalld")
104 } else {
105 vec![]
106 };
107 FirewallStatus {
108 os: "linux".to_string(),
109 active,
110 ports_open,
111 commands,
112 }
113}
114
115pub fn is_manual_ipv4_allowed(ip: Ipv4Addr) -> bool {
119 if ip.is_loopback() || ip.is_unspecified() || ip.is_multicast() {
120 return false;
121 }
122 let octets = ip.octets();
123 matches!(
124 octets,
125 [10, _, _, _] | [172, 16..=31, _, _] | [192, 168, _, _] | [169, 254, _, _]
126 )
127}