Files
Easytier/src/arch/windows.rs
T
Sijie.Sun e4be86cf92 allow specify bind dev for tunnels. also fix bugs #46)
1. fix wireguard / udp tunnel stack overflow on win.
2. custom panic handler to save panic stack.
3. fix iface filter on windows and linux.
4. add scheme black list to direct connector
2024-04-03 21:46:52 +08:00

146 lines
4.2 KiB
Rust

use std::{
ffi::c_void,
io::{self, ErrorKind},
mem,
net::SocketAddr,
os::windows::io::AsRawSocket,
ptr,
};
use network_interface::NetworkInterfaceConfig;
use windows_sys::{
core::PCSTR,
Win32::{
Foundation::{BOOL, FALSE},
Networking::WinSock::{
htonl, setsockopt, WSAGetLastError, WSAIoctl, IPPROTO_IP, IPPROTO_IPV6,
IPV6_UNICAST_IF, IP_UNICAST_IF, SIO_UDP_CONNRESET, SOCKET, SOCKET_ERROR,
},
},
};
pub fn disable_connection_reset<S: AsRawSocket>(socket: &S) -> io::Result<()> {
let handle = socket.as_raw_socket() as SOCKET;
unsafe {
// Ignoring UdpSocket's WSAECONNRESET error
// https://github.com/shadowsocks/shadowsocks-rust/issues/179
// https://stackoverflow.com/questions/30749423/is-winsock-error-10054-wsaeconnreset-normal-with-udp-to-from-localhost
//
// This is because `UdpSocket::recv_from` may return WSAECONNRESET
// if you called `UdpSocket::send_to` a destination that is not existed (may be closed).
//
// It is not an error. Could be ignored completely.
// We have to ignore it here because it will crash the server.
let mut bytes_returned: u32 = 0;
let enable: BOOL = FALSE;
let ret = WSAIoctl(
handle,
SIO_UDP_CONNRESET,
&enable as *const _ as *const c_void,
mem::size_of_val(&enable) as u32,
ptr::null_mut(),
0,
&mut bytes_returned as *mut _,
ptr::null_mut(),
None,
);
if ret == SOCKET_ERROR {
use std::io::Error;
// Error occurs
let err_code = WSAGetLastError();
return Err(Error::from_raw_os_error(err_code));
}
}
Ok(())
}
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,
format!("Failed to get interfaces. {}, error: {}", iface_name, e),
)
})?;
if let Some(iface) = ifaces.iter().find(|iface| iface.name == iface_name) {
return Ok(iface.index);
}
tracing::error!("Failed to find interface index for {}", iface_name);
Err(io::Error::new(
ErrorKind::NotFound,
format!("{}", iface_name),
))
}
pub fn set_ip_unicast_if<S: AsRawSocket>(
socket: &S,
addr: &SocketAddr,
iface: &str,
) -> io::Result<()> {
let handle = socket.as_raw_socket() as SOCKET;
let if_index = find_interface_index(iface)?;
unsafe {
// 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,
)
}
SocketAddr::V6(..) => {
// Interface index is in host byte order for IPPROTO_IPV6.
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,
)
}
};
if ret == SOCKET_ERROR {
let err = io::Error::from_raw_os_error(WSAGetLastError());
tracing::error!(
"set IP_UNICAST_IF / IPV6_UNICAST_IF interface: {}, index: {}, error: {}",
iface,
if_index,
err
);
return Err(err);
}
}
Ok(())
}
pub fn setup_socket_for_win<S: AsRawSocket>(
socket: &S,
bind_addr: &SocketAddr,
bind_dev: Option<String>,
is_udp: bool,
) -> io::Result<()> {
if is_udp {
disable_connection_reset(socket)?;
}
if let Some(iface) = bind_dev {
set_ip_unicast_if(socket, bind_addr, iface.as_str())?;
}
Ok(())
}