From 23fd4b12f9b40d03f9357a21b21ad5368daeb846 Mon Sep 17 00:00:00 2001 From: futile Date: Fri, 12 Dec 2025 07:42:20 +0000 Subject: [PATCH] use `Firewall` in `game_networking` --- src/features/game_networking.rs | 135 +++++++++++--------------------- src/gui/app.rs | 16 +++- src/util/firewall.rs | 1 + 3 files changed, 60 insertions(+), 92 deletions(-) diff --git a/src/features/game_networking.rs b/src/features/game_networking.rs index 413f7cf..568abeb 100644 --- a/src/features/game_networking.rs +++ b/src/features/game_networking.rs @@ -1,15 +1,11 @@ -use crate::{gui::settings::BlockMethod, util::system_info::SystemInfo}; -use std::{error::Error, path::PathBuf}; -use windows::{ - Win32::{ - NetworkManagement::WindowsFirewall::{ - INetFwPolicy2, INetFwRule, NET_FW_ACTION_BLOCK, NET_FW_IP_PROTOCOL_ANY, - NET_FW_RULE_DIR_OUT, NetFwPolicy2, NetFwRule, - }, - System::Com::{CLSCTX_INPROC_SERVER, CoCreateInstance}, +use crate::{ + gui::settings::BlockMethod, + util::{ + firewall::{Firewall, RuleDirection, RuleMode, RuleProtocol}, + system_info::SystemInfo, }, - core::BSTR, }; +use std::error::Error; const FILTER_NAME_EXE: &str = "[GTA Tools] Block outbound traffic for all of GTA V"; const FILTER_NAME_SAVE_SERVER: &str = "[GTA Tools] Block outbound traffic to Rockstar save server"; @@ -21,116 +17,79 @@ pub struct GameNetworking { impl Default for GameNetworking { fn default() -> Self { + let firewall = Firewall::default(); Self { - blocked: if Self::is_save_server_blocked().unwrap() { - Self::is_save_server_blocked().unwrap() + blocked: if firewall.is_blocked(FILTER_NAME_SAVE_SERVER).unwrap() { + true } else { - Self::is_exe_blocked().unwrap() + firewall.is_blocked(FILTER_NAME_EXE).unwrap() }, } } } -enum Mode { - EntireGame(PathBuf), - SaveServer(String), -} - impl GameNetworking { - fn block_generic(mode: Mode) -> Result<(), Box> { - let policy: INetFwPolicy2 = - unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }?; - let rules = unsafe { policy.Rules() }?; - let filter_name = match mode { - Mode::EntireGame(_) => FILTER_NAME_EXE, - Mode::SaveServer(_) => FILTER_NAME_SAVE_SERVER, - }; - unsafe { rules.Remove(&BSTR::from(filter_name)) }?; - let rule: INetFwRule = unsafe { CoCreateInstance(&NetFwRule, None, CLSCTX_INPROC_SERVER) }?; - unsafe { rule.SetName(&BSTR::from(filter_name)) }?; - match mode { - Mode::EntireGame(exe_path) => { - let exe_path = BSTR::from(exe_path.to_string_lossy().to_string()); - unsafe { rule.SetApplicationName(&exe_path) }?; - } - Mode::SaveServer(save_server_ip) => { - unsafe { rule.SetRemoteAddresses(&BSTR::from(save_server_ip)) }?; - } - } - unsafe { rule.SetDirection(NET_FW_RULE_DIR_OUT) }?; - unsafe { rule.SetEnabled(true.into()) }?; - unsafe { rule.SetAction(NET_FW_ACTION_BLOCK) }?; - unsafe { rule.SetProtocol(NET_FW_IP_PROTOCOL_ANY.0) }?; - unsafe { rules.Add(&rule) }?; - Ok(()) - } - - fn unblock_generic(filter_name: &str) -> Result<(), Box> { - let policy: INetFwPolicy2 = - unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }?; - let rules = unsafe { policy.Rules() }?; - unsafe { rules.Remove(&BSTR::from(filter_name)) }?; - Ok(()) - } - - fn is_blocked_generic(filter_name: &str) -> Result> { - let policy: INetFwPolicy2 = - unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }?; - let rules = unsafe { policy.Rules() }?; - let rule_exists = unsafe { rules.Item(&BSTR::from(filter_name)) }.is_ok(); - Ok(rule_exists) - } - - pub fn block_exe(&mut self, system_info: &mut SystemInfo) -> Result<(), Box> { + pub fn block_exe( + &mut self, + system_info: &mut SystemInfo, + firewall: &Firewall, + ) -> Result<(), Box> { let Some(exe_path) = system_info.get_game_exe_path() else { return Ok(()); }; - Self::block_generic(Mode::EntireGame(exe_path.to_path_buf()))?; - self.blocked = Self::is_exe_blocked()?; + firewall.add( + FILTER_NAME_EXE, + RuleMode::Executable(exe_path.to_path_buf()), + RuleDirection::Out, + RuleProtocol::Any, + )?; + self.blocked = firewall.is_blocked(FILTER_NAME_EXE)?; Ok(()) } - pub fn unblock_exe(&mut self) -> Result<(), Box> { - Self::unblock_generic(FILTER_NAME_EXE)?; - self.blocked = Self::is_exe_blocked()?; + pub fn unblock_exe(&mut self, firewall: &Firewall) -> Result<(), Box> { + firewall.remove(FILTER_NAME_EXE)?; + self.blocked = firewall.is_blocked(FILTER_NAME_EXE)?; Ok(()) } - fn is_exe_blocked() -> Result> { - Self::is_blocked_generic(FILTER_NAME_EXE) - } - - pub fn block_save_server(&mut self, save_server_ip: &str) -> Result<(), Box> { - Self::block_generic(Mode::SaveServer(save_server_ip.to_owned()))?; - self.blocked = Self::is_save_server_blocked()?; + pub fn block_save_server( + &mut self, + save_server_ip: &str, + firewall: &Firewall, + ) -> Result<(), Box> { + firewall.add( + FILTER_NAME_SAVE_SERVER, + RuleMode::Address(save_server_ip.to_owned()), + RuleDirection::Out, + RuleProtocol::Any, + )?; + self.blocked = firewall.is_blocked(FILTER_NAME_SAVE_SERVER)?; Ok(()) } - pub fn unblock_save_server(&mut self) -> Result<(), Box> { - Self::unblock_generic(FILTER_NAME_SAVE_SERVER)?; - self.blocked = Self::is_save_server_blocked()?; + pub fn unblock_save_server(&mut self, firewall: &Firewall) -> Result<(), Box> { + firewall.remove(FILTER_NAME_SAVE_SERVER)?; + self.blocked = firewall.is_blocked(FILTER_NAME_SAVE_SERVER)?; Ok(()) } - pub fn is_save_server_blocked() -> Result> { - Self::is_blocked_generic(FILTER_NAME_SAVE_SERVER) - } - pub fn ensure_block_exclusivity( &mut self, block_method: BlockMethod, + firewall: &Firewall, ) -> Result<(), Box> { match block_method { BlockMethod::EntireGame => { - if Self::is_save_server_blocked()? { - self.unblock_save_server()?; - self.blocked = Self::is_exe_blocked()?; + if firewall.is_blocked(FILTER_NAME_SAVE_SERVER)? { + self.unblock_save_server(firewall)?; + self.blocked = firewall.is_blocked(FILTER_NAME_EXE)?; } } BlockMethod::SaveServer => { - if Self::is_exe_blocked()? { - self.unblock_exe()?; - self.blocked = Self::is_save_server_blocked()?; + if firewall.is_blocked(FILTER_NAME_EXE)? { + self.unblock_exe(firewall)?; + self.blocked = firewall.is_blocked(FILTER_NAME_SAVE_SERVER)?; } } } diff --git a/src/gui/app.rs b/src/gui/app.rs index f0255cb..aafee22 100644 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -180,13 +180,17 @@ impl App { match self.settings.block_method { BlockMethod::EntireGame => { self.game_networking - .block_exe(&mut self.system_info) + .block_exe( + &mut self.system_info, + &self.firewall, + ) .unwrap(); } BlockMethod::SaveServer => { self.game_networking .block_save_server( &self.settings.save_server_ip, + &self.firewall, ) .unwrap(); } @@ -197,10 +201,14 @@ impl App { if ui.button("Unblock").clicked() { match self.settings.block_method { BlockMethod::EntireGame => { - self.game_networking.unblock_exe().unwrap(); + self.game_networking + .unblock_exe(&self.firewall) + .unwrap(); } BlockMethod::SaveServer => { - self.game_networking.unblock_save_server().unwrap(); + self.game_networking + .unblock_save_server(&self.firewall) + .unwrap(); } } } @@ -257,7 +265,7 @@ impl App { ui.label("Block method"); if let Err(why) = self .game_networking - .ensure_block_exclusivity(self.settings.block_method) + .ensure_block_exclusivity(self.settings.block_method, &self.firewall) { log::warn!("Couldn't ensure block exclusivity: {why}"); } diff --git a/src/util/firewall.rs b/src/util/firewall.rs index 9ee4131..42964b2 100644 --- a/src/util/firewall.rs +++ b/src/util/firewall.rs @@ -82,6 +82,7 @@ pub enum RuleDirection { pub enum RuleProtocol { Any, + #[allow(unused)] Tcp, Udp, }