refactor: use sysproxy-rs to set system proxy on windows (#5846)

* refactor: use sysproxy-rs to set system proxy on windows

* fix: remove download sysproxy.exe task

* chore: unified processing system proxy reset

* docs: update Changelog.md
This commit is contained in:
oomeow
2025-12-18 20:23:29 +08:00
committed by GitHub
parent b282217e5c
commit 9713343323
5 changed files with 69 additions and 215 deletions

4
Cargo.lock generated
View File

@@ -7385,8 +7385,8 @@ dependencies = [
[[package]]
name = "sysproxy"
version = "0.4.1"
source = "git+https://github.com/clash-verge-rev/sysproxy-rs#279a5cf1c4470d0b28af9a5c3fb7c2fcb503a906"
version = "0.4.2"
source = "git+https://github.com/clash-verge-rev/sysproxy-rs#51256d5921a01bbcf24fe5629296d2bfe493329d"
dependencies = [
"interfaces",
"iptools",

View File

@@ -67,6 +67,7 @@
- 改进旧版 Service 需要重新安装检测流程
- 优化 macOS, Linux 和 Windows 系统信号处理
- 链式代理仅显示 Selector 类型规则组
- 优化 Windows 系统代理设置,不再依赖 `sysproxy.exe` 来设置代理
</details>

View File

@@ -576,7 +576,7 @@ const resolveServicePermission = async () => {
};
// =======================
// Other resource resolvers (service, mmdb, geosite, geoip, enableLoopback, sysproxy)
// Other resource resolvers (service, mmdb, geosite, geoip, enableLoopback)
// =======================
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service-ipc/releases/download/${SIDECAR_HOST}`;
const resolveService = () => {
@@ -624,11 +624,6 @@ const resolveEnableLoopback = () =>
file: "enableLoopback.exe",
downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`,
});
const resolveWinSysproxy = () =>
resolveResource({
file: "sysproxy.exe",
downloadURL: `https://github.com/clash-verge-rev/sysproxy/releases/download/${arch}/sysproxy.exe`,
});
const resolveSetDnsScript = () =>
resolveResource({
@@ -676,12 +671,6 @@ const tasks = [
retry: 5,
unixOnly: platform === "linux" || platform === "darwin",
},
{
name: "windows-sysproxy",
func: resolveWinSysproxy,
retry: 5,
winOnly: true,
},
{
name: "set_dns_script",
func: resolveSetDnsScript,

View File

@@ -23,7 +23,6 @@ use tauri_plugin_autostart::ManagerExt as _;
pub struct Sysopt {
update_sysproxy: AtomicBool,
reset_sysproxy: AtomicBool,
#[cfg(not(target_os = "windows"))]
inner_proxy: Arc<RwLock<(Sysproxy, Autoproxy)>>,
guard: Arc<RwLock<GuardMonitor>>,
}
@@ -33,7 +32,6 @@ impl Default for Sysopt {
Self {
update_sysproxy: AtomicBool::new(false),
reset_sysproxy: AtomicBool::new(false),
#[cfg(not(target_os = "windows"))]
inner_proxy: Arc::new(RwLock::new((Sysproxy::default(), Autoproxy::default()))),
guard: Arc::new(RwLock::new(GuardMonitor::new(GuardType::None, Duration::from_secs(30)))),
}
@@ -69,35 +67,6 @@ async fn get_bypass() -> String {
}
}
// Uses tokio Command with CREATE_NO_WINDOW flag to avoid DLL initialization issues during shutdown
#[cfg(target_os = "windows")]
async fn execute_sysproxy_command(args: Vec<std::string::String>) -> Result<()> {
use crate::utils::dirs;
use anyhow::bail;
#[allow(unused_imports)] // Required for .creation_flags() method
use std::os::windows::process::CommandExt as _;
use tokio::process::Command;
let binary_path = dirs::service_path()?;
let sysproxy_exe = binary_path.with_file_name("sysproxy.exe");
if !sysproxy_exe.exists() {
bail!("sysproxy.exe not found");
}
let output = Command::new(sysproxy_exe)
.args(args)
.creation_flags(0x08000000) // CREATE_NO_WINDOW - 隐藏窗口
.output()
.await?;
if !output.status.success() {
bail!("sysproxy exe run failed");
}
Ok(())
}
singleton!(Sysopt, SYSOPT);
impl Sysopt {
@@ -112,12 +81,12 @@ impl Sysopt {
pub async fn refresh_guard(&self) {
logging!(info, Type::Core, "Refreshing system proxy guard...");
let verge = Config::verge().await.latest_arc();
if !verge.enable_system_proxy.unwrap_or(false) {
if !verge.enable_system_proxy.unwrap_or_default() {
logging!(info, Type::Core, "System proxy is disabled.");
self.access_guard().write().stop();
return;
}
if !verge.enable_proxy_guard.unwrap_or(false) {
if !verge.enable_proxy_guard.unwrap_or_default() {
logging!(info, Type::Core, "System proxy guard is disabled.");
return;
}
@@ -169,94 +138,62 @@ impl Sysopt {
};
let pac_port = IVerge::get_singleton_port();
let (sys_enable, pac_enable, proxy_host) = {
let (sys_enable, pac_enable, proxy_host, proxy_guard) = {
(
verge.enable_system_proxy.unwrap_or(false),
verge.proxy_auto_config.unwrap_or(false),
verge.enable_system_proxy.unwrap_or_default(),
verge.proxy_auto_config.unwrap_or_default(),
verge.proxy_host.clone().unwrap_or_else(|| String::from("127.0.0.1")),
verge.enable_proxy_guard.unwrap_or_default(),
)
};
#[cfg(not(target_os = "windows"))]
{
// 先 await, 避免持有锁导致的 Send 问题
let bypass = get_bypass().await;
// 先 await, 避免持有锁导致的 Send 问题
let bypass = get_bypass().await;
let (sys, auto) = &mut *self.inner_proxy.write();
let (sys, auto) = &mut *self.inner_proxy.write();
sys.enable = false;
sys.host = proxy_host.clone().into();
sys.port = port;
sys.bypass = bypass.into();
auto.enable = false;
auto.url = format!("http://{proxy_host}:{pac_port}/commands/pac");
self.access_guard().write().set_guard_type(GuardType::None);
if !sys_enable && !pac_enable {
// disable proxy
sys.set_system_proxy()?;
auto.set_auto_proxy()?;
return Ok(());
}
if pac_enable {
sys.enable = false;
sys.host = proxy_host.clone().into();
sys.port = port;
sys.bypass = bypass.into();
auto.enable = false;
auto.url = format!("http://{proxy_host}:{pac_port}/commands/pac");
if !sys_enable {
sys.set_system_proxy()?;
auto.set_auto_proxy()?;
self.access_guard()
.write()
.set_guard_type(GuardType::Sysproxy(sys.clone()));
return Ok(());
}
if pac_enable {
sys.enable = false;
auto.enable = true;
sys.set_system_proxy()?;
auto.set_auto_proxy()?;
auto.enable = true;
sys.set_system_proxy()?;
auto.set_auto_proxy()?;
if proxy_guard {
self.access_guard()
.write()
.set_guard_type(GuardType::Autoproxy(auto.clone()));
return Ok(());
}
return Ok(());
}
if sys_enable {
auto.enable = false;
sys.enable = true;
auto.set_auto_proxy()?;
sys.set_system_proxy()?;
if sys_enable {
auto.enable = false;
sys.enable = true;
auto.set_auto_proxy()?;
sys.set_system_proxy()?;
if proxy_guard {
self.access_guard()
.write()
.set_guard_type(GuardType::Sysproxy(sys.clone()));
return Ok(());
}
return Ok(());
}
#[cfg(target_os = "windows")]
{
if !sys_enable {
self.access_guard().write().set_guard_type(GuardType::None);
return self.reset_sysproxy().await;
}
let (args, guard_type): (Vec<std::string::String>, GuardType) = if pac_enable {
let address = format!("http://{proxy_host}:{pac_port}/commands/pac");
(
vec!["pac".into(), address.clone()],
GuardType::Autoproxy(Autoproxy {
enable: true,
url: address,
}),
)
} else {
let address = format!("{proxy_host}:{port}");
let bypass = get_bypass().await;
let bypass_for_guard = bypass.as_str().to_owned();
(
vec!["global".into(), address.clone(), bypass.into()],
GuardType::Sysproxy(Sysproxy {
enable: true,
host: proxy_host.clone().into(),
port,
bypass: bypass_for_guard,
}),
)
};
execute_sysproxy_command(args).await?;
self.access_guard().write().set_guard_type(guard_type);
}
Ok(())
}
@@ -274,20 +211,15 @@ impl Sysopt {
self.reset_sysproxy.store(false, Ordering::SeqCst);
}
//直接关闭所有代理
#[cfg(not(target_os = "windows"))]
{
let (sys, auto) = &mut *self.inner_proxy.write();
sys.enable = false;
sys.set_system_proxy()?;
auto.enable = false;
auto.set_auto_proxy()?;
}
// close proxy guard
self.access_guard().write().set_guard_type(GuardType::None);
#[cfg(target_os = "windows")]
{
execute_sysproxy_command(vec!["set".into(), "1".into()]).await?;
}
// 直接关闭所有代理
let (sys, auto) = &mut *self.inner_proxy.write();
sys.enable = false;
sys.set_system_proxy()?;
auto.enable = false;
auto.set_auto_proxy()?;
Ok(())
}

View File

@@ -45,93 +45,25 @@ pub async fn clean_async() -> bool {
// 重置系统代理
let proxy_task = tokio::task::spawn(async {
#[cfg(target_os = "windows")]
{
use sysproxy::{Autoproxy, Sysproxy};
use winapi::um::winuser::{GetSystemMetrics, SM_SHUTTINGDOWN};
// 检查系统代理是否开启
let sys_proxy_enabled = Config::verge().await.data_arc().enable_system_proxy.unwrap_or(false);
if !sys_proxy_enabled {
logging!(info, Type::Window, "系统代理未启用,跳过重置");
return true;
}
// 检查是否正在关机
let is_shutting_down = unsafe { GetSystemMetrics(SM_SHUTTINGDOWN) != 0 };
if is_shutting_down {
// sysproxy-rs 操作注册表(避免.exe的dll错误)
logging!(info, Type::Window, "检测到正在关机syspro-rs操作注册表关闭系统代理");
match Sysproxy::get_system_proxy() {
Ok(mut sysproxy) => {
sysproxy.enable = false;
if let Err(e) = sysproxy.set_system_proxy() {
logging!(warn, Type::Window, "Warning: 关机时关闭系统代理失败: {e}");
} else {
logging!(info, Type::Window, "系统代理已关闭(通过注册表)");
}
}
Err(e) => {
logging!(warn, Type::Window, "Warning: 关机时获取代理设置失败: {e}");
}
}
// 关闭自动代理配置
if let Ok(mut autoproxy) = Autoproxy::get_auto_proxy() {
autoproxy.enable = false;
let _ = autoproxy.set_auto_proxy();
}
return true;
}
// 正常退出:使用 sysproxy.exe 重置代理
logging!(info, Type::Window, "sysproxy.exe重置系统代理");
match timeout(Duration::from_secs(2), sysopt::Sysopt::global().reset_sysproxy()).await {
Ok(Ok(_)) => {
logging!(info, Type::Window, "系统代理已重置");
true
}
Ok(Err(e)) => {
logging!(warn, Type::Window, "Warning: 重置系统代理失败: {e}");
true
}
Err(_) => {
logging!(warn, Type::Window, "Warning: 重置系统代理超时,继续退出流程");
true
}
}
let sys_proxy_enabled = Config::verge().await.data_arc().enable_system_proxy.unwrap_or(false);
if !sys_proxy_enabled {
logging!(info, Type::Window, "系统代理未启用,跳过重置");
return true;
}
// 非 Windows 平台:正常重置代理
#[cfg(not(target_os = "windows"))]
{
let sys_proxy_enabled = Config::verge().await.data_arc().enable_system_proxy.unwrap_or(false);
if !sys_proxy_enabled {
logging!(info, Type::Window, "系统代理未启用,跳过重置");
return true;
logging!(info, Type::Window, "开始重置系统代理...");
match timeout(Duration::from_millis(1500), sysopt::Sysopt::global().reset_sysproxy()).await {
Ok(Ok(_)) => {
logging!(info, Type::Window, "系统代理已重置");
true
}
logging!(info, Type::Window, "开始重置系统代理...");
match timeout(Duration::from_millis(1500), sysopt::Sysopt::global().reset_sysproxy()).await {
Ok(Ok(_)) => {
logging!(info, Type::Window, "系统代理已重置");
true
}
Ok(Err(e)) => {
logging!(warn, Type::Window, "Warning: 重置系统代理失败: {e}");
true
}
Err(_) => {
logging!(warn, Type::Window, "Warning: 重置系统代理超时,继续退出");
true
}
Ok(Err(e)) => {
logging!(warn, Type::Window, "Warning: 重置系统代理失败: {e}");
false
}
Err(_) => {
logging!(warn, Type::Window, "Warning: 重置系统代理超时,继续退出");
false
}
}
});
@@ -183,7 +115,7 @@ pub async fn clean_async() -> bool {
Type::Window,
"Warning: 停止core超时可能系统正在关机继续退出"
);
true
false
}
}
});