use Firewall in game_networking

This commit is contained in:
2025-12-12 03:52:40 -05:00
committed by sapphire
parent e0a5821431
commit 23fd4b12f9
3 changed files with 60 additions and 92 deletions
+47 -88
View File
@@ -1,15 +1,11 @@
use crate::{gui::settings::BlockMethod, util::system_info::SystemInfo}; use crate::{
use std::{error::Error, path::PathBuf}; gui::settings::BlockMethod,
use windows::{ util::{
Win32::{ firewall::{Firewall, RuleDirection, RuleMode, RuleProtocol},
NetworkManagement::WindowsFirewall::{ system_info::SystemInfo,
INetFwPolicy2, INetFwRule, NET_FW_ACTION_BLOCK, NET_FW_IP_PROTOCOL_ANY,
NET_FW_RULE_DIR_OUT, NetFwPolicy2, NetFwRule,
},
System::Com::{CLSCTX_INPROC_SERVER, CoCreateInstance},
}, },
core::BSTR,
}; };
use std::error::Error;
const FILTER_NAME_EXE: &str = "[GTA Tools] Block outbound traffic for all of GTA V"; 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"; 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 { impl Default for GameNetworking {
fn default() -> Self { fn default() -> Self {
let firewall = Firewall::default();
Self { Self {
blocked: if Self::is_save_server_blocked().unwrap() { blocked: if firewall.is_blocked(FILTER_NAME_SAVE_SERVER).unwrap() {
Self::is_save_server_blocked().unwrap() true
} else { } else {
Self::is_exe_blocked().unwrap() firewall.is_blocked(FILTER_NAME_EXE).unwrap()
}, },
} }
} }
} }
enum Mode {
EntireGame(PathBuf),
SaveServer(String),
}
impl GameNetworking { impl GameNetworking {
fn block_generic(mode: Mode) -> Result<(), Box<dyn Error>> { pub fn block_exe(
let policy: INetFwPolicy2 = &mut self,
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }?; system_info: &mut SystemInfo,
let rules = unsafe { policy.Rules() }?; firewall: &Firewall,
let filter_name = match mode { ) -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
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<bool, Box<dyn Error>> {
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<dyn Error>> {
let Some(exe_path) = system_info.get_game_exe_path() else { let Some(exe_path) = system_info.get_game_exe_path() else {
return Ok(()); return Ok(());
}; };
Self::block_generic(Mode::EntireGame(exe_path.to_path_buf()))?; firewall.add(
self.blocked = Self::is_exe_blocked()?; FILTER_NAME_EXE,
RuleMode::Executable(exe_path.to_path_buf()),
RuleDirection::Out,
RuleProtocol::Any,
)?;
self.blocked = firewall.is_blocked(FILTER_NAME_EXE)?;
Ok(()) Ok(())
} }
pub fn unblock_exe(&mut self) -> Result<(), Box<dyn Error>> { pub fn unblock_exe(&mut self, firewall: &Firewall) -> Result<(), Box<dyn Error>> {
Self::unblock_generic(FILTER_NAME_EXE)?; firewall.remove(FILTER_NAME_EXE)?;
self.blocked = Self::is_exe_blocked()?; self.blocked = firewall.is_blocked(FILTER_NAME_EXE)?;
Ok(()) Ok(())
} }
fn is_exe_blocked() -> Result<bool, Box<dyn Error>> { pub fn block_save_server(
Self::is_blocked_generic(FILTER_NAME_EXE) &mut self,
} save_server_ip: &str,
firewall: &Firewall,
pub fn block_save_server(&mut self, save_server_ip: &str) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
Self::block_generic(Mode::SaveServer(save_server_ip.to_owned()))?; firewall.add(
self.blocked = Self::is_save_server_blocked()?; 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(()) Ok(())
} }
pub fn unblock_save_server(&mut self) -> Result<(), Box<dyn Error>> { pub fn unblock_save_server(&mut self, firewall: &Firewall) -> Result<(), Box<dyn Error>> {
Self::unblock_generic(FILTER_NAME_SAVE_SERVER)?; firewall.remove(FILTER_NAME_SAVE_SERVER)?;
self.blocked = Self::is_save_server_blocked()?; self.blocked = firewall.is_blocked(FILTER_NAME_SAVE_SERVER)?;
Ok(()) Ok(())
} }
pub fn is_save_server_blocked() -> Result<bool, Box<dyn Error>> {
Self::is_blocked_generic(FILTER_NAME_SAVE_SERVER)
}
pub fn ensure_block_exclusivity( pub fn ensure_block_exclusivity(
&mut self, &mut self,
block_method: BlockMethod, block_method: BlockMethod,
firewall: &Firewall,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
match block_method { match block_method {
BlockMethod::EntireGame => { BlockMethod::EntireGame => {
if Self::is_save_server_blocked()? { if firewall.is_blocked(FILTER_NAME_SAVE_SERVER)? {
self.unblock_save_server()?; self.unblock_save_server(firewall)?;
self.blocked = Self::is_exe_blocked()?; self.blocked = firewall.is_blocked(FILTER_NAME_EXE)?;
} }
} }
BlockMethod::SaveServer => { BlockMethod::SaveServer => {
if Self::is_exe_blocked()? { if firewall.is_blocked(FILTER_NAME_EXE)? {
self.unblock_exe()?; self.unblock_exe(firewall)?;
self.blocked = Self::is_save_server_blocked()?; self.blocked = firewall.is_blocked(FILTER_NAME_SAVE_SERVER)?;
} }
} }
} }
+12 -4
View File
@@ -180,13 +180,17 @@ impl App {
match self.settings.block_method { match self.settings.block_method {
BlockMethod::EntireGame => { BlockMethod::EntireGame => {
self.game_networking self.game_networking
.block_exe(&mut self.system_info) .block_exe(
&mut self.system_info,
&self.firewall,
)
.unwrap(); .unwrap();
} }
BlockMethod::SaveServer => { BlockMethod::SaveServer => {
self.game_networking self.game_networking
.block_save_server( .block_save_server(
&self.settings.save_server_ip, &self.settings.save_server_ip,
&self.firewall,
) )
.unwrap(); .unwrap();
} }
@@ -197,10 +201,14 @@ impl App {
if ui.button("Unblock").clicked() { if ui.button("Unblock").clicked() {
match self.settings.block_method { match self.settings.block_method {
BlockMethod::EntireGame => { BlockMethod::EntireGame => {
self.game_networking.unblock_exe().unwrap(); self.game_networking
.unblock_exe(&self.firewall)
.unwrap();
} }
BlockMethod::SaveServer => { 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"); ui.label("Block method");
if let Err(why) = self if let Err(why) = self
.game_networking .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}"); log::warn!("Couldn't ensure block exclusivity: {why}");
} }
+1
View File
@@ -82,6 +82,7 @@ pub enum RuleDirection {
pub enum RuleProtocol { pub enum RuleProtocol {
Any, Any,
#[allow(unused)]
Tcp, Tcp,
Udp, Udp,
} }