[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 const VNT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
|
||||||
|
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
pub mod cipher;
|
pub mod cipher;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod error;
|
|
||||||
pub mod external_route;
|
pub mod external_route;
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
pub mod igmp_server;
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
pub mod ip_proxy;
|
pub mod ip_proxy;
|
||||||
pub mod nat;
|
pub mod nat;
|
||||||
@@ -16,3 +12,5 @@ pub mod proto;
|
|||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
pub mod tun_tap_device;
|
pub mod tun_tap_device;
|
||||||
pub mod util;
|
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