use windows api instead of netsh command to manage game's network access
This commit is contained in:
@@ -25,6 +25,7 @@ windows = { version = "0.61.1", features = [
|
|||||||
"Win32_UI_Shell",
|
"Win32_UI_Shell",
|
||||||
"Win32_UI_WindowsAndMessaging",
|
"Win32_UI_WindowsAndMessaging",
|
||||||
"Win32_Security",
|
"Win32_Security",
|
||||||
|
"Win32_NetworkManagement_WindowsFirewall",
|
||||||
] }
|
] }
|
||||||
winreg = "0.55.0"
|
winreg = "0.55.0"
|
||||||
|
|
||||||
|
|||||||
+112
-54
@@ -1,9 +1,118 @@
|
|||||||
use crate::util::consts::game::{EXE_ENHANCED, EXE_LEGACY};
|
use crate::util::consts::game::{EXE_ENHANCED, EXE_LEGACY};
|
||||||
use std::{os::windows::process::CommandExt, path::Path, process::Command};
|
use std::path::Path;
|
||||||
use sysinfo::System;
|
use sysinfo::System;
|
||||||
use windows::Win32::System::Threading::CREATE_NO_WINDOW;
|
use windows::{
|
||||||
|
Win32::{
|
||||||
|
Foundation::E_INVALIDARG,
|
||||||
|
NetworkManagement::WindowsFirewall::{
|
||||||
|
INetFwPolicy2, INetFwRule, NET_FW_ACTION_BLOCK, NET_FW_IP_PROTOCOL_ANY,
|
||||||
|
NET_FW_RULE_DIR_IN, NET_FW_RULE_DIR_OUT, NetFwPolicy2, NetFwRule,
|
||||||
|
},
|
||||||
|
System::Com::{
|
||||||
|
CLSCTX_INPROC_SERVER, COINIT_MULTITHREADED, CoCreateInstance, CoInitializeEx,
|
||||||
|
CoUninitialize,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
core::{BSTR, HRESULT},
|
||||||
|
};
|
||||||
|
|
||||||
const FILTER_NAME: &str = "[GTA Tools] Block all traffic for GTA V";
|
const FILTER_NAME_IN: &str = "[GTA Tools] Block all inbound traffic for GTA V";
|
||||||
|
const FILTER_NAME_OUT: &str = "[GTA Tools] Block all outbound traffic for GTA V";
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GameNetworking {
|
||||||
|
pub is_blocked: bool,
|
||||||
|
com_initialized: bool,
|
||||||
|
policy: INetFwPolicy2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GameNetworking {
|
||||||
|
fn default() -> Self {
|
||||||
|
let result = unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) };
|
||||||
|
let mut gn = Self {
|
||||||
|
is_blocked: false,
|
||||||
|
com_initialized: result != HRESULT(0x80010106u32 as i32),
|
||||||
|
policy: unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER).unwrap() },
|
||||||
|
};
|
||||||
|
gn.is_blocked = gn.is_blocked();
|
||||||
|
gn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for GameNetworking {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if self.com_initialized {
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameNetworking {
|
||||||
|
pub fn block_all(&mut self, sysinfo: &mut System) {
|
||||||
|
let Some(exe_path) = get_game_exe_path(sysinfo) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let rules = unsafe { self.policy.Rules().unwrap() };
|
||||||
|
let filter_name_in = BSTR::from(FILTER_NAME_IN);
|
||||||
|
let filter_name_out = BSTR::from(FILTER_NAME_OUT);
|
||||||
|
unsafe {
|
||||||
|
let _ = rules.Remove(&filter_name_in);
|
||||||
|
let _ = rules.Remove(&filter_name_out);
|
||||||
|
}
|
||||||
|
let exe_path = BSTR::from(exe_path.to_string_lossy().to_string());
|
||||||
|
unsafe {
|
||||||
|
let inbound_rule: INetFwRule =
|
||||||
|
CoCreateInstance(&NetFwRule, None, CLSCTX_INPROC_SERVER).unwrap();
|
||||||
|
inbound_rule.SetName(&filter_name_in).unwrap();
|
||||||
|
inbound_rule.SetApplicationName(&exe_path).unwrap();
|
||||||
|
inbound_rule.SetDirection(NET_FW_RULE_DIR_IN).unwrap();
|
||||||
|
inbound_rule.SetEnabled(true.into()).unwrap();
|
||||||
|
inbound_rule.SetAction(NET_FW_ACTION_BLOCK).unwrap();
|
||||||
|
inbound_rule.SetProtocol(NET_FW_IP_PROTOCOL_ANY.0).unwrap();
|
||||||
|
rules.Add(&inbound_rule).unwrap();
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let outbound_rule: INetFwRule =
|
||||||
|
CoCreateInstance(&NetFwRule, None, CLSCTX_INPROC_SERVER).unwrap();
|
||||||
|
outbound_rule.SetName(&filter_name_out).unwrap();
|
||||||
|
outbound_rule.SetApplicationName(&exe_path).unwrap();
|
||||||
|
outbound_rule.SetDirection(NET_FW_RULE_DIR_OUT).unwrap();
|
||||||
|
outbound_rule.SetEnabled(true.into()).unwrap();
|
||||||
|
outbound_rule.SetAction(NET_FW_ACTION_BLOCK).unwrap();
|
||||||
|
outbound_rule.SetProtocol(NET_FW_IP_PROTOCOL_ANY.0).unwrap();
|
||||||
|
rules.Add(&outbound_rule).unwrap();
|
||||||
|
}
|
||||||
|
self.is_blocked = self.is_blocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unblock_all(&mut self) {
|
||||||
|
let rules = unsafe { self.policy.Rules().unwrap() };
|
||||||
|
unsafe {
|
||||||
|
let result = rules.Remove(&BSTR::from(FILTER_NAME_IN));
|
||||||
|
if let Err(ref why) = result {
|
||||||
|
if why.code() != E_INVALIDARG {
|
||||||
|
result.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let result = rules.Remove(&BSTR::from(FILTER_NAME_OUT));
|
||||||
|
if let Err(ref why) = result {
|
||||||
|
if why.code() != E_INVALIDARG {
|
||||||
|
result.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.is_blocked = self.is_blocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_blocked(&self) -> bool {
|
||||||
|
let rules = unsafe { self.policy.Rules().unwrap() };
|
||||||
|
let in_rule_exists = unsafe { rules.Item(&BSTR::from(FILTER_NAME_IN)).is_ok() };
|
||||||
|
let out_rule_exists = unsafe { rules.Item(&BSTR::from(FILTER_NAME_OUT)).is_ok() };
|
||||||
|
in_rule_exists || out_rule_exists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_game_exe_path(sysinfo: &mut System) -> Option<&Path> {
|
fn get_game_exe_path(sysinfo: &mut System) -> Option<&Path> {
|
||||||
sysinfo.refresh_all();
|
sysinfo.refresh_all();
|
||||||
@@ -17,54 +126,3 @@ fn get_game_exe_path(sysinfo: &mut System) -> Option<&Path> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block_all(sysinfo: &mut System) {
|
|
||||||
let Some(exe_path) = get_game_exe_path(sysinfo) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let exe_path = exe_path.display();
|
|
||||||
Command::new("netsh")
|
|
||||||
.args([
|
|
||||||
"advfirewall",
|
|
||||||
"firewall",
|
|
||||||
"add",
|
|
||||||
"rule",
|
|
||||||
&format!("name={FILTER_NAME}"),
|
|
||||||
"dir=out",
|
|
||||||
"action=block",
|
|
||||||
"protocol=ANY",
|
|
||||||
&format!("program={exe_path}"),
|
|
||||||
])
|
|
||||||
.creation_flags(CREATE_NO_WINDOW.0)
|
|
||||||
.spawn()
|
|
||||||
.unwrap();
|
|
||||||
Command::new("netsh")
|
|
||||||
.args([
|
|
||||||
"advfirewall",
|
|
||||||
"firewall",
|
|
||||||
"add",
|
|
||||||
"rule",
|
|
||||||
&format!("name={FILTER_NAME}"),
|
|
||||||
"dir=in",
|
|
||||||
"action=block",
|
|
||||||
"protocol=ANY",
|
|
||||||
&format!("program={exe_path}"),
|
|
||||||
])
|
|
||||||
.creation_flags(CREATE_NO_WINDOW.0)
|
|
||||||
.spawn()
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unblock_all() {
|
|
||||||
Command::new("netsh")
|
|
||||||
.args([
|
|
||||||
"advfirewall",
|
|
||||||
"firewall",
|
|
||||||
"delete",
|
|
||||||
"rule",
|
|
||||||
&format!("name={FILTER_NAME}"),
|
|
||||||
])
|
|
||||||
.creation_flags(CREATE_NO_WINDOW.0)
|
|
||||||
.spawn()
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|||||||
+6
-5
@@ -32,10 +32,11 @@ pub struct App {
|
|||||||
pub flags: Flags,
|
pub flags: Flags,
|
||||||
pub sysinfo: sysinfo::System,
|
pub sysinfo: sysinfo::System,
|
||||||
game_handle: windows::Win32::Foundation::HANDLE,
|
game_handle: windows::Win32::Foundation::HANDLE,
|
||||||
pub launch: features::launch::Launch,
|
|
||||||
force_close: features::force_close::ForceClose,
|
|
||||||
empty_session: features::empty_session::EmptySession,
|
|
||||||
pub anti_afk: features::anti_afk::AntiAfk,
|
pub anti_afk: features::anti_afk::AntiAfk,
|
||||||
|
empty_session: features::empty_session::EmptySession,
|
||||||
|
force_close: features::force_close::ForceClose,
|
||||||
|
game_networking: features::game_networking::GameNetworking,
|
||||||
|
pub launch: features::launch::Launch,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for App {
|
impl eframe::App for App {
|
||||||
@@ -147,13 +148,13 @@ impl App {
|
|||||||
.add_sized([button_width, 18.0], egui::Button::new("Block"))
|
.add_sized([button_width, 18.0], egui::Button::new("Block"))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
features::game_networking::block_all(&mut self.sysinfo);
|
self.game_networking.block_all(&mut self.sysinfo);
|
||||||
}
|
}
|
||||||
if ui
|
if ui
|
||||||
.add_sized([button_width, 18.0], egui::Button::new("Unblock"))
|
.add_sized([button_width, 18.0], egui::Button::new("Unblock"))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
features::game_networking::unblock_all();
|
self.game_networking.unblock_all();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user