wintun added

This commit is contained in:
ssrlive 2023-09-18 21:40:56 +08:00
parent 513702e35f
commit 8aeaf238f2
4 changed files with 177 additions and 10 deletions

View file

@ -50,3 +50,13 @@ reqwest = { version = "0.11", default-features = false, features = [
] } ] }
serial_test = "2.0" serial_test = "2.0"
test-log = "0.2" test-log = "0.2"
[target.'cfg(target_os="windows")'.dependencies]
windows = { version = "0.51", features = [
"Win32_NetworkManagement_IpHelper",
"Win32_NetworkManagement_Ndis",
"Win32_Networking_WinSock",
"Win32_Foundation",
] }
wintun = "0.3"
mio = { version = "0.8", features = ["net", "os-ext", "os-poll"] }

View file

@ -23,6 +23,8 @@ mod tuntapinterface;
mod tuntapinterfacedesc; mod tuntapinterfacedesc;
mod virtdevice; mod virtdevice;
mod virtdns; mod virtdns;
#[cfg(target_os = "windows")]
mod wintuninterface;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Proxy { pub struct Proxy {

View file

@ -6,16 +6,17 @@ use crate::{dns, error::Error, error::Result, virtdevice::VirtualTunDevice, Netw
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
use mio::unix::SourceFd; use mio::unix::SourceFd;
use mio::{event::Event, net::TcpStream, net::UdpSocket, Events, Interest, Poll, Token}; use mio::{event::Event, net::TcpStream, net::UdpSocket, Events, Interest, Poll, Token};
#[cfg(not(target_family = "unix"))]
use smoltcp::phy::DeviceCapabilities;
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
use smoltcp::phy::RawSocket; use smoltcp::phy::RawSocket;
// #[cfg(any(target_os = "linux", target_os = "android"))] // #[cfg(any(target_os = "linux", target_os = "android"))]
// use smoltcp::phy::TunTapInterface; // use smoltcp::phy::TunTapInterface;
#[cfg(target_os = "windows")]
use crate::wintuninterface::WinTunInterface;
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
use smoltcp::phy::{Device, Medium, RxToken, TxToken}; use smoltcp::phy::{RxToken, TxToken};
use smoltcp::{ use smoltcp::{
iface::{Config, Interface, SocketHandle, SocketSet}, iface::{Config, Interface, SocketHandle, SocketSet},
phy::{Device, Medium},
socket::{tcp, tcp::State, udp, udp::UdpMetadata}, socket::{tcp, tcp::State, udp, udp::UdpMetadata},
time::Instant, time::Instant,
wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket, UDP_HEADER_LEN}, wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket, UDP_HEADER_LEN},
@ -217,6 +218,8 @@ pub struct TunToProxy<'a> {
tun: TunTapInterface, tun: TunTapInterface,
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
tun: RawSocket, tun: RawSocket,
#[cfg(target_os = "windows")]
tun: WinTunInterface,
poll: Poll, poll: Poll,
iface: Interface, iface: Interface,
connection_map: HashMap<ConnectionInfo, ConnectionState>, connection_map: HashMap<ConnectionInfo, ConnectionState>,
@ -246,6 +249,11 @@ impl<'a> TunToProxy<'a> {
NetworkInterface::Fd(_fd) => panic!("Not supported"), NetworkInterface::Fd(_fd) => panic!("Not supported"),
}; };
#[cfg(target_os = "windows")]
let tun = match _interface {
NetworkInterface::Named(name) => WinTunInterface::new(name.as_str(), Medium::Ip)?,
};
let poll = Poll::new()?; let poll = Poll::new()?;
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
@ -258,19 +266,13 @@ impl<'a> TunToProxy<'a> {
poll.registry() poll.registry()
.register(&mut exit_receiver, EXIT_TOKEN, Interest::READABLE)?; .register(&mut exit_receiver, EXIT_TOKEN, Interest::READABLE)?;
#[cfg(target_family = "unix")]
let config = match tun.capabilities().medium { let config = match tun.capabilities().medium {
Medium::Ethernet => Config::new(smoltcp::wire::EthernetAddress([0x02, 0, 0, 0, 0, 0x01]).into()), Medium::Ethernet => Config::new(smoltcp::wire::EthernetAddress([0x02, 0, 0, 0, 0, 0x01]).into()),
Medium::Ip => Config::new(smoltcp::wire::HardwareAddress::Ip), Medium::Ip => Config::new(smoltcp::wire::HardwareAddress::Ip),
Medium::Ieee802154 => todo!(), Medium::Ieee802154 => todo!(),
}; };
#[cfg(not(target_family = "unix"))]
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
#[cfg(target_family = "unix")]
let mut device = VirtualTunDevice::new(tun.capabilities()); let mut device = VirtualTunDevice::new(tun.capabilities());
#[cfg(not(target_family = "unix"))]
let mut device = VirtualTunDevice::new(DeviceCapabilities::default());
let gateway4: Ipv4Addr = Ipv4Addr::from_str("0.0.0.1")?; let gateway4: Ipv4Addr = Ipv4Addr::from_str("0.0.0.1")?;
let gateway6: Ipv6Addr = Ipv6Addr::from_str("::1")?; let gateway6: Ipv6Addr = Ipv6Addr::from_str("::1")?;
@ -284,7 +286,6 @@ impl<'a> TunToProxy<'a> {
iface.set_any_ip(true); iface.set_any_ip(true);
let tun = Self { let tun = Self {
#[cfg(target_family = "unix")]
tun, tun,
poll, poll,
iface, iface,

154
src/wintuninterface.rs Normal file
View file

@ -0,0 +1,154 @@
use smoltcp::{
phy::{self, Device, DeviceCapabilities, Medium},
time::Instant,
};
use std::{
io,
net::{IpAddr, Ipv4Addr},
sync::Arc,
vec::Vec,
};
/// A virtual TUN (IP) interface.
pub struct WinTunInterface {
inner: Arc<wintun::Session>,
mtu: usize,
medium: Medium,
}
// impl AsRawFd for WinTunInterface {
// fn as_raw_fd(&self) -> RawFd {
// self.inner.borrow().as_raw_fd()
// }
// }
impl WinTunInterface {
pub fn new(name: &str, medium: Medium) -> io::Result<WinTunInterface> {
let wintun = unsafe { wintun::load() }.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let tun_name = name;
let adapter = match wintun::Adapter::open(&wintun, tun_name) {
Ok(a) => a,
Err(_) => wintun::Adapter::create(&wintun, tun_name, tun_name, None)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
};
let address = Ipv4Addr::new(10, 1, 0, 33);
let mask = Ipv4Addr::new(255, 255, 255, 0);
let gateway = Some(IpAddr::V4(Ipv4Addr::new(10, 1, 0, 1)));
adapter
.set_network_addresses_tuple(IpAddr::V4(address), IpAddr::V4(mask), gateway)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let session = adapter
.start_session(wintun::MAX_RING_CAPACITY)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let inner = Arc::new(session);
// let inner = WinTunInterfaceDesc::new(name, medium)?;
// let mtu = inner.interface_mtu()?;
let mtu = 1500;
Ok(WinTunInterface { inner, mtu, medium })
}
}
impl Drop for WinTunInterface {
fn drop(&mut self) {
if let Err(e) = self.inner.shutdown() {
log::error!("phy: failed to shutdown interface: {}", e);
}
}
}
impl Device for WinTunInterface {
type RxToken<'a> = RxToken;
type TxToken<'a> = TxToken;
fn capabilities(&self) -> DeviceCapabilities {
let mut v = DeviceCapabilities::default();
v.max_transmission_unit = self.mtu;
v.medium = self.medium;
v
}
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
let inner = self.inner.clone();
match inner.receive_blocking() {
Ok(read_pack) => Some((
RxToken {
buffer: read_pack.bytes().to_vec(),
},
TxToken { inner },
)),
Err(err) => {
log::error!("phy: failed to receive packet: {}", err);
None
}
}
// match inner.recv(&mut buffer[..]) {
// Ok(size) => {
// buffer.resize(size, 0);
// let rx = RxToken { buffer };
// let tx = TxToken {
// inner: self.inner.clone(),
// };
// Some((rx, tx))
// }
// Err(err) if err.kind() == io::ErrorKind::WouldBlock => None,
// Err(err) => panic!("{}", err),
// }
}
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
Some(TxToken {
inner: self.inner.clone(),
})
}
}
#[doc(hidden)]
pub struct RxToken {
buffer: Vec<u8>,
}
impl phy::RxToken for RxToken {
fn consume<R, F>(mut self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
f(&mut self.buffer[..])
}
}
#[doc(hidden)]
pub struct TxToken {
inner: Arc<wintun::Session>,
}
impl phy::TxToken for TxToken {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let inner = self.inner.clone();
let mut buffer = vec![0; len];
let result = f(&mut buffer);
let write_pack = inner.allocate_send_packet(len as u16);
if let Ok(mut write_pack) = write_pack {
write_pack.bytes_mut().copy_from_slice(&buffer[..]);
inner.send_packet(write_pack);
} else if let Err(err) = write_pack {
log::error!("phy: failed to allocate send packet: {}", err);
}
// match lower.send(&buffer[..]) {
// Ok(_) => {}
// Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
// log::error!("phy: tx failed due to WouldBlock")
// }
// Err(err) => panic!("{}", err),
// }
result
}
}