[mio] 合并各平台的tun/tap处理
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "tun"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.153"
|
||||
|
||||
log = { version = "0.4.20", features = [] }
|
||||
rand = "0.8.5"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||
ioctl = { version = "0.8", package = "ioctl-sys" }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
libloading = "0.8.0"
|
||||
widestring = "1.0.2"
|
||||
winapi = {version = "0.3",features = [
|
||||
"errhandlingapi",
|
||||
"combaseapi",
|
||||
"ioapiset",
|
||||
"winioctl",
|
||||
"setupapi",
|
||||
"synchapi",
|
||||
"netioapi",
|
||||
"fileapi","handleapi","winerror","minwindef","ifdef","basetsd","winnt","winreg","winbase","minwinbase",
|
||||
"impl-default"
|
||||
]}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
use crate::device::IFace;
|
||||
use crate::Fd;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::fd::RawFd;
|
||||
|
||||
pub struct Device {
|
||||
fd: Fd,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn new(fd: RawFd) -> io::Result<Self> {
|
||||
Ok(Self { fd: Fd::new(fd)? })
|
||||
}
|
||||
}
|
||||
impl IFace for Device {
|
||||
fn version(&self) -> io::Result<String> {
|
||||
Ok(String::new())
|
||||
}
|
||||
|
||||
fn name(&self) -> io::Result<String> {
|
||||
Ok(String::new())
|
||||
}
|
||||
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
|
||||
fn mtu(&self) -> io::Result<u32> {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
|
||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.fd.read(buf)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.fd.write(buf)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use io::Result;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
pub trait IFace {
|
||||
fn version(&self) -> Result<String>;
|
||||
/// Get the device name.
|
||||
fn name(&self) -> Result<String>;
|
||||
|
||||
fn shutdown(&self) -> Result<()>;
|
||||
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> Result<()>;
|
||||
|
||||
/// Get the MTU.
|
||||
fn mtu(&self) -> Result<u32>;
|
||||
|
||||
/// Set the MTU.
|
||||
fn set_mtu(&self, value: u32) -> Result<()>;
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> Result<()>;
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> Result<()>;
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize>;
|
||||
fn write(&self, buf: &[u8]) -> Result<usize>;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/// 参考
|
||||
/// https://github.com/meh/rust-tun
|
||||
/// https://github.com/Tazdevil971/tap-windows
|
||||
/// https://github.com/nulldotblack/wintun
|
||||
pub mod device;
|
||||
mod packet;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use linux::Device;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
mod android;
|
||||
#[cfg(target_os = "android")]
|
||||
pub use android::Device;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use macos::Device;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
#[cfg(unix)]
|
||||
pub use unix::Fd;
|
||||
#[cfg(windows)]
|
||||
mod windows;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub use windows::Device;
|
||||
@@ -0,0 +1,303 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::process::Command;
|
||||
use std::{io, mem, ptr};
|
||||
|
||||
use libc::{
|
||||
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TAP, IFF_TUN,
|
||||
IFF_UP, IFNAMSIZ, O_RDWR, SOCK_DGRAM,
|
||||
};
|
||||
|
||||
use crate::device::IFace;
|
||||
use crate::linux::route;
|
||||
use crate::linux::sys::*;
|
||||
use crate::packet;
|
||||
use crate::unix::{exe_cmd, Fd, SockAddr};
|
||||
|
||||
pub struct Device {
|
||||
name: String,
|
||||
ctl: Fd,
|
||||
tun: Fd,
|
||||
mac: Option<[u8; 6]>,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn new(name: Option<&str>, tap: bool) -> io::Result<Self> {
|
||||
let device = unsafe {
|
||||
let dev = match name {
|
||||
Some(name) => {
|
||||
let name =
|
||||
CString::new(name).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
|
||||
if name.as_bytes_with_nul().len() > IFNAMSIZ {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"));
|
||||
}
|
||||
|
||||
Some(name)
|
||||
}
|
||||
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut req: ifreq = mem::zeroed();
|
||||
|
||||
if let Some(dev) = dev.as_ref() {
|
||||
ptr::copy_nonoverlapping(
|
||||
dev.as_ptr() as *const c_char,
|
||||
req.ifr_name.as_mut_ptr(),
|
||||
dev.as_bytes().len(),
|
||||
);
|
||||
}
|
||||
|
||||
let device_type: c_short = if tap { IFF_TAP } else { IFF_TUN } as c_short;
|
||||
|
||||
let queues_num = 1;
|
||||
|
||||
let iff_no_pi = IFF_NO_PI as c_short;
|
||||
let iff_multi_queue = IFF_MULTI_QUEUE as c_short;
|
||||
let packet_information = false;
|
||||
req.ifr_ifru.ifru_flags = device_type
|
||||
| if packet_information { 0 } else { iff_no_pi }
|
||||
| if queues_num > 1 { iff_multi_queue } else { 0 };
|
||||
|
||||
let tun = Fd::new(libc::open(b"/dev/net/tun\0".as_ptr() as *const _, O_RDWR))
|
||||
.map_err(|_| io::Error::last_os_error())?;
|
||||
|
||||
if tunsetiff(tun.0, &mut req as *mut _ as *mut _) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
|
||||
|
||||
let name = CStr::from_ptr(req.ifr_name.as_ptr())
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let mac = if tap {
|
||||
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
|
||||
let mac_out = exe_cmd(&get_mac_cmd)?;
|
||||
let mac_str = String::from_utf8(mac_out.stdout).unwrap();
|
||||
let mut mac = [0; 6];
|
||||
let mut split = mac_str.split(":");
|
||||
for i in 0..6 {
|
||||
mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap();
|
||||
}
|
||||
Some(mac)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Device {
|
||||
name,
|
||||
tun,
|
||||
ctl,
|
||||
mac,
|
||||
}
|
||||
};
|
||||
device.enabled(true)?;
|
||||
Ok(device)
|
||||
}
|
||||
}
|
||||
|
||||
impl Device {
|
||||
fn enabled(&self, value: bool) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
if value {
|
||||
req.ifr_ifru.ifru_flags |= (IFF_UP | IFF_RUNNING) as c_short;
|
||||
} else {
|
||||
req.ifr_ifru.ifru_flags &= !(IFF_UP as c_short);
|
||||
}
|
||||
|
||||
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
unsafe fn request(&self) -> ifreq {
|
||||
let mut req: ifreq = mem::zeroed();
|
||||
ptr::copy_nonoverlapping(
|
||||
self.name.as_ptr() as *const c_char,
|
||||
req.ifr_name.as_mut_ptr(),
|
||||
self.name.len(),
|
||||
);
|
||||
req
|
||||
}
|
||||
fn address(&self) -> io::Result<Ipv4Addr> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifr_ifru.ifru_addr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_address(&self, value: Ipv4Addr) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifr_ifru.ifru_addr = SockAddr::from(value).into();
|
||||
|
||||
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn destination(&self) -> io::Result<Ipv4Addr> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifr_ifru.ifru_dstaddr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_destination(&self, value: Ipv4Addr) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifr_ifru.ifru_dstaddr = SockAddr::from(value).into();
|
||||
|
||||
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn broadcast(&self) -> io::Result<Ipv4Addr> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifr_ifru.ifru_broadaddr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_broadcast(&self, value: Ipv4Addr) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifr_ifru.ifru_broadaddr = SockAddr::from(value).into();
|
||||
|
||||
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn netmask(&self) -> io::Result<Ipv4Addr> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifr_ifru.ifru_netmask).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_netmask(&self, value: Ipv4Addr) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifr_ifru.ifru_netmask = SockAddr::from(value).into();
|
||||
|
||||
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IFace for Device {
|
||||
fn version(&self) -> io::Result<String> {
|
||||
Ok(String::new())
|
||||
}
|
||||
|
||||
fn name(&self) -> io::Result<String> {
|
||||
Ok(self.name.clone())
|
||||
}
|
||||
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
exe_cmd(&format!("ip link delete {}", self.name))?;
|
||||
Ok(())
|
||||
}
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
self.set_address(address)?;
|
||||
self.set_netmask(mask)
|
||||
}
|
||||
|
||||
fn mtu(&self) -> io::Result<u32> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(req.ifr_ifru.ifru_mtu as u32)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifr_ifru.ifru_mtu = value as _;
|
||||
|
||||
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
|
||||
route::add_route(&self.name, dest, netmask)
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
route::del_route(&self.name, dest, netmask)
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
if self.mac.is_some() {
|
||||
packet::read_tap(
|
||||
buf,
|
||||
|eth_buf| self.tun.read(eth_buf),
|
||||
|eth_buf| self.tun.write(eth_buf),
|
||||
)
|
||||
} else {
|
||||
self.tun.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
if let Some(mac) = &self.mac {
|
||||
packet::write_tap(buf, |eth_buf| self.tun.write(eth_buf), mac)
|
||||
} else {
|
||||
self.tun.write(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
mod device;
|
||||
pub use device::Device;
|
||||
mod route;
|
||||
mod sys;
|
||||
@@ -0,0 +1,16 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::unix::exe_cmd;
|
||||
|
||||
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let cmd = format!("ip route add {:?}/{:?} dev {}", address, netmask, name);
|
||||
exe_cmd(&cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn del_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let cmd = format!("ip route del {:?}/{:?} dev {}", address, netmask, name);
|
||||
exe_cmd(&cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use ioctl::*;
|
||||
use libc::{c_int, ifreq};
|
||||
|
||||
ioctl!(bad read siocgifflags with 0x8913; ifreq);
|
||||
ioctl!(bad write siocsifflags with 0x8914; ifreq);
|
||||
ioctl!(bad read siocgifaddr with 0x8915; ifreq);
|
||||
ioctl!(bad write siocsifaddr with 0x8916; ifreq);
|
||||
ioctl!(bad read siocgifdstaddr with 0x8917; ifreq);
|
||||
ioctl!(bad write siocsifdstaddr with 0x8918; ifreq);
|
||||
ioctl!(bad read siocgifbrdaddr with 0x8919; ifreq);
|
||||
ioctl!(bad write siocsifbrdaddr with 0x891a; ifreq);
|
||||
ioctl!(bad read siocgifnetmask with 0x891b; ifreq);
|
||||
ioctl!(bad write siocsifnetmask with 0x891c; ifreq);
|
||||
ioctl!(bad read siocgifmtu with 0x8921; ifreq);
|
||||
ioctl!(bad write siocsifmtu with 0x8922; ifreq);
|
||||
ioctl!(bad write siocsifname with 0x8923; ifreq);
|
||||
|
||||
ioctl!(write tunsetiff with b'T', 202; c_int);
|
||||
ioctl!(write tunsetpersist with b'T', 203; c_int);
|
||||
ioctl!(write tunsetowner with b'T', 204; c_int);
|
||||
ioctl!(write tunsetgroup with b'T', 206; c_int);
|
||||
@@ -0,0 +1,286 @@
|
||||
use std::ffi::{c_void, CStr};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::{io, mem, ptr};
|
||||
|
||||
use libc::{
|
||||
c_char, c_short, c_uint, sockaddr, socklen_t, AF_INET, AF_SYSTEM, AF_SYS_CONTROL, IFF_RUNNING,
|
||||
IFF_UP, IFNAMSIZ, PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
|
||||
};
|
||||
|
||||
use crate::device::IFace;
|
||||
use crate::macos::route;
|
||||
use crate::macos::sys::*;
|
||||
use crate::unix::{Fd, SockAddr};
|
||||
|
||||
pub struct Device {
|
||||
name: String,
|
||||
ctl: Fd,
|
||||
tun: Fd,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn new(name: Option<&str>) -> io::Result<Self> {
|
||||
let id = if let Some(name) = name {
|
||||
if name.len() > IFNAMSIZ {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"));
|
||||
}
|
||||
|
||||
if !name.starts_with("utun") {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid name"));
|
||||
}
|
||||
|
||||
name[4..]
|
||||
.parse::<u32>()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
|
||||
+ 1u32
|
||||
} else {
|
||||
0u32
|
||||
};
|
||||
let device = unsafe {
|
||||
let tun = Fd::new(libc::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))?;
|
||||
|
||||
let mut info = ctl_info {
|
||||
ctl_id: 0,
|
||||
ctl_name: {
|
||||
let mut buffer = [0; 96];
|
||||
for (i, o) in UTUN_CONTROL_NAME.as_bytes().iter().zip(buffer.iter_mut()) {
|
||||
*o = *i as _;
|
||||
}
|
||||
buffer
|
||||
},
|
||||
};
|
||||
|
||||
if ctliocginfo(tun.0, &mut info as *mut _ as *mut _) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let addr = sockaddr_ctl {
|
||||
sc_id: info.ctl_id,
|
||||
sc_len: mem::size_of::<sockaddr_ctl>() as _,
|
||||
sc_family: AF_SYSTEM as _,
|
||||
ss_sysaddr: AF_SYS_CONTROL as _,
|
||||
sc_unit: id as c_uint,
|
||||
sc_reserved: [0; 5],
|
||||
};
|
||||
|
||||
let address = &addr as *const sockaddr_ctl as *const sockaddr;
|
||||
if libc::connect(tun.0, address, mem::size_of_val(&addr) as socklen_t) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let mut name = [0u8; 64];
|
||||
let mut name_len: socklen_t = 64;
|
||||
|
||||
let optval = &mut name as *mut _ as *mut c_void;
|
||||
let optlen = &mut name_len as *mut socklen_t;
|
||||
if libc::getsockopt(tun.0, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, optval, optlen) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
|
||||
|
||||
Device {
|
||||
name: CStr::from_ptr(name.as_ptr() as *const c_char)
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
tun,
|
||||
ctl,
|
||||
}
|
||||
};
|
||||
device.enabled(true)?;
|
||||
Ok(device)
|
||||
}
|
||||
}
|
||||
|
||||
impl Device {
|
||||
fn enabled(&self, value: bool) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
if value {
|
||||
req.ifru.flags |= (IFF_UP | IFF_RUNNING) as c_short;
|
||||
} else {
|
||||
req.ifru.flags &= !(IFF_UP as c_short);
|
||||
}
|
||||
|
||||
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
unsafe fn request(&self) -> ifreq {
|
||||
let mut req: ifreq = mem::zeroed();
|
||||
ptr::copy_nonoverlapping(
|
||||
self.name.as_ptr() as *const c_char,
|
||||
req.ifrn.name.as_mut_ptr(),
|
||||
self.name.len(),
|
||||
);
|
||||
req
|
||||
}
|
||||
fn address(&self) -> io::Result<Ipv4Addr> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifru.addr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_address(&self, value: Ipv4Addr) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifru.addr = SockAddr::from(value).into();
|
||||
|
||||
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn destination(&self) -> io::Result<Ipv4Addr> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_destination(&self, value: Ipv4Addr) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifru.dstaddr = SockAddr::from(value).into();
|
||||
|
||||
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn broadcast(&self) -> io::Result<Ipv4Addr> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_broadcast(&self, value: Ipv4Addr) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifru.broadaddr = SockAddr::from(value).into();
|
||||
|
||||
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn netmask(&self) -> io::Result<Ipv4Addr> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
SockAddr::unchecked(&req.ifru.addr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_netmask(&self, value: Ipv4Addr) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifru.addr = SockAddr::from(value).into();
|
||||
|
||||
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IFace for Device {
|
||||
fn version(&self) -> io::Result<String> {
|
||||
Ok(String::new())
|
||||
}
|
||||
|
||||
fn name(&self) -> io::Result<String> {
|
||||
Ok(self.name.clone())
|
||||
}
|
||||
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
self.enabled(false)
|
||||
}
|
||||
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
self.set_address(address)?;
|
||||
self.set_netmask(mask)
|
||||
}
|
||||
|
||||
fn mtu(&self) -> io::Result<u32> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(req.ifru.mtu as _)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifru.mtu = value as _;
|
||||
|
||||
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
|
||||
route::add_route(&self.name, dest, netmask)
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
route::del_route(&self.name, dest, netmask)
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.tun.read(buf)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.tun.write(buf)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mod device;
|
||||
pub use device::Device;
|
||||
mod sys;
|
||||
|
||||
mod route;
|
||||
@@ -0,0 +1,18 @@
|
||||
use crate::unix::exe_cmd;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let cmd = format!(
|
||||
"route -n add {} -netmask {} -interface {}",
|
||||
address, netmask, name
|
||||
);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
pub fn del_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let cmd = format!(
|
||||
"route -n delete {} -netmask {} -interface {}",
|
||||
address, netmask, name
|
||||
);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
@@ -1,35 +1,11 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
//! Bindings to internal macOS stuff.
|
||||
|
||||
use ioctl::*;
|
||||
use libc::sockaddr;
|
||||
use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void};
|
||||
use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void, sockaddr, IFNAMSIZ};
|
||||
|
||||
pub const IFNAMSIZ: usize = 16;
|
||||
|
||||
pub const IFF_UP: c_short = 0x1;
|
||||
pub const IFF_RUNNING: c_short = 0x40;
|
||||
|
||||
pub const AF_SYS_CONTROL: c_ushort = 2;
|
||||
pub const AF_SYSTEM: c_char = 32;
|
||||
pub const PF_SYSTEM: c_int = AF_SYSTEM as c_int;
|
||||
pub const SYSPROTO_CONTROL: c_int = 2;
|
||||
pub const UTUN_OPT_IFNAME: c_int = 2;
|
||||
pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ctl_info {
|
||||
@@ -37,6 +13,7 @@ pub struct ctl_info {
|
||||
pub ctl_name: [c_char; 96],
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct sockaddr_ctl {
|
||||
@@ -54,6 +31,7 @@ pub union ifrn {
|
||||
pub name: [c_char; IFNAMSIZ],
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ifdevmtu {
|
||||
@@ -69,6 +47,7 @@ pub union ifku {
|
||||
pub value: c_int,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ifkpi {
|
||||
@@ -98,6 +77,7 @@ pub union ifru {
|
||||
pub functional_type: c_uint,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ifreq {
|
||||
@@ -105,6 +85,7 @@ pub struct ifreq {
|
||||
pub ifru: ifru,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ifaliasreq {
|
||||
@@ -0,0 +1 @@
|
||||
pub mod packet;
|
||||
@@ -0,0 +1,122 @@
|
||||
use std::{fmt, io};
|
||||
|
||||
/// 地址解析协议,由IP地址找到MAC地址
|
||||
/// https://www.ietf.org/rfc/rfc6747.txt
|
||||
/*
|
||||
0 2 4 5 6 8 10 (字节)
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 硬件类型|协议类型|硬件地址长度|协议地址长度|操作类型|
|
||||
| 源MAC地址 | 源ip地址 |
|
||||
| 目的MAC地址 | 目的ip地址 |
|
||||
*/
|
||||
|
||||
pub struct ArpPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ArpPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() != 28 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ArpPacket<B> {
|
||||
/// 硬件类型 以太网类型为1
|
||||
pub fn hardware_type(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
|
||||
}
|
||||
/// 上层协议类型,ipv4是0x0800
|
||||
pub fn protocol_type(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
/// 如果是MAC地址 则长度为6
|
||||
pub fn hardware_size(&self) -> u8 {
|
||||
self.buffer.as_ref()[4]
|
||||
}
|
||||
/// 如果是IPv4 则长度为4
|
||||
pub fn protocol_size(&self) -> u8 {
|
||||
self.buffer.as_ref()[5]
|
||||
}
|
||||
/// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3:RARP请求,4:RARP响应
|
||||
pub fn op_code(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
|
||||
}
|
||||
/// 发送端硬件地址,仅支持以太网
|
||||
pub fn sender_hardware_addr(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[8..14]
|
||||
}
|
||||
/// 发送端协议地址,仅支持IPv4
|
||||
pub fn sender_protocol_addr(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[14..18]
|
||||
}
|
||||
/// 接收端硬件地址,仅支持以太网
|
||||
pub fn target_hardware_addr(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[18..24]
|
||||
}
|
||||
/// 接收端协议地址,仅支持IPv4
|
||||
pub fn target_protocol_addr(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[24..28]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> ArpPacket<B> {
|
||||
/// 硬件类型 以太网类型为1
|
||||
pub fn set_hardware_type(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
/// 上层协议类型,ipv4是0x0800
|
||||
pub fn set_protocol_type(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
/// 如果是MAC地址 则长度为6
|
||||
pub fn set_hardware_size(&mut self, value: u8) {
|
||||
self.buffer.as_mut()[4] = value
|
||||
}
|
||||
/// 如果是IPv4 则长度为4
|
||||
pub fn set_protocol_size(&mut self, value: u8) {
|
||||
self.buffer.as_mut()[5] = value
|
||||
}
|
||||
/// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3:RARP请求,4:RARP响应
|
||||
pub fn set_op_code(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
/// 发送端硬件地址,仅支持以太网
|
||||
pub fn set_sender_hardware_addr(&mut self, buf: &[u8]) {
|
||||
self.buffer.as_mut()[8..14].copy_from_slice(buf)
|
||||
}
|
||||
/// 发送端协议地址,仅支持IPv4
|
||||
pub fn set_sender_protocol_addr(&mut self, buf: &[u8]) {
|
||||
self.buffer.as_mut()[14..18].copy_from_slice(buf)
|
||||
}
|
||||
/// 接收端硬件地址,仅支持以太网
|
||||
pub fn set_target_hardware_addr(&mut self, buf: &[u8]) {
|
||||
self.buffer.as_mut()[18..24].copy_from_slice(buf)
|
||||
}
|
||||
/// 接收端协议地址,仅支持IPv4
|
||||
pub fn set_target_protocol_addr(&mut self, buf: &[u8]) {
|
||||
self.buffer.as_mut()[24..28].copy_from_slice(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for ArpPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ArpPacket")
|
||||
.field("hardware_type", &self.hardware_type())
|
||||
.field("protocol_type", &self.protocol_type())
|
||||
.field("hardware_size", &self.hardware_size())
|
||||
.field("protocol_size", &self.protocol_size())
|
||||
.field("op_code", &self.op_code())
|
||||
.field("sender_hardware_addr", &self.sender_hardware_addr())
|
||||
.field("sender_protocol_addr", &self.sender_protocol_addr())
|
||||
.field("target_hardware_addr", &self.target_hardware_addr())
|
||||
.field("target_protocol_addr", &self.target_protocol_addr())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod packet;
|
||||
pub mod protocol;
|
||||
@@ -0,0 +1,77 @@
|
||||
use crate::packet::ethernet::protocol::Protocol;
|
||||
use std::{fmt, io};
|
||||
|
||||
/// 以太网帧协议
|
||||
/// https://www.ietf.org/rfc/rfc894.txt
|
||||
/*
|
||||
0 6 12 14 (字节)
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 目的地址 | 源地址 | 类型 |
|
||||
*/
|
||||
pub struct EthernetPacket<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> EthernetPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> EthernetPacket<B> {
|
||||
EthernetPacket { buffer }
|
||||
}
|
||||
|
||||
pub fn new(buffer: B) -> io::Result<EthernetPacket<B>> {
|
||||
let packet = EthernetPacket::unchecked(buffer);
|
||||
//头部固定14位
|
||||
if packet.buffer.as_ref().len() < 14 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> EthernetPacket<B> {
|
||||
/// 目的MAC地址
|
||||
pub fn destination(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[0..6]
|
||||
}
|
||||
/// 源MAC地址
|
||||
pub fn source(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[6..12]
|
||||
}
|
||||
/// 3层协议
|
||||
pub fn protocol(&self) -> Protocol {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[12..14].try_into().unwrap()).into()
|
||||
}
|
||||
/// 载荷
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[14..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> EthernetPacket<B> {
|
||||
pub fn set_destination(&mut self, value: &[u8]) {
|
||||
self.buffer.as_mut()[0..6].copy_from_slice(value);
|
||||
}
|
||||
|
||||
pub fn set_source(&mut self, value: &[u8]) {
|
||||
self.buffer.as_mut()[6..12].copy_from_slice(value);
|
||||
}
|
||||
|
||||
pub fn set_protocol(&mut self, value: Protocol) {
|
||||
let p: u16 = value.into();
|
||||
self.buffer.as_mut()[12..14].copy_from_slice(&p.to_be_bytes())
|
||||
}
|
||||
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[14..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for EthernetPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("EthernetPacket")
|
||||
.field("destination", &self.destination())
|
||||
.field("source", &self.source())
|
||||
.field("protocol", &self.protocol())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/// 以太网帧协议
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
///
|
||||
Ipv4,
|
||||
|
||||
///
|
||||
Arp,
|
||||
|
||||
///
|
||||
WakeOnLan,
|
||||
|
||||
///
|
||||
Trill,
|
||||
|
||||
///
|
||||
DecNet,
|
||||
|
||||
///
|
||||
Rarp,
|
||||
|
||||
///
|
||||
AppleTalk,
|
||||
|
||||
///
|
||||
Aarp,
|
||||
|
||||
///
|
||||
Ipx,
|
||||
|
||||
///
|
||||
Qnx,
|
||||
|
||||
///
|
||||
Ipv6,
|
||||
|
||||
///
|
||||
FlowControl,
|
||||
|
||||
///
|
||||
CobraNet,
|
||||
|
||||
///
|
||||
Mpls,
|
||||
|
||||
///
|
||||
MplsMulticast,
|
||||
|
||||
///
|
||||
PppoeDiscovery,
|
||||
|
||||
///
|
||||
PppoeSession,
|
||||
|
||||
///
|
||||
Vlan,
|
||||
|
||||
///
|
||||
PBridge,
|
||||
|
||||
///
|
||||
Lldp,
|
||||
|
||||
///
|
||||
Ptp,
|
||||
|
||||
///
|
||||
Cfm,
|
||||
|
||||
///
|
||||
QinQ,
|
||||
|
||||
///
|
||||
Unknown(u16),
|
||||
}
|
||||
|
||||
impl From<u16> for Protocol {
|
||||
fn from(value: u16) -> Protocol {
|
||||
use self::Protocol::*;
|
||||
|
||||
match value {
|
||||
0x0800 => Ipv4,
|
||||
0x0806 => Arp,
|
||||
0x0842 => WakeOnLan,
|
||||
0x22f3 => Trill,
|
||||
0x6003 => DecNet,
|
||||
0x8035 => Rarp,
|
||||
0x809b => AppleTalk,
|
||||
0x80f3 => Aarp,
|
||||
0x8137 => Ipx,
|
||||
0x8204 => Qnx,
|
||||
0x86dd => Ipv6,
|
||||
0x8808 => FlowControl,
|
||||
0x8819 => CobraNet,
|
||||
0x8847 => Mpls,
|
||||
0x8848 => MplsMulticast,
|
||||
0x8863 => PppoeDiscovery,
|
||||
0x8864 => PppoeSession,
|
||||
0x8100 => Vlan,
|
||||
0x88a8 => PBridge,
|
||||
0x88cc => Lldp,
|
||||
0x88f7 => Ptp,
|
||||
0x8902 => Cfm,
|
||||
0x9100 => QinQ,
|
||||
n => Unknown(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u16> for Protocol {
|
||||
fn into(self) -> u16 {
|
||||
use self::Protocol::*;
|
||||
|
||||
match self {
|
||||
Ipv4 => 0x0800,
|
||||
Arp => 0x0806,
|
||||
WakeOnLan => 0x0842,
|
||||
Trill => 0x22f3,
|
||||
DecNet => 0x6003,
|
||||
Rarp => 0x8035,
|
||||
AppleTalk => 0x809b,
|
||||
Aarp => 0x80f3,
|
||||
Ipx => 0x8137,
|
||||
Qnx => 0x8204,
|
||||
Ipv6 => 0x86dd,
|
||||
FlowControl => 0x8808,
|
||||
CobraNet => 0x8819,
|
||||
Mpls => 0x8847,
|
||||
MplsMulticast => 0x8848,
|
||||
PppoeDiscovery => 0x8863,
|
||||
PppoeSession => 0x8864,
|
||||
Vlan => 0x8100,
|
||||
PBridge => 0x88a8,
|
||||
Lldp => 0x88cc,
|
||||
Ptp => 0x88f7,
|
||||
Cfm => 0x8902,
|
||||
QinQ => 0x9100,
|
||||
Unknown(n) => n,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
use crate::packet::ethernet::protocol::Protocol;
|
||||
use std::io;
|
||||
|
||||
pub mod arp;
|
||||
pub mod ethernet;
|
||||
|
||||
const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9];
|
||||
pub fn read_tap<W, R>(buf: &mut [u8], read_fn: R, write_fn: W) -> io::Result<usize>
|
||||
where
|
||||
W: Fn(&[u8]) -> io::Result<usize>,
|
||||
R: Fn(&mut [u8]) -> io::Result<usize>,
|
||||
{
|
||||
let mut eth_buf = [0; 65536];
|
||||
loop {
|
||||
let len = read_fn(&mut eth_buf)?;
|
||||
//处理arp包
|
||||
let mut ether = ethernet::packet::EthernetPacket::unchecked(&mut eth_buf[..len]);
|
||||
match ether.protocol() {
|
||||
Protocol::Ipv4 => {
|
||||
let len = ether.payload().len();
|
||||
if len > buf.len() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "short"));
|
||||
}
|
||||
buf[..len].copy_from_slice(ether.payload());
|
||||
return Ok(len);
|
||||
}
|
||||
Protocol::Arp => {
|
||||
let mut arp_packet = arp::packet::ArpPacket::unchecked(ether.payload_mut());
|
||||
let sender_h: [u8; 6] = arp_packet.sender_hardware_addr().try_into().unwrap();
|
||||
let sender_p: [u8; 4] = arp_packet.sender_protocol_addr().try_into().unwrap();
|
||||
let target_p: [u8; 4] = arp_packet.target_protocol_addr().try_into().unwrap();
|
||||
if target_p == [0, 0, 0, 0] || sender_p == [0, 0, 0, 0] || target_p == sender_p {
|
||||
continue;
|
||||
}
|
||||
if arp_packet.op_code() == 1 {
|
||||
//回复一个默认的MAC
|
||||
arp_packet.set_op_code(2);
|
||||
arp_packet.set_target_hardware_addr(&sender_h);
|
||||
arp_packet.set_target_protocol_addr(&sender_p);
|
||||
arp_packet.set_sender_protocol_addr(&target_p);
|
||||
arp_packet.set_sender_hardware_addr(&MAC);
|
||||
ether.set_destination(&sender_h);
|
||||
ether.set_source(&MAC);
|
||||
write_fn(ether.buffer)?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
//忽略这些数据
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn write_tap<W>(buf: &[u8], write_fn: W, mac: &[u8; 6]) -> io::Result<usize>
|
||||
where
|
||||
W: Fn(&[u8]) -> io::Result<usize>,
|
||||
{
|
||||
// 封装二层数据
|
||||
let mut ether = ethernet::packet::EthernetPacket::unchecked(vec![0; 14 + buf.len()]);
|
||||
ether.set_source(&MAC);
|
||||
ether.set_destination(mac);
|
||||
ether.set_protocol(Protocol::Ipv4);
|
||||
ether.payload_mut().copy_from_slice(buf);
|
||||
write_fn(ðer.buffer)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
use std::io;
|
||||
use std::os::fd::{AsRawFd, IntoRawFd, RawFd};
|
||||
|
||||
pub struct Fd(pub RawFd);
|
||||
|
||||
impl Fd {
|
||||
pub fn new(value: RawFd) -> io::Result<Self> {
|
||||
if value < 0 {
|
||||
return Err(io::Error::from(io::ErrorKind::InvalidInput));
|
||||
}
|
||||
Ok(Fd(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl Fd {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len());
|
||||
|
||||
if amount < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(amount as usize)
|
||||
}
|
||||
}
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len());
|
||||
|
||||
if amount < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(amount as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Fd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Fd {
|
||||
fn into_raw_fd(mut self) -> RawFd {
|
||||
let fd = self.0;
|
||||
self.0 = -1;
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Fd {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.0 >= 0 {
|
||||
libc::close(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
mod fd;
|
||||
|
||||
pub use fd::Fd;
|
||||
use std::process::Output;
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
mod sockaddr;
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
pub use sockaddr::SockAddr;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
pub fn exe_cmd(cmd: &str) -> std::io::Result<Output> {
|
||||
use std::io;
|
||||
use std::process::Command;
|
||||
println!("exe cmd: {}", cmd);
|
||||
let out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(cmd)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !out.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("cmd={},out={:?}", cmd, out),
|
||||
));
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
@@ -1,46 +1,17 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::mem;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::ptr;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
use libc::c_uchar;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use libc::c_ushort;
|
||||
|
||||
use libc::AF_INET as _AF_INET;
|
||||
use libc::{in_addr, sockaddr, sockaddr_in};
|
||||
use std::{io, mem, net::Ipv4Addr, ptr};
|
||||
|
||||
use crate::error::*;
|
||||
use io::Result;
|
||||
|
||||
/// A wrapper for `sockaddr_in`.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SockAddr(sockaddr_in);
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
const AF_INET: c_ushort = _AF_INET as c_ushort;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
const AF_INET: c_uchar = _AF_INET as c_uchar;
|
||||
|
||||
impl SockAddr {
|
||||
/// Create a new `SockAddr` from a generic `sockaddr`.
|
||||
pub fn new(value: &sockaddr) -> Result<Self> {
|
||||
if value.sa_family != AF_INET {
|
||||
return Err(Error::InvalidAddress);
|
||||
if value.sa_family != libc::AF_INET as libc::sa_family_t {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "invalid address"));
|
||||
}
|
||||
|
||||
unsafe { Self::unchecked(value) }
|
||||
@@ -64,7 +35,7 @@ impl From<Ipv4Addr> for SockAddr {
|
||||
let octets = ip.octets();
|
||||
let mut addr = unsafe { mem::zeroed::<sockaddr_in>() };
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_family = libc::AF_INET as libc::sa_family_t;
|
||||
addr.sin_port = 0;
|
||||
addr.sin_addr = in_addr {
|
||||
s_addr: u32::from_ne_bytes(octets),
|
||||
@@ -0,0 +1,92 @@
|
||||
use crate::device::IFace;
|
||||
use crate::windows::{tap, tun};
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub enum Device {
|
||||
Tap(tap::Device),
|
||||
Tun(tun::Device),
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn new(name: &str, tap: bool) -> io::Result<Self> {
|
||||
if tap {
|
||||
Ok(Device::Tap(tap::Device::new(name)?))
|
||||
} else {
|
||||
Ok(Device::Tun(tun::Device::new(name)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IFace for Device {
|
||||
fn version(&self) -> io::Result<String> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.version(),
|
||||
Device::Tun(dev) => dev.version(),
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> io::Result<String> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.name(),
|
||||
Device::Tun(dev) => dev.name(),
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.shutdown(),
|
||||
Device::Tun(dev) => dev.shutdown(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.set_ip(address, mask),
|
||||
Device::Tun(dev) => dev.set_ip(address, mask),
|
||||
}
|
||||
}
|
||||
|
||||
fn mtu(&self) -> io::Result<u32> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.mtu(),
|
||||
Device::Tun(dev) => dev.mtu(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.set_mtu(value),
|
||||
Device::Tun(dev) => dev.set_mtu(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.add_route(dest, netmask, metric),
|
||||
Device::Tun(dev) => dev.add_route(dest, netmask, metric),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.delete_route(dest, netmask),
|
||||
Device::Tun(dev) => dev.delete_route(dest, netmask),
|
||||
}
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.read(buf),
|
||||
Device::Tun(dev) => dev.read(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
match self {
|
||||
Device::Tap(dev) => dev.write(buf),
|
||||
Device::Tun(dev) => dev.write(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ pub fn read_file(handle: HANDLE, buffer: &mut [u8]) -> io::Result<DWORD> {
|
||||
&mut ip_overlapped,
|
||||
) {
|
||||
let e = io::Error::last_os_error();
|
||||
if e.raw_os_error().unwrap_or(0) == 997 {
|
||||
if e.raw_os_error().unwrap_or(0) == ERROR_IO_PENDING as _ {
|
||||
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
|
||||
return Err(e);
|
||||
}
|
||||
@@ -166,7 +166,7 @@ pub fn write_file(handle: HANDLE, buffer: &[u8]) -> io::Result<DWORD> {
|
||||
&mut ip_overlapped,
|
||||
) {
|
||||
let e = io::Error::last_os_error();
|
||||
if e.raw_os_error().unwrap_or(0) == 997 {
|
||||
if e.raw_os_error().unwrap_or(0) == ERROR_IO_PENDING as _ {
|
||||
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
|
||||
return Err(e);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use std::io;
|
||||
use std::os::windows::process::CommandExt;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::winbase::CREATE_NO_WINDOW;
|
||||
|
||||
mod device;
|
||||
mod ffi;
|
||||
mod netsh;
|
||||
mod route;
|
||||
mod tap;
|
||||
mod tun;
|
||||
pub use device::Device;
|
||||
|
||||
/// Encode a string as a utf16 buffer
|
||||
pub fn encode_utf16(string: &str) -> Vec<u16> {
|
||||
use std::iter::once;
|
||||
string.encode_utf16().chain(once(0)).collect()
|
||||
}
|
||||
|
||||
pub fn decode_utf16(string: &[u16]) -> String {
|
||||
let end = string.iter().position(|b| *b == 0).unwrap_or(string.len());
|
||||
String::from_utf16_lossy(&string[..end])
|
||||
}
|
||||
|
||||
pub const fn ctl_code(device_type: DWORD, function: DWORD, method: DWORD, access: DWORD) -> DWORD {
|
||||
(device_type << 16) | (access << 14) | (function << 2) | method
|
||||
}
|
||||
|
||||
pub fn exe_cmd(cmd: &str) -> io::Result<()> {
|
||||
println!("exe cmd: {}", cmd);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(CREATE_NO_WINDOW)
|
||||
.arg("/C")
|
||||
.arg(&cmd)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("cmd={},out={:?}", cmd, String::from_utf8(out.stderr)),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use crate::windows::exe_cmd;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::{io, process};
|
||||
|
||||
/// 设置网卡名称
|
||||
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
|
||||
let cmd = format!(
|
||||
" netsh interface set interface name={:?} newname={:?}",
|
||||
old_name, new_name
|
||||
);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
/// 删除缓存
|
||||
pub fn delete_cache() -> io::Result<()> {
|
||||
//清除缓存
|
||||
let cmd = "netsh interface ip delete destinationcache";
|
||||
exe_cmd(cmd)
|
||||
}
|
||||
|
||||
/// 设置网卡ip
|
||||
pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> io::Result<()> {
|
||||
let cmd = format!(
|
||||
"netsh interface ip set address {} static {:?} {:?} ",
|
||||
index, address, netmask,
|
||||
);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
|
||||
pub fn set_interface_mtu(index: u32, mtu: u32) -> io::Result<()> {
|
||||
let cmd = format!(
|
||||
"netsh interface ipv4 set subinterface {} mtu={} store=persistent",
|
||||
index, mtu
|
||||
);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
|
||||
let cmd = format!(
|
||||
"netsh interface ip set interface {} metric={}",
|
||||
index, metric
|
||||
);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
/// 禁用ipv6
|
||||
pub fn disabled_ipv6(index: u32) -> io::Result<()> {
|
||||
let cmd = format!("netsh interface ipv6 set interface {} disabled", index);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::windows::exe_cmd;
|
||||
|
||||
/// 添加路由
|
||||
pub fn add_route(
|
||||
index: u32,
|
||||
dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
metric: u16,
|
||||
) -> io::Result<()> {
|
||||
let cmd = format!(
|
||||
"route add {:?} mask {:?} {:?} metric {} if {}",
|
||||
dest, netmask, gateway, metric, index
|
||||
);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
|
||||
/// 删除路由
|
||||
pub fn delete_route(
|
||||
index: u32,
|
||||
dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
let cmd = format!(
|
||||
"route delete {:?} mask {:?} {:?} if {}",
|
||||
dest, netmask, gateway, index
|
||||
);
|
||||
exe_cmd(&cmd)
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use winapi::shared::ifdef::NET_LUID;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::fileapi::OPEN_EXISTING;
|
||||
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
|
||||
use winapi::um::winioctl::{FILE_ANY_ACCESS, FILE_DEVICE_UNKNOWN, METHOD_BUFFERED};
|
||||
use winapi::um::winnt::{
|
||||
FILE_ATTRIBUTE_SYSTEM, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE,
|
||||
};
|
||||
|
||||
use crate::device::IFace;
|
||||
use crate::packet;
|
||||
use crate::packet::ethernet::protocol::Protocol;
|
||||
use crate::packet::{arp, ethernet};
|
||||
use crate::windows::{ctl_code, decode_utf16, encode_utf16, ffi, netsh, route};
|
||||
|
||||
/* Present in 8.1 */
|
||||
const TAP_WIN_IOCTL_GET_MAC: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
const TAP_WIN_IOCTL_GET_VERSION: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
const TAP_WIN_IOCTL_GET_MTU: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
const TAP_WIN_IOCTL_GET_INFO: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 4, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
const TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 5, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
const TAP_WIN_IOCTL_SET_MEDIA_STATUS: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
const TAP_WIN_IOCTL_CONFIG_DHCP_MASQ: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 7, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
const TAP_WIN_IOCTL_GET_LOG_LINE: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 8, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
const TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 9, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
/* Added in 8.2 */
|
||||
/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
|
||||
const TAP_WIN_IOCTL_CONFIG_TUN: DWORD =
|
||||
ctl_code(FILE_DEVICE_UNKNOWN, 10, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
||||
|
||||
pub struct Device {
|
||||
handle: HANDLE,
|
||||
index: u32,
|
||||
luid: NET_LUID,
|
||||
mac: [u8; 6],
|
||||
}
|
||||
|
||||
unsafe impl Send for Device {}
|
||||
|
||||
unsafe impl Sync for Device {}
|
||||
|
||||
impl Device {
|
||||
/// 打开设备,设置为TUN模式,激活网卡
|
||||
pub fn new(name_str: &str) -> io::Result<Self> {
|
||||
let name = encode_utf16(name_str);
|
||||
let luid = ffi::alias_to_luid(&name).map_err(|e| {
|
||||
io::Error::new(
|
||||
e.kind(),
|
||||
format!("alias_to_luid name={},err={:?}", name_str, e),
|
||||
)
|
||||
})?;
|
||||
let guid = ffi::luid_to_guid(&luid)
|
||||
.and_then(|guid| ffi::string_from_guid(&guid))
|
||||
.map_err(|e| {
|
||||
io::Error::new(
|
||||
e.kind(),
|
||||
format!("luid_to_guid name={},err={:?}", name_str, e),
|
||||
)
|
||||
})?;
|
||||
let path = format!(r"\\.\Global\{}.tap", decode_utf16(&guid));
|
||||
let handle = ffi::create_file(
|
||||
&encode_utf16(&path),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
|
||||
)
|
||||
.map_err(|e| io::Error::new(e.kind(), format!("tap name={},err={:?}", name_str, e)))?;
|
||||
|
||||
// ep保存tun网卡的IP地址和掩码
|
||||
// let mut ep = [0;3];
|
||||
// ep[0] = Ipv4Addr::new(10,26,0,11).into();
|
||||
// ep[2] = Ipv4Addr::new(255,255,255,0).into();;
|
||||
// ep[1] = ep[0] & ep[2];
|
||||
// //tun模式收不到ipv4包,原因未知 https://github.com/OpenVPN/tap-windows6/issues/111
|
||||
// ffi::device_io_control(handle, TAP_WIN_IOCTL_CONFIG_TUN, &ep, &mut ()).map_err(
|
||||
// |e| {
|
||||
// io::Error::new(
|
||||
// e.kind(),
|
||||
// format!("TAP_WIN_IOCTL_CONFIG_TUN name={},err={:?}", name_str, e),
|
||||
// )
|
||||
// },
|
||||
// )?;
|
||||
let mut mac = [0u8; 6];
|
||||
ffi::device_io_control(handle, TAP_WIN_IOCTL_GET_MAC, &(), &mut mac)
|
||||
.map_err(|e| {
|
||||
io::Error::new(
|
||||
e.kind(),
|
||||
format!("TAP_WIN_IOCTL_CONFIG_TUN name={},err={:?}", name_str, e),
|
||||
)
|
||||
})
|
||||
.map_err(|e| io::Error::new(e.kind(), format!("TAP_WIN_IOCTL_GET_MAC,err={:?}", e)))?;
|
||||
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||
// 设置网卡跃点
|
||||
netsh::set_interface_metric(index, 0)?;
|
||||
let device = Self {
|
||||
handle,
|
||||
index,
|
||||
luid,
|
||||
mac,
|
||||
};
|
||||
device.enabled(true)?;
|
||||
Ok(device)
|
||||
}
|
||||
fn write_tap(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
ffi::write_file(self.handle, buf).map(|res| res as _)
|
||||
}
|
||||
fn enabled(&self, value: bool) -> io::Result<()> {
|
||||
let status: u32 = if value { 1 } else { 0 };
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
TAP_WIN_IOCTL_SET_MEDIA_STATUS,
|
||||
&status,
|
||||
&mut (),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9];
|
||||
|
||||
impl IFace for Device {
|
||||
fn version(&self) -> io::Result<String> {
|
||||
let mut version = [0u32; 3];
|
||||
ffi::device_io_control(self.handle, TAP_WIN_IOCTL_GET_VERSION, &(), &mut version)?;
|
||||
Ok(format!("{}.{}.{}", version[0], version[1], version[2]))
|
||||
}
|
||||
fn name(&self) -> io::Result<String> {
|
||||
ffi::luid_to_alias(&self.luid).map(|name| decode_utf16(&name))
|
||||
}
|
||||
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
self.enabled(false)
|
||||
}
|
||||
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
netsh::set_interface_ip(self.index, &address, &mask)
|
||||
}
|
||||
|
||||
fn mtu(&self) -> io::Result<u32> {
|
||||
let mut mtu = 0;
|
||||
ffi::device_io_control(self.handle, TAP_WIN_IOCTL_GET_MTU, &(), &mut mtu).map(|_| mtu)
|
||||
}
|
||||
|
||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
||||
netsh::set_interface_mtu(self.index, value)
|
||||
}
|
||||
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
route::add_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED, metric)?;
|
||||
netsh::delete_cache()
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
route::delete_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED)?;
|
||||
netsh::delete_cache()
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
packet::read_tap(
|
||||
buf,
|
||||
|eth_buf| ffi::read_file(self.handle, eth_buf).map(|res| res as usize),
|
||||
|eth_buf| ffi::write_file(self.handle, eth_buf).map(|res| res as _),
|
||||
)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
// 封装二层数据
|
||||
packet::write_tap(
|
||||
buf,
|
||||
|eth_buf| ffi::write_file(self.handle, eth_buf).map(|res| res as _),
|
||||
&self.mac,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Device {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = ffi::close_handle(self.handle) {
|
||||
log::warn!("close_handle={:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
use libloading::{Error, Library};
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use winapi::um::{synchapi, winbase, winnt};
|
||||
|
||||
use crate::{decode_utf16, encode_utf16, ffi, netsh, route, IFace};
|
||||
use rand::Rng;
|
||||
pub mod packet;
|
||||
use winapi::um::winbase;
|
||||
use winapi::um::{synchapi, winnt};
|
||||
|
||||
use crate::device::IFace;
|
||||
use crate::windows::decode_utf16;
|
||||
use crate::windows::{encode_utf16, ffi, netsh, route};
|
||||
|
||||
mod packet;
|
||||
mod wintun_log;
|
||||
mod wintun_raw;
|
||||
|
||||
@@ -18,7 +23,7 @@ pub const MIN_RING_CAPACITY: u32 = 0x2_0000;
|
||||
/// Maximum pool name length including zero terminator
|
||||
pub const MAX_POOL: usize = 256;
|
||||
|
||||
pub struct TunDevice {
|
||||
pub struct Device {
|
||||
pub(crate) luid: u64,
|
||||
pub(crate) index: u32,
|
||||
/// The session handle given to us by WintunStartSession
|
||||
@@ -39,109 +44,95 @@ pub struct TunDevice {
|
||||
pub(crate) adapter: wintun_raw::WINTUN_ADAPTER_HANDLE,
|
||||
}
|
||||
|
||||
unsafe impl Send for TunDevice {}
|
||||
unsafe impl Send for Device {}
|
||||
|
||||
unsafe impl Sync for TunDevice {}
|
||||
unsafe impl Sync for Device {}
|
||||
|
||||
impl TunDevice {
|
||||
pub unsafe fn create<L>(library: L, pool: &str, name: &str) -> io::Result<Self>
|
||||
where
|
||||
L: Into<libloading::Library>,
|
||||
{
|
||||
let win_tun = match wintun_raw::wintun::from_library(library) {
|
||||
Ok(win_tun) => win_tun,
|
||||
Err(e) => {
|
||||
impl Device {
|
||||
pub fn new(name: &str) -> io::Result<Self> {
|
||||
unsafe {
|
||||
let library = match Library::new("wintun.dll") {
|
||||
Ok(library) => library,
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("wintun.dll not found {:?}", e),
|
||||
));
|
||||
}
|
||||
};
|
||||
let win_tun = match wintun_raw::wintun::from_library(library) {
|
||||
Ok(win_tun) => win_tun,
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("library error {:?} ", e),
|
||||
));
|
||||
}
|
||||
};
|
||||
let name_utf16 = encode_utf16(name);
|
||||
if name_utf16.len() > MAX_POOL {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("library error {:?} ", e),
|
||||
format!("too long {}:{:?}", MAX_POOL, name),
|
||||
));
|
||||
}
|
||||
};
|
||||
let pool_utf16 = encode_utf16(pool);
|
||||
if pool_utf16.len() > MAX_POOL {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("长度大于{}:{:?}", MAX_POOL, pool),
|
||||
));
|
||||
}
|
||||
let name_utf16 = encode_utf16(name);
|
||||
if name_utf16.len() > MAX_POOL {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("长度大于{}:{:?}", MAX_POOL, pool),
|
||||
));
|
||||
}
|
||||
let mut guid_bytes: [u8; 16] = [0u8; 16];
|
||||
rand::thread_rng().fill(&mut guid_bytes);
|
||||
let guid = u128::from_ne_bytes(guid_bytes);
|
||||
//SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred
|
||||
//guid to the winapi guid type is safe and will allow the windows kernel to see our GUID
|
||||
wintun_log::set_default_logger_if_unset(&win_tun);
|
||||
let _ = Self::delete_for_name(&win_tun, &name_utf16);
|
||||
let mut guid_bytes: [u8; 16] = [0u8; 16];
|
||||
rand::thread_rng().fill(&mut guid_bytes);
|
||||
let guid = u128::from_ne_bytes(guid_bytes);
|
||||
//SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred
|
||||
//guid to the winapi guid type is safe and will allow the windows kernel to see our GUID
|
||||
|
||||
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(guid) };
|
||||
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
|
||||
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(guid) };
|
||||
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
|
||||
|
||||
wintun_log::set_default_logger_if_unset(&win_tun);
|
||||
|
||||
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
|
||||
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
|
||||
//applies for all Wintun* functions below
|
||||
let adapter =
|
||||
win_tun.WintunCreateAdapter(pool_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
|
||||
if adapter.is_null() {
|
||||
log::error!("adapter.is_null {:?}", io::Error::last_os_error());
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Failed to crate adapter",
|
||||
));
|
||||
}
|
||||
Self::init(win_tun, adapter)
|
||||
}
|
||||
pub unsafe fn init(
|
||||
win_tun: wintun_raw::wintun,
|
||||
adapter: wintun_raw::WINTUN_ADAPTER_HANDLE,
|
||||
) -> io::Result<Self> {
|
||||
// 开启session
|
||||
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
|
||||
if session.is_null() {
|
||||
log::error!("session.is_null {:?}", io::Error::last_os_error());
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"WintunStartSession failed",
|
||||
));
|
||||
}
|
||||
//SAFETY: We follow the contract required by CreateEventA. See MSDN
|
||||
//(the pointers are allowed to be null, and 0 is okay for the others)
|
||||
let shutdown_event =
|
||||
synchapi::CreateEventA(std::ptr::null_mut(), 0, 0, std::ptr::null_mut());
|
||||
let read_event = win_tun.WintunGetReadWaitEvent(session) as winnt::HANDLE;
|
||||
let mut luid: wintun_raw::NET_LUID = std::mem::zeroed();
|
||||
win_tun.WintunGetAdapterLUID(adapter, &mut luid as *mut wintun_raw::NET_LUID);
|
||||
let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?;
|
||||
Ok(TunDevice {
|
||||
luid: std::mem::transmute(luid),
|
||||
index,
|
||||
session,
|
||||
win_tun,
|
||||
read_event,
|
||||
shutdown_event,
|
||||
adapter,
|
||||
})
|
||||
}
|
||||
pub unsafe fn delete_for_name<L>(library: L, name: &str) -> io::Result<()>
|
||||
where
|
||||
L: Into<libloading::Library>,
|
||||
{
|
||||
let win_tun = match wintun_raw::wintun::from_library(library) {
|
||||
Ok(win_tun) => win_tun,
|
||||
Err(e) => {
|
||||
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
|
||||
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
|
||||
//applies for all Wintun* functions below
|
||||
let adapter =
|
||||
win_tun.WintunCreateAdapter(name_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
|
||||
if adapter.is_null() {
|
||||
log::error!("adapter.is_null {:?}", io::Error::last_os_error());
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("library error {:?} ", e),
|
||||
"Failed to crate adapter",
|
||||
));
|
||||
}
|
||||
};
|
||||
wintun_log::set_default_logger_if_unset(&win_tun);
|
||||
let name_utf16 = encode_utf16(name);
|
||||
// 开启session
|
||||
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
|
||||
if session.is_null() {
|
||||
log::error!("session.is_null {:?}", io::Error::last_os_error());
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"WintunStartSession failed",
|
||||
));
|
||||
}
|
||||
//SAFETY: We follow the contract required by CreateEventA. See MSDN
|
||||
//(the pointers are allowed to be null, and 0 is okay for the others)
|
||||
let shutdown_event =
|
||||
synchapi::CreateEventA(std::ptr::null_mut(), 0, 0, std::ptr::null_mut());
|
||||
let read_event = win_tun.WintunGetReadWaitEvent(session) as winnt::HANDLE;
|
||||
let mut luid: wintun_raw::NET_LUID = std::mem::zeroed();
|
||||
win_tun.WintunGetAdapterLUID(adapter, &mut luid as *mut wintun_raw::NET_LUID);
|
||||
let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?;
|
||||
// 设置网卡跃点
|
||||
netsh::set_interface_metric(index, 0)?;
|
||||
Ok(Self {
|
||||
luid: std::mem::transmute(luid),
|
||||
index,
|
||||
session,
|
||||
win_tun,
|
||||
read_event,
|
||||
shutdown_event,
|
||||
adapter,
|
||||
})
|
||||
}
|
||||
}
|
||||
pub unsafe fn delete_for_name(
|
||||
win_tun: &wintun_raw::wintun,
|
||||
name_utf16: &Vec<u16>,
|
||||
) -> io::Result<()> {
|
||||
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
|
||||
if adapter.is_null() {
|
||||
log::error!(
|
||||
@@ -157,11 +148,10 @@ impl TunDevice {
|
||||
win_tun.WintunDeleteDriver();
|
||||
Ok(())
|
||||
}
|
||||
pub fn delete(self) -> io::Result<()> {
|
||||
drop(self);
|
||||
Ok(())
|
||||
}
|
||||
pub fn version(&self) -> io::Result<Version> {
|
||||
}
|
||||
|
||||
impl IFace for Device {
|
||||
fn version(&self) -> io::Result<String> {
|
||||
let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };
|
||||
if version == 0 {
|
||||
return Err(io::Error::new(
|
||||
@@ -169,78 +159,66 @@ impl TunDevice {
|
||||
"WintunGetRunningDriverVersion",
|
||||
));
|
||||
} else {
|
||||
Ok(Version {
|
||||
major: ((version >> 16) & 0xFF) as u16,
|
||||
minor: (version & 0xFF) as u16,
|
||||
})
|
||||
Ok(format!("{}.{}", (version >> 16) & 0xFFFF, version & 0xFFFF))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Version {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
}
|
||||
|
||||
// impl TunDevice {
|
||||
// fn get_adapter_luid(&self) -> u64 {
|
||||
// let mut luid: wintun_raw::NET_LUID = unsafe { std::mem::zeroed() };
|
||||
// unsafe { self.win_tun.WintunGetAdapterLUID(self.adapter, &mut luid as *mut wintun_raw::NET_LUID) };
|
||||
// unsafe { std::mem::transmute(luid) }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl IFace for TunDevice {
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
// let _ = unsafe { synchapi::SetEvent(self.shutdown_event) };
|
||||
// let _ = unsafe { handleapi::CloseHandle(self.shutdown_event) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_index(&self) -> io::Result<u32> {
|
||||
Ok(self.index)
|
||||
}
|
||||
|
||||
fn get_name(&self) -> io::Result<String> {
|
||||
fn name(&self) -> io::Result<String> {
|
||||
let luid = self.luid;
|
||||
ffi::luid_to_alias(&unsafe { std::mem::transmute(luid) }).map(|name| decode_utf16(&name))
|
||||
}
|
||||
|
||||
fn set_name(&self, new_name: &str) -> io::Result<()> {
|
||||
let name = self.get_name()?;
|
||||
netsh::set_interface_name(&name, new_name)
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
unsafe {
|
||||
if 0 == synchapi::SetEvent(self.shutdown_event) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
netsh::set_interface_ip(self.get_index()?, &address, &mask)
|
||||
netsh::set_interface_ip(self.index, &address, &mask)
|
||||
}
|
||||
|
||||
fn add_route(
|
||||
&self,
|
||||
dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
metric: u16,
|
||||
) -> io::Result<()> {
|
||||
route::add_route(self.get_index()?, dest, netmask, gateway, metric)
|
||||
fn mtu(&self) -> io::Result<u32> {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
route::delete_route(self.get_index()?, dest, netmask, gateway)
|
||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
||||
netsh::set_interface_mtu(self.index, value)
|
||||
}
|
||||
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
|
||||
netsh::set_interface_mtu(self.get_index()?, mtu)
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
route::add_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED, metric)?;
|
||||
netsh::delete_cache()
|
||||
}
|
||||
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_metric(index, metric)
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
route::delete_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED)?;
|
||||
netsh::delete_cache()
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let packet = self.receive_blocking()?;
|
||||
let packet = packet.bytes();
|
||||
let len = packet.len();
|
||||
if len > buf.len() {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "data too long"));
|
||||
}
|
||||
buf[..len].copy_from_slice(packet);
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
let mut packet = self.allocate_send_packet(buf.len() as u16)?;
|
||||
packet.bytes_mut().copy_from_slice(buf);
|
||||
self.send_packet(packet);
|
||||
Ok(buf.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl TunDevice {
|
||||
impl Device {
|
||||
pub fn try_receive(&self) -> io::Result<Option<packet::TunPacket>> {
|
||||
let mut size = 0u32;
|
||||
|
||||
@@ -297,7 +275,7 @@ impl TunDevice {
|
||||
};
|
||||
match result {
|
||||
winbase::WAIT_FAILED => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "WAIT_FAILED"))
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "WAIT_FAILED"));
|
||||
}
|
||||
_ => {
|
||||
if result == winbase::WAIT_OBJECT_0 {
|
||||
@@ -314,9 +292,6 @@ impl TunDevice {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TunDevice {
|
||||
pub fn allocate_send_packet(&self, size: u16) -> io::Result<packet::TunPacket> {
|
||||
let bytes_ptr = unsafe {
|
||||
self.win_tun
|
||||
@@ -350,13 +325,17 @@ impl TunDevice {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TunDevice {
|
||||
impl Drop for Device {
|
||||
fn drop(&mut self) {
|
||||
//Close adapter on drop
|
||||
//This is why we need an Arc of wintun
|
||||
unsafe {
|
||||
if let Err(e) = ffi::close_handle(self.shutdown_event) {
|
||||
log::warn!("close shutdown_event={:?}", e)
|
||||
}
|
||||
self.win_tun.WintunEndSession(self.session);
|
||||
self.win_tun.WintunCloseAdapter(self.adapter);
|
||||
self.win_tun.WintunDeleteDriver()
|
||||
};
|
||||
if 0 != self.win_tun.WintunDeleteDriver() {
|
||||
log::warn!("WintunDeleteDriver failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::TunDevice;
|
||||
use crate::windows::tun::Device;
|
||||
|
||||
pub(crate) enum Kind {
|
||||
SendPacketPending,
|
||||
@@ -16,7 +16,7 @@ pub struct TunPacket<'a> {
|
||||
|
||||
//Share ownership of session to prevent the session from being dropped before packets that
|
||||
//belong to it
|
||||
pub(crate) tun_device: Option<&'a TunDevice>,
|
||||
pub(crate) tun_device: Option<&'a Device>,
|
||||
}
|
||||
|
||||
impl<'a> TunPacket<'a> {
|
||||
@@ -1,6 +1,6 @@
|
||||
use log::*;
|
||||
|
||||
use crate::tun::wintun_raw;
|
||||
use crate::windows::tun::wintun_raw;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use widestring::U16CStr;
|
||||
|
||||
Reference in New Issue
Block a user