From 4205a332a74318a682f514e4f5d1f3672b83887c Mon Sep 17 00:00:00 2001 From: futile Date: Fri, 12 Dec 2025 07:16:05 +0000 Subject: [PATCH] add firewall helper util --- src/util.rs | 1 + src/util/firewall.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/util/firewall.rs diff --git a/src/util.rs b/src/util.rs index a04b640..a06c828 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,6 @@ pub mod consts; pub mod countdown; +pub mod firewall; pub mod logging; pub mod persistent_state; pub mod system_info; diff --git a/src/util/firewall.rs b/src/util/firewall.rs new file mode 100644 index 0000000..1ece93b --- /dev/null +++ b/src/util/firewall.rs @@ -0,0 +1,78 @@ +use std::{error::Error, path::PathBuf}; +use windows::{ + Win32::{ + NetworkManagement::WindowsFirewall::{ + INetFwPolicy2, INetFwRule, NET_FW_ACTION_BLOCK, NET_FW_IP_PROTOCOL_ANY, + NET_FW_IP_PROTOCOL_TCP, NET_FW_IP_PROTOCOL_UDP, NET_FW_RULE_DIR_IN, + NET_FW_RULE_DIR_OUT, NetFwPolicy2, NetFwRule, + }, + System::Com::{CLSCTX_INPROC_SERVER, CoCreateInstance}, + }, + core::BSTR, +}; + +pub struct Firewall { + policy: INetFwPolicy2, +} + +impl Firewall { + pub fn new() -> Result> { + Ok(Self { + policy: unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }?, + }) + } + + pub fn add( + &self, + name: &str, + mode: RuleMode, + direction: RuleDirection, + protocol: RuleProtocol, + ) -> Result<(), Box> { + let rules = unsafe { self.policy.Rules() }?; + unsafe { rules.Remove(&BSTR::from(name)) }?; + let rule: INetFwRule = unsafe { CoCreateInstance(&NetFwRule, None, CLSCTX_INPROC_SERVER) }?; + unsafe { rule.SetName(&BSTR::from(name)) }?; + match mode { + RuleMode::Executable(exe) => { + unsafe { rule.SetApplicationName(&BSTR::from(exe.to_string_lossy().to_string())) }? + } + RuleMode::Address(ip) => unsafe { rule.SetRemoteAddresses(&BSTR::from(ip)) }?, + } + match direction { + RuleDirection::In => unsafe { rule.SetDirection(NET_FW_RULE_DIR_IN) }?, + RuleDirection::Out => unsafe { rule.SetDirection(NET_FW_RULE_DIR_OUT) }?, + } + unsafe { rule.SetEnabled(true.into()) }?; + unsafe { rule.SetAction(NET_FW_ACTION_BLOCK) }?; + match protocol { + RuleProtocol::Any => unsafe { rule.SetProtocol(NET_FW_IP_PROTOCOL_ANY.0) }?, + RuleProtocol::Tcp => unsafe { rule.SetProtocol(NET_FW_IP_PROTOCOL_TCP.0) }?, + RuleProtocol::Udp => unsafe { rule.SetProtocol(NET_FW_IP_PROTOCOL_UDP.0) }?, + } + unsafe { rules.Add(&rule) }?; + Ok(()) + } + + pub fn remove(&self, name: &str) -> Result<(), Box> { + let rules = unsafe { self.policy.Rules() }?; + unsafe { rules.Remove(&BSTR::from(name)) }?; + Ok(()) + } +} + +pub enum RuleMode { + Executable(PathBuf), + Address(String), +} + +pub enum RuleDirection { + In, + Out, +} + +pub enum RuleProtocol { + Any, + Tcp, + Udp, +}