1use std::fmt;
8use std::path::PathBuf;
9
10#[cfg(any(windows, test))]
11mod rules;
12#[cfg(windows)]
13mod windows;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum Profile {
18 Domain,
19 Private,
20 Public,
21}
22
23impl Profile {
24 const ALL: [Self; 3] = [Self::Domain, Self::Private, Self::Public];
25
26 #[must_use]
28 pub fn name(self) -> &'static str {
29 match self {
30 Self::Domain => "domain",
31 Self::Private => "private",
32 Self::Public => "public",
33 }
34 }
35
36 fn bit(self) -> u32 {
38 match self {
39 Self::Domain => 1,
40 Self::Private => 2,
41 Self::Public => 4,
42 }
43 }
44}
45
46impl fmt::Display for Profile {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.write_str(self.name())
49 }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
54pub struct Profiles(u32);
55
56impl Profiles {
57 pub fn iter(self) -> impl Iterator<Item = Profile> {
58 Profile::ALL
59 .into_iter()
60 .filter(move |&profile| self.has(profile))
61 }
62
63 fn has(self, profile: Profile) -> bool {
64 self.0 & profile.bit() != 0
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
70pub enum Problem {
71 MissingAllow {
73 program: PathBuf,
74 ports: Vec<u16>,
75 profiles: Profiles,
76 },
77 Blocked { rule: String, ports: Vec<u16> },
79}
80
81#[derive(Debug, thiserror::Error)]
82pub enum CheckError {
83 #[error("cannot find the path of this program: {0}")]
84 Program(#[from] std::io::Error),
85 #[error("the firewall could not be queried (HRESULT {0:#010x})")]
86 Query(i32),
87}
88
89pub const SUPPORTED: bool = cfg!(windows);
91
92pub fn check(port: u16) -> Result<Vec<Problem>, CheckError> {
100 #[cfg(windows)]
101 return windows::check(port);
102 #[cfg(not(windows))]
103 {
104 let _ = port;
105 Ok(Vec::new())
106 }
107}