[mio] 去除多余代码

This commit is contained in:
lubeilin
2024-02-29 22:28:20 +08:00
parent 318c267c34
commit 5850a59ec9
28 changed files with 2 additions and 3433 deletions
-25
View File
@@ -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" }
-128
View File
@@ -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()
}
}
-126
View File
@@ -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
}
}
-94
View File
@@ -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>;
}
-54
View File
@@ -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>;
-32
View File
@@ -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()
}
-384
View File
@@ -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,
}
}
}
-43
View File
@@ -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)
}
-111
View File
@@ -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);
-445
View File
@@ -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)
// }
// }
-32
View File
@@ -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)
}
-60
View File
@@ -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());
}
}
-124
View File
@@ -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);
}
}
}
}
-24
View File
@@ -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};
-124
View File
@@ -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()
// }
// }
-21
View File
@@ -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
View File
@@ -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};
-48
View File
@@ -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 _))
}
-175
View File
@@ -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);
}
}
}
-144
View File
@@ -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, &ethernet_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)
}
}
-153
View File
@@ -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) {}
-363
View File
@@ -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(&ethernet_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(),
}
}
-37
View File
@@ -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"
]
-49
View File
@@ -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<()>;
}
-80
View File
@@ -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(())
}
-65
View File
@@ -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(())
}
-297
View File
@@ -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,
)
}
-191
View File
@@ -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);
}
}