mirror of
https://github.com/EasyTier/EasyTier.git
synced 2025-09-26 20:51:17 +08:00
improve experience of subnet/kcp proxy
1. add self to windows firewall on windows 2. android always use smoltcp
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -1968,8 +1968,8 @@ dependencies = [
|
||||
"url",
|
||||
"uuid",
|
||||
"wildmatch",
|
||||
"windows 0.52.0",
|
||||
"windows-service",
|
||||
"windows-sys 0.52.0",
|
||||
"winreg 0.52.0",
|
||||
"zerocopy",
|
||||
"zip",
|
||||
@@ -9061,6 +9061,16 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core 0.52.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
|
@@ -89,6 +89,7 @@ fn get_os_hostname() -> Result<String, String> {
|
||||
|
||||
#[tauri::command]
|
||||
fn set_logging_level(level: String) -> Result<(), String> {
|
||||
#[allow(static_mut_refs)]
|
||||
let sender = unsafe { LOGGER_LEVEL_SENDER.as_ref().unwrap() };
|
||||
sender.send(level).map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
@@ -188,7 +189,10 @@ pub fn run() {
|
||||
let Ok(Some(logger_reinit)) = utils::init_logger(config, true) else {
|
||||
return Ok(());
|
||||
};
|
||||
unsafe { LOGGER_LEVEL_SENDER.replace(logger_reinit) };
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe {
|
||||
LOGGER_LEVEL_SENDER.replace(logger_reinit)
|
||||
};
|
||||
|
||||
// for tray icon, menu need to be built in js
|
||||
#[cfg(not(target_os = "android"))]
|
||||
|
@@ -204,12 +204,15 @@ netlink-packet-core = { version = "0.7.0" }
|
||||
netlink-packet-utils = "0.5.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.52", features = [
|
||||
"Win32_Networking_WinSock",
|
||||
"Win32_NetworkManagement_IpHelper",
|
||||
windows = { version = "0.52.0", features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_NetworkManagement_WindowsFirewall",
|
||||
"Win32_System_Com",
|
||||
"Win32_Networking",
|
||||
"Win32_System_Ole",
|
||||
"Win32_Networking_WinSock",
|
||||
"Win32_System_IO",
|
||||
] }
|
||||
]}
|
||||
encoding = "0.2"
|
||||
winreg = "0.52"
|
||||
windows-service = "0.7.0"
|
||||
|
@@ -1,26 +1,27 @@
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
io::{self, ErrorKind},
|
||||
mem,
|
||||
net::SocketAddr,
|
||||
os::windows::io::AsRawSocket,
|
||||
ptr,
|
||||
};
|
||||
use std::{io, net::SocketAddr, os::windows::io::AsRawSocket};
|
||||
|
||||
use anyhow::Context;
|
||||
use network_interface::NetworkInterfaceConfig;
|
||||
use windows_sys::{
|
||||
core::PCSTR,
|
||||
use windows::{
|
||||
core::BSTR,
|
||||
Win32::{
|
||||
Foundation::{BOOL, FALSE},
|
||||
NetworkManagement::WindowsFirewall::{
|
||||
INetFwPolicy2, INetFwRule, NET_FW_ACTION_ALLOW, NET_FW_PROFILE2_PRIVATE,
|
||||
NET_FW_PROFILE2_PUBLIC, NET_FW_RULE_DIR_IN, NET_FW_RULE_DIR_OUT,
|
||||
},
|
||||
Networking::WinSock::{
|
||||
htonl, setsockopt, WSAGetLastError, WSAIoctl, IPPROTO_IP, IPPROTO_IPV6,
|
||||
IPV6_UNICAST_IF, IP_UNICAST_IF, SIO_UDP_CONNRESET, SOCKET, SOCKET_ERROR,
|
||||
},
|
||||
System::Com::{
|
||||
CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, COINIT_MULTITHREADED,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub fn disable_connection_reset<S: AsRawSocket>(socket: &S) -> io::Result<()> {
|
||||
let handle = socket.as_raw_socket() as SOCKET;
|
||||
let handle = SOCKET(socket.as_raw_socket() as usize);
|
||||
|
||||
unsafe {
|
||||
// Ignoring UdpSocket's WSAECONNRESET error
|
||||
@@ -39,21 +40,18 @@ pub fn disable_connection_reset<S: AsRawSocket>(socket: &S) -> io::Result<()> {
|
||||
let ret = WSAIoctl(
|
||||
handle,
|
||||
SIO_UDP_CONNRESET,
|
||||
&enable as *const _ as *const c_void,
|
||||
mem::size_of_val(&enable) as u32,
|
||||
ptr::null_mut(),
|
||||
Some(&enable as *const _ as *const std::ffi::c_void),
|
||||
std::mem::size_of_val(&enable) as u32,
|
||||
None,
|
||||
0,
|
||||
&mut bytes_returned as *mut _,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
if ret == SOCKET_ERROR {
|
||||
use std::io::Error;
|
||||
|
||||
// Error occurs
|
||||
let err_code = WSAGetLastError();
|
||||
return Err(Error::from_raw_os_error(err_code));
|
||||
return Err(std::io::Error::from_raw_os_error(err_code.0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +61,7 @@ pub fn disable_connection_reset<S: AsRawSocket>(socket: &S) -> io::Result<()> {
|
||||
pub fn interface_count() -> io::Result<usize> {
|
||||
let ifaces = network_interface::NetworkInterface::show().map_err(|e| {
|
||||
io::Error::new(
|
||||
ErrorKind::NotFound,
|
||||
io::ErrorKind::NotFound,
|
||||
format!("Failed to get interfaces. error: {}", e),
|
||||
)
|
||||
})?;
|
||||
@@ -73,7 +71,7 @@ pub fn interface_count() -> io::Result<usize> {
|
||||
pub fn find_interface_index(iface_name: &str) -> io::Result<u32> {
|
||||
let ifaces = network_interface::NetworkInterface::show().map_err(|e| {
|
||||
io::Error::new(
|
||||
ErrorKind::NotFound,
|
||||
io::ErrorKind::NotFound,
|
||||
format!("Failed to get interfaces. {}, error: {}", iface_name, e),
|
||||
)
|
||||
})?;
|
||||
@@ -82,7 +80,7 @@ pub fn find_interface_index(iface_name: &str) -> io::Result<u32> {
|
||||
}
|
||||
tracing::error!("Failed to find interface index for {}", iface_name);
|
||||
Err(io::Error::new(
|
||||
ErrorKind::NotFound,
|
||||
io::ErrorKind::NotFound,
|
||||
format!("{}", iface_name),
|
||||
))
|
||||
}
|
||||
@@ -92,7 +90,7 @@ pub fn set_ip_unicast_if<S: AsRawSocket>(
|
||||
addr: &SocketAddr,
|
||||
iface: &str,
|
||||
) -> io::Result<()> {
|
||||
let handle = socket.as_raw_socket() as SOCKET;
|
||||
let handle = SOCKET(socket.as_raw_socket() as usize);
|
||||
|
||||
let if_index = find_interface_index(iface)?;
|
||||
|
||||
@@ -100,30 +98,23 @@ pub fn set_ip_unicast_if<S: AsRawSocket>(
|
||||
// https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
|
||||
let ret = match addr {
|
||||
SocketAddr::V4(..) => {
|
||||
// Interface index is in network byte order for IPPROTO_IP.
|
||||
let if_index = htonl(if_index);
|
||||
setsockopt(
|
||||
handle,
|
||||
IPPROTO_IP as i32,
|
||||
IP_UNICAST_IF as i32,
|
||||
&if_index as *const _ as PCSTR,
|
||||
mem::size_of_val(&if_index) as i32,
|
||||
)
|
||||
let if_index_bytes = if_index.to_ne_bytes();
|
||||
setsockopt(handle, IPPROTO_IP.0, IP_UNICAST_IF, Some(&if_index_bytes))
|
||||
}
|
||||
SocketAddr::V6(..) => {
|
||||
// Interface index is in host byte order for IPPROTO_IPV6.
|
||||
let if_index_bytes = if_index.to_ne_bytes();
|
||||
setsockopt(
|
||||
handle,
|
||||
IPPROTO_IPV6 as i32,
|
||||
IPV6_UNICAST_IF as i32,
|
||||
&if_index as *const _ as PCSTR,
|
||||
mem::size_of_val(&if_index) as i32,
|
||||
IPPROTO_IPV6.0,
|
||||
IPV6_UNICAST_IF,
|
||||
Some(&if_index_bytes),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if ret == SOCKET_ERROR {
|
||||
let err = io::Error::from_raw_os_error(WSAGetLastError());
|
||||
let err = std::io::Error::from_raw_os_error(WSAGetLastError().0);
|
||||
tracing::error!(
|
||||
"set IP_UNICAST_IF / IPV6_UNICAST_IF interface: {}, index: {}, error: {}",
|
||||
iface,
|
||||
@@ -152,4 +143,95 @@ pub fn setup_socket_for_win<S: AsRawSocket>(
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ComInitializer;
|
||||
|
||||
impl ComInitializer {
|
||||
fn new() -> windows::core::Result<Self> {
|
||||
unsafe { CoInitializeEx(None, COINIT_MULTITHREADED)? };
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ComInitializer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_add_self_to_firewall_allowlist(inbound: bool) -> anyhow::Result<()> {
|
||||
let _com = ComInitializer::new()?;
|
||||
// 创建防火墙策略实例
|
||||
let policy: INetFwPolicy2 = unsafe {
|
||||
CoCreateInstance(
|
||||
&windows::Win32::NetworkManagement::WindowsFirewall::NetFwPolicy2,
|
||||
None,
|
||||
CLSCTX_ALL,
|
||||
)
|
||||
}?;
|
||||
|
||||
// 创建防火墙规则实例
|
||||
let rule: INetFwRule = unsafe {
|
||||
CoCreateInstance(
|
||||
&windows::Win32::NetworkManagement::WindowsFirewall::NetFwRule,
|
||||
None,
|
||||
CLSCTX_ALL,
|
||||
)
|
||||
}?;
|
||||
|
||||
// 设置规则属性
|
||||
let exe_path = std::env::current_exe()
|
||||
.with_context(|| "Failed to get current executable path when adding firewall rule")?
|
||||
.to_string_lossy()
|
||||
.replace(r"\\?\", "");
|
||||
|
||||
let name = BSTR::from(format!(
|
||||
"EasyTier {} ({})",
|
||||
exe_path,
|
||||
if inbound { "Inbound" } else { "Outbound" }
|
||||
));
|
||||
let desc = BSTR::from("Allow EasyTier to do subnet proxy and kcp proxy");
|
||||
let app_path = BSTR::from(&exe_path);
|
||||
|
||||
unsafe {
|
||||
rule.SetName(&name)?;
|
||||
rule.SetDescription(&desc)?;
|
||||
rule.SetApplicationName(&app_path)?;
|
||||
rule.SetAction(NET_FW_ACTION_ALLOW)?;
|
||||
if inbound {
|
||||
rule.SetDirection(NET_FW_RULE_DIR_IN)?; // 允许入站连接
|
||||
} else {
|
||||
rule.SetDirection(NET_FW_RULE_DIR_OUT)?; // 允许出站连接
|
||||
}
|
||||
rule.SetEnabled(windows::Win32::Foundation::VARIANT_TRUE)?;
|
||||
rule.SetProfiles(NET_FW_PROFILE2_PRIVATE.0 | NET_FW_PROFILE2_PUBLIC.0)?;
|
||||
rule.SetGrouping(&BSTR::from("EasyTier"))?;
|
||||
|
||||
// 获取规则集合并添加新规则
|
||||
let rules = policy.Rules()?;
|
||||
rules.Remove(&name)?; // 先删除同名规则
|
||||
rules.Add(&rule)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_self_to_firewall_allowlist() -> anyhow::Result<()> {
|
||||
do_add_self_to_firewall_allowlist(true)?;
|
||||
do_add_self_to_firewall_allowlist(false)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_add_self_to_firewall_allowlist() {
|
||||
let res = add_self_to_firewall_allowlist();
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
}
|
||||
|
@@ -452,7 +452,10 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
|
||||
async fn get_proxy_listener(&self) -> Result<ProxyTcpListener> {
|
||||
#[cfg(feature = "smoltcp")]
|
||||
if self.global_ctx.get_flags().use_smoltcp || self.global_ctx.no_tun() {
|
||||
if self.global_ctx.get_flags().use_smoltcp
|
||||
|| self.global_ctx.no_tun()
|
||||
|| cfg!(target_os = "android")
|
||||
{
|
||||
// use smoltcp network stack
|
||||
self.local_port
|
||||
.store(8899, std::sync::atomic::Ordering::Relaxed);
|
||||
|
@@ -349,6 +349,15 @@ impl VirtualNic {
|
||||
{
|
||||
let dev_name = self.global_ctx.get_flags().dev_name;
|
||||
|
||||
match crate::arch::windows::add_self_to_firewall_allowlist() {
|
||||
Ok(_) => tracing::info!("add_self_to_firewall_allowlist successful!"),
|
||||
Err(e) => {
|
||||
println!("Failed to add Easytier to firewall allowlist, Subnet proxy and KCP proxy may not work properly. error: {}", e);
|
||||
println!("You can add firewall rules manually, or use --use-smoltcp to run with user-space TCP/IP stack.");
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
|
||||
match checkreg(&dev_name) {
|
||||
Ok(_) => tracing::trace!("delete successful!"),
|
||||
Err(e) => tracing::error!("An error occurred: {}", e),
|
||||
|
Reference in New Issue
Block a user