[mio] 去除多余代码
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
[package]
|
||||
name = "tun"
|
||||
version = "0.5.4"
|
||||
edition = "2018"
|
||||
|
||||
authors = ["meh. <[email protected]>"]
|
||||
license = "WTFPL"
|
||||
|
||||
description = "TUN device creation and handling."
|
||||
repository = "https://github.com/meh/rust-tun"
|
||||
keywords = ["tun", "network", "tunnel", "bindings"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
thiserror = "1"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "android"))'.dependencies]
|
||||
bytes = { version = "1", optional = true }
|
||||
byteorder = { version = "1", optional = true }
|
||||
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||
ioctl = { version = "0.6", package = "ioctl-sys" }
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
// 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::net::{IpAddr, Ipv4Addr};
|
||||
use std::net::{SocketAddr, SocketAddrV4};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
/// Helper trait to convert things into IPv4 addresses.
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub trait IntoAddress {
|
||||
/// Convert the type to an `Ipv4Addr`.
|
||||
fn into_address(&self) -> Result<Ipv4Addr>;
|
||||
}
|
||||
|
||||
impl IntoAddress for u32 {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
Ok(Ipv4Addr::new(
|
||||
((*self) & 0xff) as u8,
|
||||
((*self >> 8) & 0xff) as u8,
|
||||
((*self >> 16) & 0xff) as u8,
|
||||
((*self >> 24) & 0xff) as u8,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoAddress for i32 {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
(*self as u32).into_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoAddress for (u8, u8, u8, u8) {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
Ok(Ipv4Addr::new(self.0, self.1, self.2, self.3))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoAddress for str {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
self.parse().map_err(|_| Error::InvalidAddress)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoAddress for &'a str {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
(*self).into_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoAddress for String {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
(&**self).into_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoAddress for &'a String {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
(&**self).into_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoAddress for Ipv4Addr {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
Ok(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoAddress for &'a Ipv4Addr {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
(&**self).into_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoAddress for IpAddr {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
match *self {
|
||||
IpAddr::V4(ref value) => Ok(*value),
|
||||
|
||||
IpAddr::V6(_) => Err(Error::InvalidAddress),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoAddress for &'a IpAddr {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
(&**self).into_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoAddress for SocketAddrV4 {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
Ok(*self.ip())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoAddress for &'a SocketAddrV4 {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
(&**self).into_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoAddress for SocketAddr {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
match *self {
|
||||
SocketAddr::V4(ref value) => Ok(*value.ip()),
|
||||
|
||||
SocketAddr::V6(_) => Err(Error::InvalidAddress),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoAddress for &'a SocketAddr {
|
||||
fn into_address(&self) -> Result<Ipv4Addr> {
|
||||
(&**self).into_address()
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// 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::net::Ipv4Addr;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
use crate::address::IntoAddress;
|
||||
use crate::platform;
|
||||
|
||||
/// TUN interface OSI layer of operation.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Layer {
|
||||
L2,
|
||||
L3,
|
||||
}
|
||||
|
||||
impl Default for Layer {
|
||||
fn default() -> Self {
|
||||
Layer::L3
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration builder for a TUN interface.
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct Configuration {
|
||||
pub(crate) name: Option<String>,
|
||||
pub(crate) platform: platform::Configuration,
|
||||
|
||||
pub(crate) address: Option<Ipv4Addr>,
|
||||
pub(crate) destination: Option<Ipv4Addr>,
|
||||
pub(crate) broadcast: Option<Ipv4Addr>,
|
||||
pub(crate) netmask: Option<Ipv4Addr>,
|
||||
pub(crate) mtu: Option<i32>,
|
||||
pub(crate) enabled: Option<bool>,
|
||||
pub(crate) layer: Option<Layer>,
|
||||
pub(crate) queues: Option<usize>,
|
||||
pub(crate) raw_fd: Option<RawFd>,
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
/// Access the platform dependant configuration.
|
||||
pub fn platform<F>(&mut self, f: F) -> &mut Self
|
||||
where
|
||||
F: FnOnce(&mut platform::Configuration),
|
||||
{
|
||||
f(&mut self.platform);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the name.
|
||||
pub fn name<S: AsRef<str>>(&mut self, name: S) -> &mut Self {
|
||||
self.name = Some(name.as_ref().into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the address.
|
||||
pub fn address<A: IntoAddress>(&mut self, value: A) -> &mut Self {
|
||||
self.address = Some(value.into_address().unwrap());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the destination address.
|
||||
pub fn destination<A: IntoAddress>(&mut self, value: A) -> &mut Self {
|
||||
self.destination = Some(value.into_address().unwrap());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the broadcast address.
|
||||
pub fn broadcast<A: IntoAddress>(&mut self, value: A) -> &mut Self {
|
||||
self.broadcast = Some(value.into_address().unwrap());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the netmask.
|
||||
pub fn netmask<A: IntoAddress>(&mut self, value: A) -> &mut Self {
|
||||
self.netmask = Some(value.into_address().unwrap());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the MTU.
|
||||
pub fn mtu(&mut self, value: i32) -> &mut Self {
|
||||
self.mtu = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the interface to be enabled once created.
|
||||
pub fn up(&mut self) -> &mut Self {
|
||||
self.enabled = Some(true);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the interface to be disabled once created.
|
||||
pub fn down(&mut self) -> &mut Self {
|
||||
self.enabled = Some(false);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the OSI layer of operation.
|
||||
pub fn layer(&mut self, value: Layer) -> &mut Self {
|
||||
self.layer = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the number of queues.
|
||||
pub fn queues(&mut self, value: usize) -> &mut Self {
|
||||
self.queues = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the raw fd.
|
||||
pub fn raw_fd(&mut self, fd: RawFd) -> &mut Self {
|
||||
self.raw_fd = Some(fd);
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// 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::net::Ipv4Addr;
|
||||
|
||||
use crate::configuration::Configuration;
|
||||
use crate::error::*;
|
||||
|
||||
/// A TUN device.
|
||||
pub trait Device {
|
||||
type Queue;
|
||||
|
||||
/// Reconfigure the device.
|
||||
fn configure(&mut self, config: &Configuration) -> Result<()> {
|
||||
if let Some(ip) = config.address {
|
||||
self.set_address(ip)?;
|
||||
}
|
||||
|
||||
if let Some(ip) = config.destination {
|
||||
self.set_destination(ip)?;
|
||||
}
|
||||
|
||||
if let Some(ip) = config.broadcast {
|
||||
self.set_broadcast(ip)?;
|
||||
}
|
||||
|
||||
if let Some(ip) = config.netmask {
|
||||
self.set_netmask(ip)?;
|
||||
}
|
||||
|
||||
if let Some(mtu) = config.mtu {
|
||||
self.set_mtu(mtu)?;
|
||||
}
|
||||
|
||||
if let Some(enabled) = config.enabled {
|
||||
self.enabled(enabled)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the device name.
|
||||
fn name(&self) -> &str;
|
||||
|
||||
/// Set the device name.
|
||||
fn set_name(&mut self, name: &str) -> Result<()>;
|
||||
|
||||
/// Turn on or off the interface.
|
||||
fn enabled(&mut self, value: bool) -> Result<()>;
|
||||
|
||||
/// Get the address.
|
||||
fn address(&self) -> Result<Ipv4Addr>;
|
||||
|
||||
/// Set the address.
|
||||
fn set_address(&mut self, value: Ipv4Addr) -> Result<()>;
|
||||
|
||||
/// Get the destination address.
|
||||
fn destination(&self) -> Result<Ipv4Addr>;
|
||||
|
||||
/// Set the destination address.
|
||||
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()>;
|
||||
|
||||
/// Get the broadcast address.
|
||||
fn broadcast(&self) -> Result<Ipv4Addr>;
|
||||
|
||||
/// Set the broadcast address.
|
||||
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()>;
|
||||
|
||||
/// Get the netmask.
|
||||
fn netmask(&self) -> Result<Ipv4Addr>;
|
||||
|
||||
/// Set the netmask.
|
||||
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()>;
|
||||
|
||||
/// Get the MTU.
|
||||
fn mtu(&self) -> Result<i32>;
|
||||
|
||||
/// Set the MTU.
|
||||
fn set_mtu(&mut self, value: i32) -> Result<()>;
|
||||
|
||||
/// Get a device queue.
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue>;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// 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::{ffi, io, num};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("invalid configuration")]
|
||||
InvalidConfig,
|
||||
|
||||
#[error("not implementated")]
|
||||
NotImplemented,
|
||||
|
||||
#[error("device name too long")]
|
||||
NameTooLong,
|
||||
|
||||
#[error("invalid device name")]
|
||||
InvalidName,
|
||||
|
||||
#[error("invalid address")]
|
||||
InvalidAddress,
|
||||
|
||||
#[error("invalid file descriptor")]
|
||||
InvalidDescriptor,
|
||||
|
||||
#[error("unsuported network layer of operation")]
|
||||
UnsupportedLayer,
|
||||
|
||||
#[error("invalid queues number")]
|
||||
InvalidQueuesNumber,
|
||||
|
||||
#[error(transparent)]
|
||||
Io(#[from] io::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
Nul(#[from] ffi::NulError),
|
||||
|
||||
#[error(transparent)]
|
||||
ParseNum(#[from] num::ParseIntError),
|
||||
}
|
||||
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
@@ -1,32 +0,0 @@
|
||||
// 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.
|
||||
#![cfg(unix)]
|
||||
mod error;
|
||||
pub use crate::error::*;
|
||||
|
||||
mod address;
|
||||
pub use crate::address::IntoAddress;
|
||||
|
||||
mod device;
|
||||
pub use crate::device::Device;
|
||||
|
||||
mod configuration;
|
||||
pub use crate::configuration::{Configuration, Layer};
|
||||
|
||||
pub mod platform;
|
||||
pub use crate::platform::create;
|
||||
|
||||
pub fn configure() -> Configuration {
|
||||
Configuration::default()
|
||||
}
|
||||
@@ -1,384 +0,0 @@
|
||||
// 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::ffi::{CStr, CString};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::vec::Vec;
|
||||
|
||||
use libc;
|
||||
use libc::{c_char, c_short};
|
||||
use libc::{AF_INET, O_RDWR, SOCK_DGRAM};
|
||||
|
||||
use crate::configuration::{Configuration, Layer};
|
||||
use crate::device::Device as D;
|
||||
use crate::error::*;
|
||||
use crate::platform::linux::sys::*;
|
||||
use crate::platform::posix::{self, Fd, SockAddr};
|
||||
|
||||
/// A TUN device using the TUN/TAP Linux driver.
|
||||
pub struct Device {
|
||||
name: String,
|
||||
queues: Vec<Queue>,
|
||||
ctl: Fd,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// Create a new `Device` for the given `Configuration`.
|
||||
pub fn new(config: &Configuration) -> Result<Self> {
|
||||
let mut device = unsafe {
|
||||
let dev = match config.name.as_ref() {
|
||||
Some(name) => {
|
||||
let name = CString::new(name.clone())?;
|
||||
|
||||
if name.as_bytes_with_nul().len() > IFNAMSIZ {
|
||||
return Err(Error::NameTooLong);
|
||||
}
|
||||
|
||||
Some(name)
|
||||
}
|
||||
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut queues = Vec::new();
|
||||
|
||||
let mut req: ifreq = mem::zeroed();
|
||||
|
||||
if let Some(dev) = dev.as_ref() {
|
||||
ptr::copy_nonoverlapping(
|
||||
dev.as_ptr() as *const c_char,
|
||||
req.ifrn.name.as_mut_ptr(),
|
||||
dev.as_bytes().len(),
|
||||
);
|
||||
}
|
||||
|
||||
let device_type: c_short = config.layer.unwrap_or(Layer::L3).into();
|
||||
|
||||
let queues_num = config.queues.unwrap_or(1);
|
||||
if queues_num < 1 {
|
||||
return Err(Error::InvalidQueuesNumber);
|
||||
}
|
||||
|
||||
req.ifru.flags = device_type
|
||||
| if config.platform.packet_information {
|
||||
0
|
||||
} else {
|
||||
IFF_NO_PI
|
||||
}
|
||||
| if queues_num > 1 { IFF_MULTI_QUEUE } else { 0 };
|
||||
|
||||
for _ in 0..queues_num {
|
||||
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().into());
|
||||
}
|
||||
|
||||
queues.push(Queue {
|
||||
tun: Arc::new(tun),
|
||||
pi_enabled: config.platform.packet_information,
|
||||
});
|
||||
}
|
||||
|
||||
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))
|
||||
.map_err(|_| io::Error::last_os_error())?;
|
||||
|
||||
Device {
|
||||
name: CStr::from_ptr(req.ifrn.name.as_ptr())
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
queues,
|
||||
ctl,
|
||||
}
|
||||
};
|
||||
|
||||
device.configure(config)?;
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
/// Prepare a new request.
|
||||
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
|
||||
}
|
||||
|
||||
// /// Make the device persistent.
|
||||
// pub fn persist(&mut self) -> Result<()> {
|
||||
// unsafe {
|
||||
// if tunsetpersist(self.as_raw_fd(), &1) < 0 {
|
||||
// Err(io::Error::last_os_error().into())
|
||||
// } else {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Set the owner of the device.
|
||||
// pub fn user(&mut self, value: i32) -> Result<()> {
|
||||
// unsafe {
|
||||
// if tunsetowner(self.as_raw_fd(), &value) < 0 {
|
||||
// Err(io::Error::last_os_error().into())
|
||||
// } else {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /// Set the group of the device.
|
||||
// pub fn group(&mut self, value: i32) -> Result<()> {
|
||||
// unsafe {
|
||||
// if tunsetgroup(self.as_raw_fd(), &value) < 0 {
|
||||
// Err(io::Error::last_os_error().into())
|
||||
// } else {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
/// Return whether the device has packet information
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
self.queues[0].has_packet_information()
|
||||
}
|
||||
|
||||
/// Set non-blocking mode
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.queues[0].set_nonblock()
|
||||
}
|
||||
}
|
||||
|
||||
impl D for Device {
|
||||
type Queue = Queue;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn set_name(&mut self, value: &str) -> Result<()> {
|
||||
unsafe {
|
||||
let name = CString::new(value)?;
|
||||
|
||||
if name.as_bytes_with_nul().len() > IFNAMSIZ {
|
||||
return Err(Error::NameTooLong);
|
||||
}
|
||||
|
||||
let mut req = self.request();
|
||||
ptr::copy_nonoverlapping(
|
||||
name.as_ptr() as *const c_char,
|
||||
req.ifru.newname.as_mut_ptr(),
|
||||
value.len(),
|
||||
);
|
||||
|
||||
if siocsifname(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
self.name = value.into();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn enabled(&mut self, value: bool) -> Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
if value {
|
||||
req.ifru.flags |= IFF_UP | IFF_RUNNING;
|
||||
} else {
|
||||
req.ifru.flags &= !IFF_UP;
|
||||
}
|
||||
|
||||
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn address(&self) -> 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.ifru.addr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_address(&mut self, value: Ipv4Addr) -> 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().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn destination(&self) -> 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().into());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_destination(&mut self, value: Ipv4Addr) -> 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().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn broadcast(&self) -> 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().into());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_broadcast(&mut self, value: Ipv4Addr) -> 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().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn netmask(&self) -> 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().into());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifru.netmask).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifru.netmask = SockAddr::from(value).into();
|
||||
|
||||
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn mtu(&self) -> Result<i32> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
Ok(req.ifru.mtu)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_mtu(&mut self, value: i32) -> Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifru.mtu = value;
|
||||
|
||||
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue> {
|
||||
self.queues.get(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Queue {
|
||||
tun: Arc<Fd>,
|
||||
pi_enabled: bool,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
self.pi_enabled
|
||||
}
|
||||
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.tun.set_nonblock()
|
||||
}
|
||||
pub fn reader(&self) -> posix::Reader {
|
||||
posix::Reader(self.tun.clone())
|
||||
}
|
||||
pub fn writer(&self) -> posix::Writer {
|
||||
posix::Writer(self.tun.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Layer> for c_short {
|
||||
fn from(layer: Layer) -> Self {
|
||||
match layer {
|
||||
Layer::L2 => IFF_TAP,
|
||||
Layer::L3 => IFF_TUN,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//! Linux specific functionality.
|
||||
|
||||
pub mod sys;
|
||||
|
||||
mod device;
|
||||
pub use self::device::{Device, Queue};
|
||||
|
||||
use crate::configuration::Configuration as C;
|
||||
use crate::error::*;
|
||||
|
||||
/// Linux-only interface configuration.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct Configuration {
|
||||
pub(crate) packet_information: bool,
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
/// Enable or disable packet information, when enabled the first 4 bytes of
|
||||
/// each packet is a header with flags and protocol type.
|
||||
pub fn packet_information(&mut self, value: bool) -> &mut Self {
|
||||
self.packet_information = value;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a TUN device with the given name.
|
||||
pub fn create(configuration: &C) -> Result<Device> {
|
||||
Device::new(configuration)
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
// 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 Linux stuff.
|
||||
|
||||
use ioctl::*;
|
||||
use libc::sockaddr;
|
||||
use libc::{c_char, c_int, c_short, c_uchar, c_uint, c_ulong, c_ushort, c_void};
|
||||
|
||||
pub const IFNAMSIZ: usize = 16;
|
||||
|
||||
pub const IFF_UP: c_short = 0x1;
|
||||
pub const IFF_RUNNING: c_short = 0x40;
|
||||
|
||||
pub const IFF_TUN: c_short = 0x0001;
|
||||
pub const IFF_TAP: c_short = 0x0002;
|
||||
pub const IFF_NO_PI: c_short = 0x1000;
|
||||
pub const IFF_MULTI_QUEUE: c_short = 0x0100;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ifmap {
|
||||
pub mem_start: c_ulong,
|
||||
pub mem_end: c_ulong,
|
||||
pub base_addr: c_ushort,
|
||||
pub irq: c_uchar,
|
||||
pub dma: c_uchar,
|
||||
pub port: c_uchar,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union ifsu {
|
||||
pub raw_hdlc_proto: *mut c_void,
|
||||
pub cisco: *mut c_void,
|
||||
pub fr: *mut c_void,
|
||||
pub fr_pvc: *mut c_void,
|
||||
pub fr_pvc_info: *mut c_void,
|
||||
pub sync: *mut c_void,
|
||||
pub te1: *mut c_void,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct if_settings {
|
||||
pub type_: c_uint,
|
||||
pub size: c_uint,
|
||||
pub ifsu: ifsu,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union ifrn {
|
||||
pub name: [c_char; IFNAMSIZ],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union ifru {
|
||||
pub addr: sockaddr,
|
||||
pub dstaddr: sockaddr,
|
||||
pub broadaddr: sockaddr,
|
||||
pub netmask: sockaddr,
|
||||
pub hwaddr: sockaddr,
|
||||
|
||||
pub flags: c_short,
|
||||
pub ivalue: c_int,
|
||||
pub mtu: c_int,
|
||||
pub map: ifmap,
|
||||
pub slave: [c_char; IFNAMSIZ],
|
||||
pub newname: [c_char; IFNAMSIZ],
|
||||
pub data: *mut c_void,
|
||||
pub settings: if_settings,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ifreq {
|
||||
pub ifrn: ifrn,
|
||||
pub ifru: ifru,
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1,445 +0,0 @@
|
||||
// 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.
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use libc;
|
||||
use libc::{c_char, c_uint, c_void, sockaddr, socklen_t, AF_INET, SOCK_DGRAM};
|
||||
|
||||
use crate::configuration::{Configuration, Layer};
|
||||
use crate::device::Device as D;
|
||||
use crate::error::*;
|
||||
use crate::platform::macos::sys::*;
|
||||
use crate::platform::posix::{self, Fd, SockAddr};
|
||||
|
||||
/// A TUN device using the TUN macOS driver.
|
||||
pub struct Device {
|
||||
name: String,
|
||||
queue: Queue,
|
||||
ctl: Fd,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// Create a new `Device` for the given `Configuration`.
|
||||
pub fn new(config: &Configuration) -> Result<Self> {
|
||||
let id = if let Some(name) = config.name.as_ref() {
|
||||
if name.len() > IFNAMSIZ {
|
||||
return Err(Error::NameTooLong);
|
||||
}
|
||||
|
||||
if !name.starts_with("utun") {
|
||||
return Err(Error::InvalidName);
|
||||
}
|
||||
|
||||
name[4..].parse()?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if config.layer.filter(|l| *l != Layer::L3).is_some() {
|
||||
return Err(Error::UnsupportedLayer);
|
||||
}
|
||||
|
||||
let queues_number = config.queues.unwrap_or(1);
|
||||
if queues_number != 1 {
|
||||
return Err(Error::InvalidQueuesNumber);
|
||||
}
|
||||
|
||||
let mut device = unsafe {
|
||||
let tun = Fd::new(libc::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))
|
||||
.map_err(|_| io::Error::last_os_error())?;
|
||||
|
||||
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().into());
|
||||
}
|
||||
|
||||
let addr = sockaddr_ctl {
|
||||
sc_id: info.ctl_id,
|
||||
sc_len: mem::size_of::<sockaddr_ctl>() as _,
|
||||
sc_family: AF_SYSTEM,
|
||||
ss_sysaddr: AF_SYS_CONTROL,
|
||||
sc_unit: id as c_uint,
|
||||
sc_reserved: [0; 5],
|
||||
};
|
||||
|
||||
if libc::connect(
|
||||
tun.0,
|
||||
&addr as *const sockaddr_ctl as *const sockaddr,
|
||||
mem::size_of_val(&addr) as socklen_t,
|
||||
) < 0
|
||||
{
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
let mut name = [0u8; 64];
|
||||
let mut name_len: socklen_t = 64;
|
||||
|
||||
if libc::getsockopt(
|
||||
tun.0,
|
||||
SYSPROTO_CONTROL,
|
||||
UTUN_OPT_IFNAME,
|
||||
&mut name as *mut _ as *mut c_void,
|
||||
&mut name_len as *mut socklen_t,
|
||||
) < 0
|
||||
{
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))
|
||||
.map_err(|_| io::Error::last_os_error())?;
|
||||
|
||||
Device {
|
||||
name: CStr::from_ptr(name.as_ptr() as *const c_char)
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
queue: Queue { tun: Arc::new(tun) },
|
||||
ctl: ctl,
|
||||
}
|
||||
};
|
||||
|
||||
device.configure(&config)?;
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
/// Prepare a new request.
|
||||
pub 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
|
||||
}
|
||||
|
||||
/// Set the IPv4 alias of the device.
|
||||
pub fn set_alias(&mut self, addr: Ipv4Addr, broadaddr: Ipv4Addr, mask: Ipv4Addr) -> Result<()> {
|
||||
unsafe {
|
||||
let mut req: ifaliasreq = mem::zeroed();
|
||||
ptr::copy_nonoverlapping(
|
||||
self.name.as_ptr() as *const c_char,
|
||||
req.ifran.as_mut_ptr(),
|
||||
self.name.len(),
|
||||
);
|
||||
|
||||
req.addr = SockAddr::from(addr).into();
|
||||
req.broadaddr = SockAddr::from(broadaddr).into();
|
||||
req.mask = SockAddr::from(mask).into();
|
||||
|
||||
if siocaifaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// /// Split the interface into a `Reader` and `Writer`.
|
||||
// pub fn split(self) -> (posix::Reader, posix::Writer) {
|
||||
// let fd = Arc::new(self.queue.tun);
|
||||
// (posix::Reader(fd.clone()), posix::Writer(fd.clone()))
|
||||
// }
|
||||
|
||||
/// Return whether the device has packet information
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
self.queue.has_packet_information()
|
||||
}
|
||||
|
||||
/// Set non-blocking mode
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.queue.set_nonblock()
|
||||
}
|
||||
}
|
||||
|
||||
// impl Read for Device {
|
||||
// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// self.queue.tun.read(buf)
|
||||
// }
|
||||
//
|
||||
// fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
// self.queue.tun.read_vectored(bufs)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Write for Device {
|
||||
// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
// self.queue.tun.write(buf)
|
||||
// }
|
||||
//
|
||||
// fn flush(&mut self) -> io::Result<()> {
|
||||
// self.queue.tun.flush()
|
||||
// }
|
||||
//
|
||||
// fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
// self.queue.tun.write_vectored(bufs)
|
||||
// }
|
||||
// }
|
||||
|
||||
impl D for Device {
|
||||
type Queue = Queue;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
// XXX: Cannot set interface name on Darwin.
|
||||
fn set_name(&mut self, value: &str) -> Result<()> {
|
||||
Err(Error::InvalidName)
|
||||
}
|
||||
|
||||
fn enabled(&mut self, value: bool) -> Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
if value {
|
||||
req.ifru.flags |= IFF_UP | IFF_RUNNING;
|
||||
} else {
|
||||
req.ifru.flags &= !IFF_UP;
|
||||
}
|
||||
|
||||
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn address(&self) -> 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.ifru.addr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_address(&mut self, value: Ipv4Addr) -> 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().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn destination(&self) -> 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().into());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_destination(&mut self, value: Ipv4Addr) -> 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().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn broadcast(&self) -> 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().into());
|
||||
}
|
||||
|
||||
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_broadcast(&mut self, value: Ipv4Addr) -> 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().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn netmask(&self) -> 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().into());
|
||||
}
|
||||
|
||||
SockAddr::unchecked(&req.ifru.addr).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_netmask(&mut self, value: Ipv4Addr) -> 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().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn mtu(&self) -> Result<i32> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
|
||||
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
Ok(req.ifru.mtu)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_mtu(&mut self, value: i32) -> Result<()> {
|
||||
unsafe {
|
||||
let mut req = self.request();
|
||||
req.ifru.mtu = value;
|
||||
|
||||
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue> {
|
||||
if index > 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(&self.queue)
|
||||
}
|
||||
}
|
||||
|
||||
// impl AsRawFd for Device {
|
||||
// fn as_raw_fd(&self) -> RawFd {
|
||||
// self.queue.as_raw_fd()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl IntoRawFd for Device {
|
||||
// fn into_raw_fd(self) -> RawFd {
|
||||
// self.queue.into_raw_fd()
|
||||
// }
|
||||
// }
|
||||
|
||||
pub struct Queue {
|
||||
tun: Arc<Fd>,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
// on macos this is always the case
|
||||
true
|
||||
}
|
||||
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.tun.set_nonblock()
|
||||
}
|
||||
|
||||
pub fn reader(&self) -> posix::Reader {
|
||||
posix::Reader(self.tun.clone())
|
||||
}
|
||||
pub fn writer(&self) -> posix::Writer {
|
||||
posix::Writer(self.tun.clone())
|
||||
}
|
||||
}
|
||||
|
||||
// impl AsRawFd for Queue {
|
||||
// fn as_raw_fd(&self) -> RawFd {
|
||||
// self.tun.as_raw_fd()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl IntoRawFd for Queue {
|
||||
// fn into_raw_fd(self) -> RawFd {
|
||||
// self.tun.into_raw_fd()
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Read for Queue {
|
||||
// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// self.tun.read(buf)
|
||||
// }
|
||||
//
|
||||
// fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
// self.tun.read_vectored(bufs)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Write for Queue {
|
||||
// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
// self.tun.write(buf)
|
||||
// }
|
||||
//
|
||||
// fn flush(&mut self) -> io::Result<()> {
|
||||
// self.tun.flush()
|
||||
// }
|
||||
//
|
||||
// fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
// self.tun.write_vectored(bufs)
|
||||
// }
|
||||
// }
|
||||
@@ -1,32 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//! macOS specific functionality.
|
||||
|
||||
pub mod sys;
|
||||
|
||||
mod device;
|
||||
pub use self::device::{Device, Queue};
|
||||
|
||||
use crate::configuration::Configuration as C;
|
||||
use crate::error::*;
|
||||
|
||||
/// macOS-only interface configuration.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct Configuration {}
|
||||
|
||||
/// Create a TUN device with the given name.
|
||||
pub fn create(configuration: &C) -> Result<Device> {
|
||||
Device::new(&configuration)
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//! Platform specific modules.
|
||||
|
||||
#[cfg(unix)]
|
||||
pub mod posix;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod linux;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use self::linux::{create, Configuration, Device, Queue};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod macos;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use self::macos::{create, Configuration, Device, Queue};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::configuration::Configuration;
|
||||
use crate::device::Device;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
#[test]
|
||||
fn create() {
|
||||
let dev = super::create(
|
||||
Configuration::default()
|
||||
.name("utun6")
|
||||
.address("192.168.50.1")
|
||||
.netmask("255.255.0.0")
|
||||
.mtu(1400)
|
||||
.up(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
"192.168.50.1".parse::<Ipv4Addr>().unwrap(),
|
||||
dev.address().unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"255.255.0.0".parse::<Ipv4Addr>().unwrap(),
|
||||
dev.netmask().unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(1400, dev.mtu().unwrap());
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
// 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::io::{self, Read, Write};
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
|
||||
use crate::error::*;
|
||||
use libc::{self, fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
|
||||
|
||||
/// POSIX file descriptor support for `io` traits.
|
||||
pub struct Fd(pub RawFd);
|
||||
|
||||
impl Fd {
|
||||
pub fn new(value: RawFd) -> Result<Self> {
|
||||
if value < 0 {
|
||||
return Err(Error::InvalidDescriptor);
|
||||
}
|
||||
|
||||
Ok(Fd(value))
|
||||
}
|
||||
|
||||
/// Enable non-blocking mode
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } {
|
||||
0 => Ok(()),
|
||||
_ => Err(io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Fd {
|
||||
fn read(&mut 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)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let iov = bufs.as_ptr().cast();
|
||||
let iovcnt = bufs.len().min(libc::c_int::MAX as usize) as _;
|
||||
|
||||
let n = libc::readv(self.0, iov, iovcnt);
|
||||
if n < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Fd {
|
||||
fn write(&mut 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)
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let iov = bufs.as_ptr().cast();
|
||||
let iovcnt = bufs.len().min(libc::c_int::MAX as usize) as _;
|
||||
|
||||
let n = libc::writev(self.0, iov, iovcnt);
|
||||
if n < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(n 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//! POSIX compliant support.
|
||||
|
||||
mod sockaddr;
|
||||
pub use self::sockaddr::SockAddr;
|
||||
|
||||
mod fd;
|
||||
pub use self::fd::Fd;
|
||||
|
||||
mod split;
|
||||
pub use self::split::{Reader, Writer};
|
||||
@@ -1,124 +0,0 @@
|
||||
// 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::io;
|
||||
use std::mem;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::platform::posix::Fd;
|
||||
use libc;
|
||||
|
||||
/// Read-only end for a file descriptor.
|
||||
#[derive(Clone)]
|
||||
pub struct Reader(pub(crate) Arc<Fd>);
|
||||
|
||||
/// Write-only end for a file descriptor.
|
||||
#[derive(Clone)]
|
||||
pub struct Writer(pub(crate) Arc<Fd>);
|
||||
|
||||
impl Reader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::read(self.0.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len());
|
||||
|
||||
if amount < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(amount as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let mut msg: libc::msghdr = mem::zeroed();
|
||||
// msg.msg_name: NULL
|
||||
// msg.msg_namelen: 0
|
||||
msg.msg_iov = bufs.as_mut_ptr().cast();
|
||||
msg.msg_iovlen = bufs.len().min(libc::c_int::MAX as usize) as _;
|
||||
|
||||
let n = libc::recvmsg(self.0.as_raw_fd(), &mut msg, 0);
|
||||
if n < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::write(self.0.as_raw_fd(), buf.as_ptr() as *const _, buf.len());
|
||||
|
||||
if amount < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(amount as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let mut msg: libc::msghdr = mem::zeroed();
|
||||
// msg.msg_name = NULL
|
||||
// msg.msg_namelen = 0
|
||||
msg.msg_iov = bufs.as_ptr() as *mut _;
|
||||
msg.msg_iovlen = bufs.len().min(libc::c_int::MAX as usize) as _;
|
||||
|
||||
let n = libc::sendmsg(self.0.as_raw_fd(), &msg, 0);
|
||||
if n < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
pub fn write_all(&self, mut buf: &[u8]) -> io::Result<()> {
|
||||
while !buf.is_empty() {
|
||||
match self.write(buf) {
|
||||
Ok(0) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::WriteZero,
|
||||
"failed to write whole buffer",
|
||||
));
|
||||
}
|
||||
Ok(n) => buf = &buf[n..],
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Reader {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
impl AsRawFd for Writer {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
//
|
||||
// impl AsRawFd for Writer {
|
||||
// fn as_raw_fd(&self) -> RawFd {
|
||||
// self.0.as_raw_fd()
|
||||
// }
|
||||
// }
|
||||
@@ -1,21 +0,0 @@
|
||||
use std::io;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Io error")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("Protobuf error")]
|
||||
Protobuf(#[from] protobuf::Error),
|
||||
#[error("Invalid packet")]
|
||||
InvalidPacket,
|
||||
#[error("Not support")]
|
||||
NotSupport,
|
||||
#[error("Stop")]
|
||||
Stop(String),
|
||||
#[error("Warn")]
|
||||
Warn(String),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
+2
-4
@@ -1,14 +1,10 @@
|
||||
use crate::error::Error;
|
||||
pub const VNT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub mod channel;
|
||||
pub mod cipher;
|
||||
pub mod core;
|
||||
pub mod error;
|
||||
pub mod external_route;
|
||||
pub mod handle;
|
||||
pub mod igmp_server;
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
pub mod ip_proxy;
|
||||
pub mod nat;
|
||||
@@ -16,3 +12,5 @@ pub mod proto;
|
||||
pub mod protocol;
|
||||
pub mod tun_tap_device;
|
||||
pub mod util;
|
||||
|
||||
pub use handle::callback::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
use std::io;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter(RawFd);
|
||||
|
||||
pub struct DeviceReader(RawFd);
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,为了兼容其他代码,头部空了14个字节
|
||||
pub fn write_ipv4(&self, buf: &[u8]) -> io::Result<()> {
|
||||
let buf = &buf[14..];
|
||||
self.write_ipv4_tun(buf)
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
// unsafe {
|
||||
// libc::close(self.0);
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
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 create(fd: i32) -> (DeviceWriter, DeviceReader) {
|
||||
(DeviceWriter(fd as _), DeviceReader(fd as _))
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
use crate::tun_tap_device::linux_mac::DeviceW;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceType, DeviceWriter, DriverInfo};
|
||||
use parking_lot::Mutex;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use tun::Device;
|
||||
|
||||
pub const TUN_INTERFACE_NAME: &str = "vnt-tun";
|
||||
pub const TAP_INTERFACE_NAME: &str = "vnt-tap";
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn change_ip(
|
||||
&self,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
_old_netmask: Ipv4Addr,
|
||||
_old_gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
let mut config = tun::Configuration::default();
|
||||
let broadcast_address =
|
||||
(!u32::from_be_bytes(netmask.octets())) | u32::from_be_bytes(gateway.octets());
|
||||
let broadcast_address = Ipv4Addr::from(broadcast_address);
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.broadcast(broadcast_address)
|
||||
// .queues(2)
|
||||
.up();
|
||||
let mut dev = self.lock.lock();
|
||||
if let Err(e) = dev.configure(&config) {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
||||
}
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &self.in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
// add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(
|
||||
name,
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let route_add_str: String = format!("ip route add {:?}/{:?} dev {}", address, netmask, name);
|
||||
let route_add_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !route_add_out.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!(
|
||||
"添加路由失败: cmd:{},out:{:?}",
|
||||
route_add_str, route_add_out
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_device(
|
||||
device_type: DeviceType,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
let mut config = tun::Configuration::default();
|
||||
let broadcast_address =
|
||||
(!u32::from_be_bytes(netmask.octets())) | u32::from_be_bytes(gateway.octets());
|
||||
let broadcast_address = Ipv4Addr::from(broadcast_address);
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(mtu.into())
|
||||
.broadcast(broadcast_address)
|
||||
// .queues(2) 用多个队列有兼容性问题
|
||||
.up();
|
||||
match device_type {
|
||||
DeviceType::Tun => {
|
||||
config.name(TUN_INTERFACE_NAME);
|
||||
}
|
||||
DeviceType::Tap => {
|
||||
config.name(TAP_INTERFACE_NAME);
|
||||
config.layer(tun::Layer::L2);
|
||||
}
|
||||
}
|
||||
let dev = tun::create(&config).expect("tun/tap failed to create");
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
// add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(
|
||||
name,
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
)?;
|
||||
let device_w = match device_type {
|
||||
DeviceType::Tun => DeviceW::Tun(writer),
|
||||
DeviceType::Tap => {
|
||||
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
|
||||
let mac_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(get_mac_cmd)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !mac_out.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("获取mac地址错误: {:?}", mac_out),
|
||||
));
|
||||
}
|
||||
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();
|
||||
}
|
||||
DeviceW::Tap((writer, mac))
|
||||
}
|
||||
};
|
||||
let driver_info = DriverInfo {
|
||||
device_type,
|
||||
name: name.to_string(),
|
||||
version: String::new(),
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(
|
||||
device_w,
|
||||
Arc::new(Mutex::new(dev)),
|
||||
in_ips,
|
||||
address,
|
||||
packet_information,
|
||||
),
|
||||
DeviceReader::new(reader),
|
||||
driver_info,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn delete_device(_device_type: DeviceType) {
|
||||
for name in [TUN_INTERFACE_NAME, TAP_INTERFACE_NAME] {
|
||||
let cmd = format!("ip link delete {}", name);
|
||||
let delete_tun = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&cmd)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !delete_tun.status.success() {
|
||||
log::warn!("删除网卡失败:{:?}", delete_tun);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::BufMut;
|
||||
use packet::ethernet;
|
||||
use parking_lot::Mutex;
|
||||
use std::net::Ipv4Addr;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
use tun::platform::linux::Device;
|
||||
#[cfg(any(target_os = "macos"))]
|
||||
use tun::platform::macos::Device;
|
||||
use tun::platform::posix::{Reader, Writer};
|
||||
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum DeviceW {
|
||||
Tun(Writer),
|
||||
Tap((Writer, [u8; 6])),
|
||||
}
|
||||
|
||||
impl DeviceW {
|
||||
pub fn is_tun(&self) -> bool {
|
||||
match self {
|
||||
DeviceW::Tun(_) => true,
|
||||
DeviceW::Tap(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter {
|
||||
writer: DeviceW,
|
||||
pub lock: Arc<Mutex<Device>>,
|
||||
pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
packet_information: bool,
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn new(
|
||||
writer: DeviceW,
|
||||
lock: Arc<Mutex<Device>>,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
_ip: Ipv4Addr,
|
||||
packet_information: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
writer,
|
||||
lock,
|
||||
in_ips,
|
||||
packet_information,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn write(packet_information: bool, writer: &Writer, packet: &[u8]) -> io::Result<()> {
|
||||
if packet_information {
|
||||
let mut buf = Vec::<u8>::with_capacity(4 + packet.len());
|
||||
buf.put_u16(0);
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
buf.put_u16(libc::PF_INET as u16);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
buf.put_u16(libc::ETH_P_IP as u16);
|
||||
buf.extend_from_slice(packet);
|
||||
let len = writer.write(&buf)?;
|
||||
if len != buf.len() {
|
||||
log::error!("tun write error");
|
||||
}
|
||||
} else {
|
||||
let len = writer.write(packet)?;
|
||||
if len != packet.len() {
|
||||
log::error!("tun write error");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
///tun网卡写入ipv4数据
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(writer) => Self::write(self.packet_information, writer, buf),
|
||||
DeviceW::Tap(_) => Err(io::Error::from(io::ErrorKind::Unsupported)),
|
||||
}
|
||||
}
|
||||
/// tap网卡写入以太网帧
|
||||
pub fn write_ethernet_tap(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(_) => Err(io::Error::from(io::ErrorKind::Unsupported)),
|
||||
DeviceW::Tap((writer, _)) => Self::write(self.packet_information, writer, buf),
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,头部必须留14字节,给tap写入以太网帧头
|
||||
pub fn write_ipv4(&self, buf: &mut [u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(writer) => Self::write(self.packet_information, writer, &buf[14..]),
|
||||
DeviceW::Tap((writer, mac)) => {
|
||||
let source_mac = [
|
||||
buf[14 + 12],
|
||||
buf[14 + 13],
|
||||
buf[14 + 14],
|
||||
buf[14 + 15],
|
||||
!mac[5],
|
||||
234,
|
||||
];
|
||||
let mut ethernet_packet = EthernetPacket::unchecked(buf);
|
||||
ethernet_packet.set_source(&source_mac);
|
||||
ethernet_packet.set_destination(mac);
|
||||
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
|
||||
Self::write(self.packet_information, writer, ðernet_packet.buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
//早期使用close直接切断网卡,现在并不需要这么做也能正常关闭
|
||||
// unsafe {
|
||||
// match &self.writer {
|
||||
// DeviceW::Tun(writer) => {
|
||||
// libc::close(writer.as_raw_fd());
|
||||
// }
|
||||
// DeviceW::Tap((writer, _)) => {
|
||||
// libc::close(writer.as_raw_fd());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
pub fn is_tun(&self) -> bool {
|
||||
self.writer.is_tun()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DeviceReader(Reader);
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn new(device: Reader) -> Self {
|
||||
DeviceReader(device)
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
use crate::tun_tap_device::linux_mac::DeviceW;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceType, DeviceWriter, DriverInfo};
|
||||
use parking_lot::Mutex;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use tun::Device;
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn change_ip(
|
||||
&self,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
_old_netmask: Ipv4Addr,
|
||||
_old_gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
let mut config = tun::Configuration::default();
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.up();
|
||||
let mut dev = self.lock.lock();
|
||||
if let Err(e) = dev.configure(&config) {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
||||
}
|
||||
if let Err(e) = config_ip(dev.name(), address, netmask, gateway) {
|
||||
log::error!("{}", e);
|
||||
}
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &self.in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(
|
||||
name,
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_device(
|
||||
device_type: DeviceType,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
match device_type {
|
||||
DeviceType::Tun => {}
|
||||
DeviceType::Tap => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(mtu.into())
|
||||
.up();
|
||||
|
||||
let dev = tun::create(&config).unwrap();
|
||||
let name = dev.name();
|
||||
config_ip(name, address, netmask, gateway)?;
|
||||
for (address, netmask) in &in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(
|
||||
name,
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
)?;
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
let driver_info = DriverInfo {
|
||||
device_type,
|
||||
name: name.to_string(),
|
||||
version: String::new(),
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(
|
||||
DeviceW::Tun(writer),
|
||||
Arc::new(Mutex::new(dev)),
|
||||
in_ips,
|
||||
address,
|
||||
packet_information,
|
||||
),
|
||||
DeviceReader::new(reader),
|
||||
driver_info,
|
||||
))
|
||||
}
|
||||
|
||||
fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let route_add_str: String = format!(
|
||||
"route -n add {} -netmask {} -interface {}",
|
||||
address, netmask, name
|
||||
);
|
||||
let route_add_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !route_add_out.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!(
|
||||
"添加路由失败: cmd:{},out:{:?}",
|
||||
route_add_str, route_add_out
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn config_ip(
|
||||
name: &str,
|
||||
address: Ipv4Addr,
|
||||
_netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", name, address, gateway);
|
||||
let up_eth_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&up_eth_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !up_eth_out.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("设置网络地址失败: cmd:{},out:{:?}", up_eth_str, up_eth_out),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_device(_device_type: DeviceType) {}
|
||||
@@ -1,363 +0,0 @@
|
||||
use crate::tun_tap_device::{DeviceType, DriverInfo};
|
||||
use libloading::Library;
|
||||
use packet::ethernet;
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
use parking_lot::Mutex;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{io, thread};
|
||||
use win_tun_tap::{IFace, TapDevice, TunDevice};
|
||||
|
||||
pub const TUN_INTERFACE_NAME: &str = "Vnt-Tun-V1";
|
||||
pub const TUN_POOL_NAME: &str = "Vnt-Tun-V1";
|
||||
pub const TAP_INTERFACE_NAME: &str = "Vnt-Tap-V1";
|
||||
|
||||
pub enum Device {
|
||||
Tun(TunDevice),
|
||||
Tap((TapDevice, [u8; 6])),
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn is_tun(&self) -> bool {
|
||||
match self {
|
||||
Device::Tun(_) => true,
|
||||
Device::Tap(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter {
|
||||
device: Arc<Device>,
|
||||
lock: Arc<Mutex<()>>,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn new(device: Arc<Device>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, _ip: Ipv4Addr) -> Self {
|
||||
Self {
|
||||
device,
|
||||
lock: Arc::new(Default::default()),
|
||||
in_ips,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
///tun网卡写入ipv4数据
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let mut packet = dev.allocate_send_packet(buf.len() as u16)?;
|
||||
packet.bytes_mut().copy_from_slice(buf);
|
||||
dev.send_packet(packet);
|
||||
Ok(())
|
||||
}
|
||||
Device::Tap(_) => Err(io::Error::from(io::ErrorKind::Unsupported)),
|
||||
}
|
||||
}
|
||||
/// tap网卡写入以太网帧
|
||||
pub fn write_ethernet_tap(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(_) => Err(io::Error::from(io::ErrorKind::Unsupported)),
|
||||
Device::Tap((dev, _)) => {
|
||||
dev.write(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,头部必须留14字节,给tap写入以太网帧头
|
||||
pub fn write_ipv4(&self, buf: &mut [u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let mut packet = dev.allocate_send_packet((buf.len() - 14) as u16)?;
|
||||
packet.bytes_mut().copy_from_slice(&buf[14..]);
|
||||
dev.send_packet(packet);
|
||||
}
|
||||
Device::Tap((dev, mac)) => {
|
||||
let source_mac = [
|
||||
buf[14 + 12],
|
||||
buf[14 + 13],
|
||||
buf[14 + 14],
|
||||
buf[14 + 15],
|
||||
!mac[5],
|
||||
234,
|
||||
];
|
||||
let mut ethernet_packet = EthernetPacket::unchecked(buf);
|
||||
ethernet_packet.set_source(&source_mac);
|
||||
ethernet_packet.set_destination(mac);
|
||||
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
|
||||
dev.write(ðernet_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn change_ip(
|
||||
&self,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
old_netmask: Ipv4Addr,
|
||||
old_gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
let _guard = self.lock.lock();
|
||||
let dev: &dyn IFace = match self.device.as_ref() {
|
||||
Device::Tun(dev) => dev as &dyn IFace,
|
||||
Device::Tap((dev, _)) => dev as &dyn IFace,
|
||||
};
|
||||
if let Err(e) = dev.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway) {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
dev.set_ip(address, netmask)?;
|
||||
for (address, netmask) in &self.in_ips {
|
||||
dev.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
dev.add_route(address, netmask, gateway, 1)?;
|
||||
// 广播和组播路由
|
||||
// dev.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
dev.add_route(
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
gateway,
|
||||
1,
|
||||
)?;
|
||||
delete_cache();
|
||||
Ok(())
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => dev.shutdown(),
|
||||
Device::Tap((dev, _)) => dev.shutdown(),
|
||||
}
|
||||
}
|
||||
pub fn is_tun(&self) -> bool {
|
||||
self.device.is_tun()
|
||||
}
|
||||
}
|
||||
|
||||
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
|
||||
let ip = ip.octets();
|
||||
let mask = mask.octets();
|
||||
Ipv4Addr::from([
|
||||
ip[0] & mask[0],
|
||||
ip[1] & mask[1],
|
||||
ip[2] & mask[2],
|
||||
ip[3] & mask[3],
|
||||
])
|
||||
}
|
||||
|
||||
pub struct DeviceReader {
|
||||
device: Arc<Device>,
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn new(device: Arc<Device>) -> Self {
|
||||
Self { device }
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let packet = dev.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)
|
||||
}
|
||||
Device::Tap((dev, _)) => dev.read(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) {
|
||||
Ok(_) => {
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
Err(_) => {}
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("wintun.dll not found {:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
let tun_device = match TunDevice::create(
|
||||
Library::new("wintun.dll").unwrap(),
|
||||
TUN_POOL_NAME,
|
||||
TUN_INTERFACE_NAME,
|
||||
) {
|
||||
Ok(tun_device) => tun_device,
|
||||
Err(_) => {
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
match TunDevice::create(
|
||||
Library::new("wintun.dll").unwrap(),
|
||||
TUN_POOL_NAME,
|
||||
TUN_INTERFACE_NAME,
|
||||
) {
|
||||
Ok(tun_device) => tun_device,
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let name = tun_device.get_name()?;
|
||||
let version = format!("{:?}", tun_device.version()?);
|
||||
tun_device.set_ip(address, netmask)?;
|
||||
tun_device.set_metric(1)?;
|
||||
tun_device.set_mtu(mtu)?;
|
||||
// ip代理路由
|
||||
for (address, netmask) in &in_ips {
|
||||
tun_device.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
tun_device.add_route(address, netmask, gateway, 1)?;
|
||||
// 广播和组播路由 修改了广播路由会导致发不出广播
|
||||
// tun_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
tun_device.add_route(
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
gateway,
|
||||
1,
|
||||
)?;
|
||||
delete_cache();
|
||||
let device = Arc::new(Device::Tun(tun_device));
|
||||
let driver_info = DriverInfo {
|
||||
device_type: DeviceType::Tun,
|
||||
name,
|
||||
version,
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(device.clone(), in_ips, address),
|
||||
DeviceReader::new(device),
|
||||
driver_info,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_cache() {
|
||||
//清除路由缓存
|
||||
let delete_cache = "netsh interface ip delete destinationcache";
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(delete_cache)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
log::warn!("删除缓存失败:{:?}", out);
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_tun() {
|
||||
unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {}
|
||||
},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tap(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||
Ok(tap_device) => tap_device,
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
let tap_device = TapDevice::create()?;
|
||||
tap_device.set_name(TAP_INTERFACE_NAME)?;
|
||||
tap_device
|
||||
}
|
||||
};
|
||||
let mac = tap_device.get_mac()?;
|
||||
let name = tap_device.get_name()?;
|
||||
let version = format!("{:?}", tap_device.get_version()?);
|
||||
let mac_str = format!("mac:{:x?}", mac);
|
||||
tap_device.set_ip(address, netmask)?;
|
||||
tap_device.set_metric(1)?;
|
||||
tap_device.set_mtu(mtu)?;
|
||||
tap_device.set_status(true)?;
|
||||
tap_device.add_route(address, netmask, gateway, 1)?;
|
||||
for (address, netmask) in &in_ips {
|
||||
tap_device.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 广播和组播路由
|
||||
// tap_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
tap_device.add_route(
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
gateway,
|
||||
1,
|
||||
)?;
|
||||
delete_cache();
|
||||
let tap = Arc::new(Device::Tap((tap_device, mac)));
|
||||
let driver_info = DriverInfo {
|
||||
device_type: DeviceType::Tap,
|
||||
name,
|
||||
version,
|
||||
mac: Some(mac_str),
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(tap.clone(), in_ips, address),
|
||||
DeviceReader::new(tap),
|
||||
driver_info,
|
||||
))
|
||||
}
|
||||
|
||||
fn delete_tap() {
|
||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||
Ok(tap_device) => tap_device,
|
||||
Err(_) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let _ = tap_device.delete();
|
||||
}
|
||||
|
||||
pub fn create_device(
|
||||
device_type: DeviceType,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
match device_type {
|
||||
DeviceType::Tun => create_tun(address, netmask, gateway, in_ips, mtu),
|
||||
DeviceType::Tap => create_tap(address, netmask, gateway, in_ips, mtu),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_device(device_type: DeviceType) {
|
||||
match device_type {
|
||||
DeviceType::Tun => delete_tun(),
|
||||
DeviceType::Tap => delete_tap(),
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
[package]
|
||||
name = "win-tun-tap"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.17"
|
||||
winreg = "0.51.0"
|
||||
scopeguard = "1.1"
|
||||
libloading = "0.8.0"
|
||||
widestring = "1.0.2"
|
||||
once_cell = "1.8"
|
||||
itertools = "0.11.0"
|
||||
rand = "0.8.5"
|
||||
[dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = [
|
||||
"errhandlingapi",
|
||||
"combaseapi",
|
||||
"ioapiset",
|
||||
"winioctl",
|
||||
"setupapi",
|
||||
"synchapi",
|
||||
"netioapi",
|
||||
"fileapi",
|
||||
"winbase",
|
||||
"winerror",
|
||||
"ipexport",
|
||||
"iphlpapi",
|
||||
"handleapi",
|
||||
"ifdef",
|
||||
"minwinbase",
|
||||
"basetsd",
|
||||
"impl-default"
|
||||
]
|
||||
@@ -1,49 +0,0 @@
|
||||
#![cfg(windows)]
|
||||
|
||||
mod ffi;
|
||||
mod netsh;
|
||||
mod route;
|
||||
mod tap;
|
||||
mod tun;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
pub use tap::TapDevice;
|
||||
pub use tun::*;
|
||||
|
||||
/// Encode a string as a utf16 buffer
|
||||
fn encode_utf16(string: &str) -> Vec<u16> {
|
||||
use std::iter::once;
|
||||
string.encode_utf16().chain(once(0)).collect()
|
||||
}
|
||||
|
||||
/// Decode a string from a utf16 buffer
|
||||
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 trait IFace {
|
||||
fn shutdown(&self) -> io::Result<()>;
|
||||
/// 获取接口索引
|
||||
fn get_index(&self) -> io::Result<u32>;
|
||||
/// 获取名称
|
||||
fn get_name(&self) -> io::Result<String>;
|
||||
/// 设置名称
|
||||
fn set_name(&self, new_name: &str) -> io::Result<()>;
|
||||
/// 设置ip
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()>;
|
||||
/// 设置路由
|
||||
fn add_route(
|
||||
&self,
|
||||
dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
metric: u16,
|
||||
) -> io::Result<()>;
|
||||
/// 删除路由
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()>;
|
||||
/// 设置最大传输单元
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()>;
|
||||
/// 设置跃点
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()>;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
/// 设置网卡名称
|
||||
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
|
||||
);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000) //winapi-0.3.9/src/um/winbase.rs:283
|
||||
.arg("/C")
|
||||
.arg(&cmd)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::warn!("修改网卡名称失败:cmd={:?},out={:?}", cmd, out);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "修改网卡名称失败"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// 设置网卡ip
|
||||
pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> io::Result<()> {
|
||||
let set_address = format!(
|
||||
"netsh interface ip set address {} static {:?} {:?} ",
|
||||
index, address, netmask,
|
||||
);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_address)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}", set_address, out);
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("设置网络地址失败: {:?}", out),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> {
|
||||
let set_mtu = format!(
|
||||
"netsh interface ipv4 set subinterface {} mtu={} store=persistent",
|
||||
index, mtu
|
||||
);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_mtu)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}", set_mtu, out);
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("设置mtu失败: {:?}", out),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
|
||||
let set_metric = format!(
|
||||
"netsh interface ip set interface {} metric={}",
|
||||
index, metric
|
||||
);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_metric)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}", set_metric, out);
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("设置metric失败: {:?}", out),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
/// 添加路由
|
||||
pub fn add_route(
|
||||
index: u32,
|
||||
dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
metric: u16,
|
||||
) -> io::Result<()> {
|
||||
let set_route = format!(
|
||||
"route add {:?} mask {:?} {:?} metric {} if {}",
|
||||
dest, netmask, gateway, metric, index
|
||||
);
|
||||
// 执行添加路由命令
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_route)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}", set_route, out);
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("添加路由失败: {:?}", out),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 删除路由
|
||||
pub fn delete_route(
|
||||
index: u32,
|
||||
dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
if index == 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("网络接口索引错误: {:?}", index),
|
||||
));
|
||||
}
|
||||
let delete_route = format!(
|
||||
"route delete {:?} mask {:?} {:?} if {}",
|
||||
dest, netmask, gateway, index
|
||||
);
|
||||
// 删除路由
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(delete_route)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("删除路由失败: {:?}", out),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
use winapi::shared::ifdef::NET_LUID;
|
||||
use winapi::shared::minwindef::*;
|
||||
|
||||
use winapi::um::fileapi::*;
|
||||
use winapi::um::setupapi::*;
|
||||
use winapi::um::winnt::*;
|
||||
|
||||
use scopeguard::{guard, ScopeGuard};
|
||||
use winreg::RegKey;
|
||||
|
||||
use std::io;
|
||||
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
|
||||
|
||||
use crate::{decode_utf16, encode_utf16, ffi};
|
||||
|
||||
/// tap-windows hardware ID
|
||||
const HARDWARE_ID: &str = "tap0901";
|
||||
|
||||
winapi::DEFINE_GUID! {
|
||||
GUID_NETWORK_ADAPTER,
|
||||
0x4d36e972, 0xe325, 0x11ce,
|
||||
0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
|
||||
}
|
||||
|
||||
/// Create a new interface and returns its NET_LUID
|
||||
pub fn create_interface() -> io::Result<NET_LUID> {
|
||||
let devinfo = ffi::create_device_info_list(&GUID_NETWORK_ADAPTER)?;
|
||||
|
||||
let _guard = guard((), |_| {
|
||||
let _ = ffi::destroy_device_info_list(devinfo);
|
||||
});
|
||||
|
||||
let class_name = ffi::class_name_from_guid(&GUID_NETWORK_ADAPTER)?;
|
||||
|
||||
let devinfo_data = ffi::create_device_info(
|
||||
devinfo,
|
||||
&class_name,
|
||||
&GUID_NETWORK_ADAPTER,
|
||||
&encode_utf16(""),
|
||||
DICD_GENERATE_ID,
|
||||
)?;
|
||||
|
||||
ffi::set_selected_device(devinfo, &devinfo_data)?;
|
||||
ffi::set_device_registry_property(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
SPDRP_HARDWAREID,
|
||||
&encode_utf16(HARDWARE_ID),
|
||||
)?;
|
||||
|
||||
ffi::build_driver_info_list(devinfo, &devinfo_data, SPDIT_COMPATDRIVER)?;
|
||||
|
||||
let _guard = guard((), |_| {
|
||||
let _ = ffi::destroy_driver_info_list(devinfo, &devinfo_data, SPDIT_COMPATDRIVER);
|
||||
});
|
||||
|
||||
let mut driver_version = 0;
|
||||
let mut member_index = 0;
|
||||
|
||||
while let Some(drvinfo_data) =
|
||||
ffi::enum_driver_info(devinfo, &devinfo_data, SPDIT_COMPATDRIVER, member_index)
|
||||
{
|
||||
member_index += 1;
|
||||
|
||||
let drvinfo_data = match drvinfo_data {
|
||||
Ok(drvinfo_data) => drvinfo_data,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if drvinfo_data.DriverVersion <= driver_version {
|
||||
continue;
|
||||
}
|
||||
|
||||
let drvinfo_detail =
|
||||
match ffi::get_driver_info_detail(devinfo, &devinfo_data, &drvinfo_data) {
|
||||
Ok(drvinfo_detail) => drvinfo_detail,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let is_compatible = drvinfo_detail
|
||||
.HardwareID
|
||||
.split(|b| *b == 0)
|
||||
.map(|id| decode_utf16(id))
|
||||
.any(|id| id.eq_ignore_ascii_case(HARDWARE_ID));
|
||||
|
||||
if !is_compatible {
|
||||
continue;
|
||||
}
|
||||
|
||||
match ffi::set_selected_driver(devinfo, &devinfo_data, &drvinfo_data) {
|
||||
Ok(_) => (),
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
driver_version = drvinfo_data.DriverVersion;
|
||||
}
|
||||
|
||||
if driver_version == 0 {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "No driver found"));
|
||||
}
|
||||
|
||||
let uninstaller = guard((), |_| {
|
||||
let _ = ffi::call_class_installer(devinfo, &devinfo_data, DIF_REMOVE);
|
||||
});
|
||||
|
||||
ffi::call_class_installer(devinfo, &devinfo_data, DIF_REGISTERDEVICE)?;
|
||||
|
||||
let _ = ffi::call_class_installer(devinfo, &devinfo_data, DIF_REGISTER_COINSTALLERS);
|
||||
let _ = ffi::call_class_installer(devinfo, &devinfo_data, DIF_INSTALLINTERFACES);
|
||||
|
||||
ffi::call_class_installer(devinfo, &devinfo_data, DIF_INSTALLDEVICE)?;
|
||||
|
||||
let key = ffi::open_dev_reg_key(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
DICS_FLAG_GLOBAL,
|
||||
0,
|
||||
DIREG_DRV,
|
||||
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||
)?;
|
||||
|
||||
let key = RegKey::predef(key as _);
|
||||
|
||||
while let Err(_) = key.get_value::<DWORD, &str>("*IfType") {
|
||||
ffi::notify_change_key_value(key.raw_handle() as _, TRUE, REG_NOTIFY_CHANGE_NAME, 2000)?;
|
||||
}
|
||||
|
||||
while let Err(_) = key.get_value::<DWORD, &str>("NetLuidIndex") {
|
||||
ffi::notify_change_key_value(key.raw_handle() as _, TRUE, REG_NOTIFY_CHANGE_NAME, 2000)?;
|
||||
}
|
||||
|
||||
let if_type: DWORD = key.get_value("*IfType")?;
|
||||
let luid_index: DWORD = key.get_value("NetLuidIndex")?;
|
||||
|
||||
// Defuse the uninstaller
|
||||
ScopeGuard::into_inner(uninstaller);
|
||||
|
||||
let mut luid = NET_LUID { Value: 0 };
|
||||
|
||||
luid.set_IfType(if_type as _);
|
||||
luid.set_NetLuidIndex(luid_index as _);
|
||||
|
||||
Ok(luid)
|
||||
}
|
||||
|
||||
/// Check if the given interface exists and is a valid tap-windows device
|
||||
pub fn check_interface(luid: &NET_LUID) -> io::Result<()> {
|
||||
let devinfo = ffi::get_class_devs(&GUID_NETWORK_ADAPTER, DIGCF_PRESENT)?;
|
||||
|
||||
let _guard = guard((), |_| {
|
||||
let _ = ffi::destroy_device_info_list(devinfo);
|
||||
});
|
||||
|
||||
let mut member_index = 0;
|
||||
|
||||
while let Some(devinfo_data) = ffi::enum_device_info(devinfo, member_index) {
|
||||
member_index += 1;
|
||||
|
||||
let devinfo_data = match devinfo_data {
|
||||
Ok(devinfo_data) => devinfo_data,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let hardware_id =
|
||||
match ffi::get_device_registry_property(devinfo, &devinfo_data, SPDRP_HARDWAREID) {
|
||||
Ok(hardware_id) => hardware_id,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
if !decode_utf16(&hardware_id).eq_ignore_ascii_case(HARDWARE_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let key = match ffi::open_dev_reg_key(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
DICS_FLAG_GLOBAL,
|
||||
0,
|
||||
DIREG_DRV,
|
||||
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||
) {
|
||||
Ok(key) => RegKey::predef(key as _),
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let if_type: DWORD = match key.get_value("*IfType") {
|
||||
Ok(if_type) => if_type,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let luid_index: DWORD = match key.get_value("NetLuidIndex") {
|
||||
Ok(luid_index) => luid_index,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let mut luid2 = NET_LUID { Value: 0 };
|
||||
|
||||
luid2.set_IfType(if_type as _);
|
||||
luid2.set_NetLuidIndex(luid_index as _);
|
||||
|
||||
if luid.Value != luid2.Value {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found it!
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"TAP Device not found",
|
||||
))
|
||||
}
|
||||
|
||||
/// Deletes an existing interface
|
||||
pub fn delete_interface(luid: &NET_LUID) -> io::Result<()> {
|
||||
let devinfo = ffi::get_class_devs(&GUID_NETWORK_ADAPTER, DIGCF_PRESENT)?;
|
||||
|
||||
let _guard = guard((), |_| {
|
||||
let _ = ffi::destroy_device_info_list(devinfo);
|
||||
});
|
||||
|
||||
let mut member_index = 0;
|
||||
|
||||
while let Some(devinfo_data) = ffi::enum_device_info(devinfo, member_index) {
|
||||
member_index += 1;
|
||||
|
||||
let devinfo_data = match devinfo_data {
|
||||
Ok(devinfo_data) => devinfo_data,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let hardware_id =
|
||||
match ffi::get_device_registry_property(devinfo, &devinfo_data, SPDRP_HARDWAREID) {
|
||||
Ok(hardware_id) => hardware_id,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
if !decode_utf16(&hardware_id).eq_ignore_ascii_case(HARDWARE_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let key = match ffi::open_dev_reg_key(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
DICS_FLAG_GLOBAL,
|
||||
0,
|
||||
DIREG_DRV,
|
||||
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||
) {
|
||||
Ok(key) => RegKey::predef(key as _),
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let if_type: DWORD = match key.get_value("*IfType") {
|
||||
Ok(if_type) => if_type,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let luid_index: DWORD = match key.get_value("NetLuidIndex") {
|
||||
Ok(luid_index) => luid_index,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let mut luid2 = NET_LUID { Value: 0 };
|
||||
|
||||
luid2.set_IfType(if_type as _);
|
||||
luid2.set_NetLuidIndex(luid_index as _);
|
||||
|
||||
if luid.Value != luid2.Value {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found it!
|
||||
return ffi::call_class_installer(devinfo, &devinfo_data, DIF_REMOVE);
|
||||
}
|
||||
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"TAP Device not found",
|
||||
))
|
||||
}
|
||||
|
||||
/// Open an handle to an interface
|
||||
pub fn open_interface(luid: &NET_LUID) -> io::Result<HANDLE> {
|
||||
let guid = ffi::luid_to_guid(luid).and_then(|guid| ffi::string_from_guid(&guid))?;
|
||||
|
||||
let path = format!(r"\\.\Global\{}.tap", &decode_utf16(&guid));
|
||||
|
||||
ffi::create_file(
|
||||
&encode_utf16(&path),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, //FILE_ATTRIBUTE_SYSTEM,
|
||||
)
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
use std::net::Ipv4Addr;
|
||||
use std::{io, time};
|
||||
|
||||
use winapi::shared::ifdef::NET_LUID;
|
||||
use winapi::um::winioctl::*;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use crate::{decode_utf16, encode_utf16, ffi, netsh, route, IFace};
|
||||
|
||||
mod iface;
|
||||
|
||||
pub struct TapDevice {
|
||||
index: u32,
|
||||
luid: NET_LUID,
|
||||
handle: HANDLE,
|
||||
}
|
||||
|
||||
unsafe impl Send for TapDevice {}
|
||||
|
||||
unsafe impl Sync for TapDevice {}
|
||||
|
||||
impl TapDevice {
|
||||
/// Retieve the mac of the interface
|
||||
pub fn get_mac(&self) -> io::Result<[u8; 6]> {
|
||||
let mut mac = [0; 6];
|
||||
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
&(),
|
||||
&mut mac,
|
||||
)
|
||||
.map(|_| mac)
|
||||
}
|
||||
|
||||
/// Retrieve the version of the driver
|
||||
pub fn get_version(&self) -> io::Result<[u32; 3]> {
|
||||
let mut version = [0; 3];
|
||||
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
&(),
|
||||
&mut version,
|
||||
)
|
||||
.map(|_| version)
|
||||
}
|
||||
|
||||
/// Retieve the mtu of the interface
|
||||
pub fn get_mtu(&self) -> io::Result<u32> {
|
||||
let mut mtu = 0;
|
||||
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
&(),
|
||||
&mut mtu,
|
||||
)
|
||||
.map(|_| mtu)
|
||||
}
|
||||
|
||||
/// Set the status of the interface, true for connected,
|
||||
/// false for disconnected.
|
||||
pub fn set_status(&self, status: bool) -> io::Result<()> {
|
||||
let status: u32 = if status { 1 } else { 0 };
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
&status,
|
||||
&mut (),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TapDevice {
|
||||
pub fn create() -> io::Result<Self> {
|
||||
let luid = iface::create_interface()?;
|
||||
// Even after retrieving the luid, we might need to wait
|
||||
let start = time::Instant::now();
|
||||
let handle = loop {
|
||||
// If we surpassed 2 seconds just return
|
||||
let now = time::Instant::now();
|
||||
if now - start > time::Duration::from_secs(3) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::TimedOut,
|
||||
"Interface timed out",
|
||||
));
|
||||
}
|
||||
|
||||
match iface::open_interface(&luid) {
|
||||
Err(_) => {
|
||||
std::thread::yield_now();
|
||||
continue;
|
||||
}
|
||||
Ok(handle) => break handle,
|
||||
};
|
||||
};
|
||||
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||
Ok(Self {
|
||||
index,
|
||||
luid,
|
||||
handle,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn open(name: &str) -> io::Result<Self> {
|
||||
let name = encode_utf16(name);
|
||||
|
||||
let luid = ffi::alias_to_luid(&name)?;
|
||||
iface::check_interface(&luid)?;
|
||||
|
||||
let handle = iface::open_interface(&luid)?;
|
||||
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||
Ok(Self {
|
||||
index,
|
||||
luid,
|
||||
handle,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn delete(self) -> io::Result<()> {
|
||||
// iface::delete_interface(&self.luid)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl IFace for TapDevice {
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
self.set_status(false)
|
||||
}
|
||||
|
||||
fn get_index(&self) -> io::Result<u32> {
|
||||
Ok(self.index)
|
||||
}
|
||||
|
||||
fn get_name(&self) -> io::Result<String> {
|
||||
ffi::luid_to_alias(&self.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 set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_ip(index, &address, &mask)
|
||||
}
|
||||
|
||||
fn add_route(
|
||||
&self,
|
||||
dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
metric: u16,
|
||||
) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
route::add_route(index, dest, netmask, gateway, metric)
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
route::delete_route(index, dest, netmask, gateway)
|
||||
}
|
||||
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_mtu(index, mtu)
|
||||
}
|
||||
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_metric(index, metric)
|
||||
}
|
||||
}
|
||||
|
||||
impl TapDevice {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
ffi::read_file(self.handle, buf).map(|res| res as _)
|
||||
}
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
ffi::write_file(self.handle, buf).map(|res| res as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TapDevice {
|
||||
fn drop(&mut self) {
|
||||
let _ = ffi::close_handle(self.handle);
|
||||
let _ = iface::delete_interface(&self.luid);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user