From b640bc50efe5f32fb9ecb72027340efa6a1e119d Mon Sep 17 00:00:00 2001 From: lubeilin <1791778603@qq.com> Date: Fri, 23 Jun 2023 15:29:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6tun=E3=80=81tap=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=EF=BC=8C=E5=87=8F=E5=B0=91=E9=87=8D=E5=A4=8D=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- switch/src/tap_device/linux.rs | 58 ----- switch/src/tap_device/mac.rs | 13 - switch/src/tap_device/mod.rs | 21 -- switch/src/tap_device/windows.rs | 101 -------- switch/src/tun_device/linux.rs | 57 ----- switch/src/tun_device/mac.rs | 72 ------ switch/src/tun_device/mod.rs | 21 -- switch/src/tun_device/unix.rs | 72 ------ switch/src/tun_device/windows.rs | 147 ----------- switch/src/tun_tap_device/linux.rs | 121 ++++++++++ switch/src/tun_tap_device/mac.rs | 114 +++++++++ switch/src/tun_tap_device/mod.rs | 32 +++ switch/src/tun_tap_device/unix.rs | 144 +++++++++++ switch/src/tun_tap_device/windows.rs | 349 +++++++++++++++++++++++++++ 14 files changed, 760 insertions(+), 562 deletions(-) delete mode 100644 switch/src/tap_device/linux.rs delete mode 100644 switch/src/tap_device/mac.rs delete mode 100644 switch/src/tap_device/mod.rs delete mode 100644 switch/src/tap_device/windows.rs delete mode 100644 switch/src/tun_device/linux.rs delete mode 100644 switch/src/tun_device/mac.rs delete mode 100644 switch/src/tun_device/mod.rs delete mode 100644 switch/src/tun_device/unix.rs delete mode 100644 switch/src/tun_device/windows.rs create mode 100644 switch/src/tun_tap_device/linux.rs create mode 100644 switch/src/tun_tap_device/mac.rs create mode 100644 switch/src/tun_tap_device/mod.rs create mode 100644 switch/src/tun_tap_device/unix.rs create mode 100644 switch/src/tun_tap_device/windows.rs diff --git a/switch/src/tap_device/linux.rs b/switch/src/tap_device/linux.rs deleted file mode 100644 index 7ac2f76..0000000 --- a/switch/src/tap_device/linux.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::tun_device::{TunReader, TunWriter}; - -pub type TapReader = TunReader; -pub type TapWriter = TunWriter; - -use std::net::Ipv4Addr; -use std::sync::Arc; -use tun::Device; -use parking_lot::Mutex; -use std::io; - -pub fn create_tap( - address: Ipv4Addr, - netmask: Ipv4Addr, - gateway: Ipv4Addr, -) -> io::Result<(TunWriter, TunReader, [u8; 6])> { - println!("========TAP网卡配置========"); - let mut config = tun::Configuration::default(); - - config - .destination(gateway) - .address(address) - .netmask(netmask) - .mtu(1420) - .layer(tun::Layer::L2) - // .queues(2) 用多个队列有兼容性问题 - .up(); - - let dev = tun::create(&config).unwrap(); - let name = dev.name(); - println!("name:{:?}", name); - let packet_information = dev.has_packet_information(); - let queue = dev.queue(0).unwrap(); - let reader = queue.reader(); - let writer = queue.writer(); - let get_mac_cmd = format!("cat /sys/class/net/{}/address", name); - let mac_out = std::process::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(); - } - println!("mac:{:?}", mac); - println!("========TAP网卡配置========"); - Ok(( - TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))), - TunReader(reader, packet_information), - mac - )) -} diff --git a/switch/src/tap_device/mac.rs b/switch/src/tap_device/mac.rs deleted file mode 100644 index 668df6a..0000000 --- a/switch/src/tap_device/mac.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::tun_device::{TunReader, TunWriter}; - -pub type TapReader = TunReader; -pub type TapWriter = TunWriter; -use std::net::Ipv4Addr; - -pub fn create_tap( - address: Ipv4Addr, - netmask: Ipv4Addr, - gateway: Ipv4Addr, -) -> crate::error::Result<(TapWriter, TapReader, [u8; 6])> { - unimplemented!() -} \ No newline at end of file diff --git a/switch/src/tap_device/mod.rs b/switch/src/tap_device/mod.rs deleted file mode 100644 index 77194bd..0000000 --- a/switch/src/tap_device/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[cfg(target_os = "windows")] -mod windows; -#[cfg(any(target_os = "linux", target_os = "android"))] -mod linux; -#[cfg(target_os = "macos")] -mod mac; -#[cfg(target_os = "macos")] -pub use mac::{TapWriter, TapReader}; -#[cfg(target_os = "macos")] -pub use mac::create_tap; - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub use linux::{TapWriter, TapReader}; -#[cfg(any(target_os = "linux", target_os = "android"))] -pub use linux::create_tap; -#[cfg(target_os = "windows")] -pub use windows::create_tap; -#[cfg(target_os = "windows")] -pub use windows::delete_tap; -#[cfg(target_os = "windows")] -pub use windows::{TapReader, TapWriter}; \ No newline at end of file diff --git a/switch/src/tap_device/windows.rs b/switch/src/tap_device/windows.rs deleted file mode 100644 index 80606c3..0000000 --- a/switch/src/tap_device/windows.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::io; -use std::net::Ipv4Addr; -use std::sync::Arc; - -use parking_lot::Mutex; - -use win_tun_tap::{IFace, TapDevice}; - -#[derive(Clone)] -pub struct TapWriter(Arc, Arc>); - -impl TapWriter { - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn change_ip( - &self, - address: Ipv4Addr, - netmask: Ipv4Addr, - gateway: Ipv4Addr, - old_netmask: Ipv4Addr, - old_gateway: Ipv4Addr, - ) -> io::Result<()> { - if let Err(e) = - self.0.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway) - { - log::warn!("{:?}", e); - } - self.0.set_ip(address, netmask)?; - self.0.add_route(dest(gateway, netmask), netmask, gateway) - } - pub fn close(&self) -> io::Result<()> { - self.0.shutdown() - } -} - -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], - ]) -} - -#[derive(Clone)] -pub struct TapReader(Arc); - -impl TapReader { - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } -} - -pub const TAP_INTERFACE_NAME: &str = "Switch-Tap-V1"; - -pub fn create_tap( - address: Ipv4Addr, - netmask: Ipv4Addr, - gateway: Ipv4Addr, -) -> io::Result<(TapWriter, TapReader, [u8; 6])> { - println!("========TAP网卡配置========"); - 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()?; - println!("name:{:?}", tap_device.get_name()?); - println!("version:{:x?}", tap_device.get_version()?); - println!("mac:{:x?}", mac); - tap_device.set_ip(address, netmask)?; - tap_device.set_metric(1)?; - tap_device.set_mtu(1420)?; - tap_device.set_status(true)?; - tap_device.add_route(address, netmask, gateway)?; - let tap = Arc::new(tap_device); - println!("========TAP网卡配置========"); - Ok(( - TapWriter(tap.clone(), Arc::default()), - TapReader(tap), - mac - )) -} - -pub fn delete_tap() { - let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) { - Ok(tap_device) => tap_device, - Err(_) => { - return; - } - }; - let _ = tap_device.delete(); -} \ No newline at end of file diff --git a/switch/src/tun_device/linux.rs b/switch/src/tun_device/linux.rs deleted file mode 100644 index ccc671d..0000000 --- a/switch/src/tun_device/linux.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::io; -use crate::tun_device::{TunReader, TunWriter}; -use std::net::Ipv4Addr; -use std::sync::Arc; -use tun::Device; -use parking_lot::Mutex; -use std::process::Command; - -pub fn create_tun( - address: Ipv4Addr, - netmask: Ipv4Addr, - gateway: Ipv4Addr, - in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, -) -> crate::error::Result<(TunWriter, TunReader)> { - println!("========TUN网卡配置========"); - let mut config = tun::Configuration::default(); - - config - .destination(gateway) - .address(address) - .netmask(netmask) - .mtu(1420) - // .queues(2) 用多个队列有兼容性问题 - .up(); - - let dev = tun::create(&config).unwrap(); - 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(); - println!("name:{:?}", name); - for (address, netmask) in in_ips { - add_route(name, address, netmask)?; - } - println!("========TUN网卡配置========"); - Ok(( - TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))), - TunReader(reader, packet_information), - )) -} - -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!("添加路由失败: {:?}", route_add_out))); - } - Ok(()) -} diff --git a/switch/src/tun_device/mac.rs b/switch/src/tun_device/mac.rs deleted file mode 100644 index cc53d8e..0000000 --- a/switch/src/tun_device/mac.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::net::Ipv4Addr; -use std::process::Command; -use std::io; -use tun::Device; -use parking_lot::Mutex; -use std::sync::Arc; - -use crate::tun_device::{TunReader, TunWriter}; - -pub fn create_tun( - address: Ipv4Addr, - netmask: Ipv4Addr, - gateway: Ipv4Addr, - in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, -) -> crate::error::Result<(TunWriter, TunReader)> { - println!("========TUN网卡配置========"); - let mut config = tun::Configuration::default(); - - config - .destination(gateway) - .address(address) - .netmask(netmask) - .mtu(1420) - .up(); - - let dev = tun::create(&config).unwrap(); - let name = dev.name(); - config_ip(name, address, netmask, gateway)?; - add_route(name, address, netmask)?; - for (address, netmask) in in_ips { - add_route(name, address, netmask)?; - } - let packet_information = dev.has_packet_information(); - let queue = dev.queue(0).unwrap(); - let reader = queue.reader(); - let writer = queue.writer(); - println!("name:{:?}", name); - println!("========TUN网卡配置========"); - Ok(( - TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))), - TunReader(reader, packet_information), - )) -} - -fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> { - let route_add_str: String = format!( - "sudo route -n add -net {:?}/{:?} -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!("添加路由失败: {:?}", route_add_out))); - } - Ok(()) -} - -pub(crate) 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!("设置网络地址失败: {:?}", up_eth_out))); - } - Ok(()) -} diff --git a/switch/src/tun_device/mod.rs b/switch/src/tun_device/mod.rs deleted file mode 100644 index 20c85cd..0000000 --- a/switch/src/tun_device/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[cfg(any(target_os = "linux", target_os = "android"))] -pub use linux::create_tun; -#[cfg(target_os = "macos")] -pub use mac::create_tun; -#[cfg(any(unix))] -pub use unix::{TunReader, TunWriter}; -#[cfg(target_os = "windows")] -pub use windows::create_tun; -#[cfg(target_os = "windows")] -pub use windows::delete_tun; -#[cfg(target_os = "windows")] -pub use windows::{TunReader, TunWriter}; - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub mod linux; -#[cfg(target_os = "macos")] -pub mod mac; -#[cfg(any(unix))] -pub mod unix; -#[cfg(target_os = "windows")] -pub mod windows; diff --git a/switch/src/tun_device/unix.rs b/switch/src/tun_device/unix.rs deleted file mode 100644 index ce90080..0000000 --- a/switch/src/tun_device/unix.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::io; -use std::sync::Arc; - -use bytes::BufMut; -use tun::platform::posix::{Reader, Writer}; -use std::net::Ipv4Addr; -use std::os::unix::io::AsRawFd; -#[cfg(any(target_os = "linux", target_os = "android"))] -use tun::platform::linux::Device; -#[cfg(any(target_os = "macos", target_os = "ios"))] -use tun::platform::macos::Device; -use parking_lot::Mutex; - -#[derive(Clone)] -pub struct TunReader(pub(crate) Reader, pub(crate) bool); - -impl TunReader { - pub fn read(&self, buf: & mut [u8]) -> io::Result { - self.0.read(buf) - } -} - - -#[derive(Clone)] -pub struct TunWriter(pub(crate) Writer, pub(crate) bool, pub(crate) Arc>); - -impl TunWriter { - pub fn write(&self, packet: &[u8]) -> io::Result<()> { - if self.1 { - let mut buf = Vec::::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); - self.0.write_all(&buf) - } else { - self.0.write_all(packet) - } - } - pub fn close(&self) -> io::Result<()>{ - unsafe { - let raw = self.0.as_raw_fd(); - if raw >= 0 { - libc::close(raw); - } - } - Ok(()) - } - 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(); - use tun::Device; - config - .destination(gateway) - .address(address) - .netmask(netmask) - .mtu(1420) - // .queues(2) - .up(); - let mut dev = self.2.lock(); - if let Err(e) = dev.configure(&config) { - return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e))); - } - #[cfg(target_os = "macos")] - if let Err(e) = crate::tun_device::mac::config_ip(dev.name(), address, netmask, gateway){ - log::error!("{}",e); - } - return Ok(()); - } -} diff --git a/switch/src/tun_device/windows.rs b/switch/src/tun_device/windows.rs deleted file mode 100644 index 611f02e..0000000 --- a/switch/src/tun_device/windows.rs +++ /dev/null @@ -1,147 +0,0 @@ -use std::{io, thread}; -use std::net::Ipv4Addr; -use std::sync::Arc; -use std::time::Duration; - -use libloading::Library; -use parking_lot::Mutex; - -use win_tun_tap::{IFace, TunDevice}; -use win_tun_tap::packet::TunPacket; - -pub const TUN_INTERFACE_NAME: &str = "Switch-V1"; -pub const TUN_POOL_NAME: &str = "Switch-V1"; - -#[derive(Clone)] -pub struct TunWriter(Arc, Arc>); - -impl TunWriter { - pub fn write(&self, buf: &[u8]) -> io::Result<()> { - let mut packet = self.0.allocate_send_packet(buf.len() as u16)?; - packet.bytes_mut().copy_from_slice(buf); - self.0.send_packet(packet); - return Ok(()); - } - pub fn change_ip( - &self, - address: Ipv4Addr, - netmask: Ipv4Addr, - gateway: Ipv4Addr, - old_netmask: Ipv4Addr, - old_gateway: Ipv4Addr, - ) -> io::Result<()> { - if let Err(e) = - self.0.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway) - { - log::warn!("{:?}", e); - } - self.0.set_ip(address, netmask)?; - self.0.add_route(dest(gateway, netmask), netmask, gateway) - } - pub fn close(&self) -> io::Result<()> { - self.0.shutdown() - } -} - -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], - ]) -} - -#[derive(Clone)] -pub struct TunReader(Arc); - - -impl TunReader { - pub fn next(&self) -> io::Result { - self.0.receive_blocking() - } -} - -pub fn create_tun( - address: Ipv4Addr, - netmask: Ipv4Addr, - gateway: Ipv4Addr, - in_ips:Vec<(Ipv4Addr,Ipv4Addr)> -) -> io::Result<(TunWriter, TunReader)> { - unsafe { - println!("========TUN网卡配置========"); - 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) => { - log::error!("wintun.dll not found"); - 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), - )); - } - } - } - }; - println!("name:{:?}", tun_device.get_name()?); - println!("version:{:?}", tun_device.version()?); - tun_device.set_ip(address, netmask)?; - tun_device.set_metric(1)?; - tun_device.set_mtu(1420)?; - for (address, netmask) in in_ips { - tun_device.add_route(address, netmask, gateway)?; - } - tun_device.add_route(address, netmask, gateway)?; - let device = Arc::new(tun_device); - println!("========TUN网卡配置========"); - Ok(( - TunWriter(device.clone(), Arc::default()), - TunReader(device), - )) - } -} - -pub fn delete_tun() { - unsafe { - match Library::new("wintun.dll") { - Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) { - Ok(_) => { - } - Err(_) => {} - }, - Err(_) => {} - } - } -} - - - - - diff --git a/switch/src/tun_tap_device/linux.rs b/switch/src/tun_tap_device/linux.rs new file mode 100644 index 0000000..a317f1e --- /dev/null +++ b/switch/src/tun_tap_device/linux.rs @@ -0,0 +1,121 @@ +use std::io; +use std::net::Ipv4Addr; +use crate::tun_tap_device::{DeviceReader, DeviceType, DeviceWriter}; +use tun::Device; +use parking_lot::Mutex; +use std::process::Command; +use std::sync::Arc; +use crate::tun_tap_device::unix::DeviceW; + +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) + .mtu(1420) + // .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)>, +) -> io::Result<(DeviceWriter, DeviceReader)> { + println!("========网卡配置========"); + let mut config = tun::Configuration::default(); + + config + .destination(gateway) + .address(address) + .netmask(netmask) + .mtu(1420) + // .queues(2) 用多个队列有兼容性问题 + .up(); + match device_type { + DeviceType::Tun => {} + DeviceType::Tap => { + config.layer(tun::Layer::L2); + } + } + let dev = tun::create(&config).unwrap(); + 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(); + println!("name:{:?}", 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)) + } + }; + println!("========TUN网卡配置========"); + Ok(( + DeviceWriter::new(device_w, Arc::new(Mutex::new(dev)), in_ips, address, packet_information), + DeviceReader::new(reader), + )) +} + +pub fn delete_device(_device_type: DeviceType) {} \ No newline at end of file diff --git a/switch/src/tun_tap_device/mac.rs b/switch/src/tun_tap_device/mac.rs new file mode 100644 index 0000000..b96e924 --- /dev/null +++ b/switch/src/tun_tap_device/mac.rs @@ -0,0 +1,114 @@ +use std::io; +use std::net::Ipv4Addr; +use crate::tun_tap_device::{DeviceReader, DeviceType, DeviceWriter}; +use tun::Device; +use parking_lot::Mutex; +use std::process::Command; +use std::sync::Arc; +use crate::tun_tap_device::unix::DeviceW; + +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) + .mtu(1420) + .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)>, +) -> io::Result<(DeviceWriter, DeviceReader)> { + match device_type { + DeviceType::Tun => {} + DeviceType::Tap => { + unimplemented!() + } + } + println!("========TUN网卡配置========"); + let mut config = tun::Configuration::default(); + + config + .destination(gateway) + .address(address) + .netmask(netmask) + .mtu(1420) + .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(); + println!("name:{:?}", name); + println!("========TUN网卡配置========"); + Ok(( + DeviceWriter::new(DeviceW::Tun(writer), Arc::new(Mutex::new(dev)), in_ips, address, packet_information), + DeviceReader::new(reader), + )) +} + +fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> { + let route_add_str: String = format!( + "sudo route -n add -net {:?}/{:?} -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) {} \ No newline at end of file diff --git a/switch/src/tun_tap_device/mod.rs b/switch/src/tun_tap_device/mod.rs new file mode 100644 index 0000000..fabc12d --- /dev/null +++ b/switch/src/tun_tap_device/mod.rs @@ -0,0 +1,32 @@ +#[cfg(target_os = "windows")] +pub mod windows; +#[cfg(any(target_os = "linux", target_os = "android"))] +pub mod linux; +#[cfg(target_os = "macos")] +pub mod mac; +#[cfg(any(unix))] +pub mod unix; + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub use linux::create_device; +#[cfg(any(target_os = "linux", target_os = "android"))] +pub use linux::delete_device; +#[cfg(any(unix))] +pub use unix::{DeviceWriter, DeviceReader}; + +#[cfg(target_os = "macos")] +pub use mac::create_device; +#[cfg(target_os = "macos")] +pub use mac::delete_device; + +#[cfg(target_os = "windows")] +pub use windows::create_device; +#[cfg(target_os = "windows")] +pub use windows::delete_device; +#[cfg(target_os = "windows")] +pub use windows::{DeviceWriter, DeviceReader}; + +pub enum DeviceType { + Tun, + Tap, +} \ No newline at end of file diff --git a/switch/src/tun_tap_device/unix.rs b/switch/src/tun_tap_device/unix.rs new file mode 100644 index 0000000..4b84242 --- /dev/null +++ b/switch/src/tun_tap_device/unix.rs @@ -0,0 +1,144 @@ +use std::io; +use std::sync::Arc; + +use bytes::BufMut; +use tun::platform::posix::{Reader, Writer}; +use std::net::Ipv4Addr; +use std::os::unix::io::AsRawFd; +use crossbeam::atomic::AtomicCell; +#[cfg(any(target_os = "linux", target_os = "android"))] +use tun::platform::linux::Device; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use tun::platform::macos::Device; +use parking_lot::Mutex; +use packet::ethernet; + +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>, + pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, + ip: Arc>, + packet_information: bool, +} + +impl DeviceWriter { + pub fn new(writer: DeviceW,lock: Arc>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, ip: Ipv4Addr, packet_information: bool) -> Self { + Self { + writer, + lock, + in_ips, + ip: Arc::new(AtomicCell::new(ip)), + packet_information, + } + } +} + +impl DeviceWriter { + pub fn write(packet_information: bool, writer: &Writer, packet: &[u8]) -> io::Result<()> { + if packet_information { + let mut buf = Vec::::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); + writer.write_all(&buf) + } else { + writer.write_all(packet) + } + } + ///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], 123, 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 ip(&self) -> Ipv4Addr { + self.ip.load() + } + pub fn close(&self) -> io::Result<()> { + 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() + } +} + +#[derive(Clone)] +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 { + self.0.read(buf) + } +} diff --git a/switch/src/tun_tap_device/windows.rs b/switch/src/tun_tap_device/windows.rs new file mode 100644 index 0000000..5c5520b --- /dev/null +++ b/switch/src/tun_tap_device/windows.rs @@ -0,0 +1,349 @@ +use std::{io, thread}; +use std::net::Ipv4Addr; +use std::sync::Arc; +use std::time::Duration; +use crossbeam::atomic::AtomicCell; +use libloading::Library; +use parking_lot::Mutex; +use packet::ethernet; +use packet::ethernet::packet::EthernetPacket; +use win_tun_tap::{IFace, TapDevice, TunDevice}; +use crate::tun_tap_device::DeviceType; + +pub const TUN_INTERFACE_NAME: &str = "Switch-Tun-V1"; +pub const TUN_POOL_NAME: &str = "Switch-Tun-V1"; +pub const TAP_INTERFACE_NAME: &str = "Switch-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, + lock: Arc>, + in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, + ip: Arc>, +} + +impl DeviceWriter { + pub fn new(device: Arc, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, ip: Ipv4Addr) -> Self { + Self { + device, + lock: Arc::new(Default::default()), + in_ips, + ip: Arc::new(AtomicCell::new(ip)), + } + } +} + +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], 123, 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)?; + self.ip.store(address); + 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) + } + pub fn ip(&self) -> Ipv4Addr { + self.ip.load() + } + 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], + ]) +} + +#[derive(Clone)] +pub struct DeviceReader { + device: Arc, +} + +impl DeviceReader { + pub fn new(device: Arc) -> Self { + Self { + device, + } + } +} + +impl DeviceReader { + pub fn read(&self, buf: &mut [u8]) -> io::Result { + 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)>, +) -> io::Result<(DeviceWriter, DeviceReader)> { + unsafe { + println!("========TUN网卡配置========"); + 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) => { + log::error!("wintun.dll not found"); + 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), + )); + } + } + } + }; + println!("name:{:?}", tun_device.get_name()?); + println!("version:{:?}", tun_device.version()?); + tun_device.set_ip(address, netmask)?; + tun_device.set_metric(1)?; + tun_device.set_mtu(1420)?; + // 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)?; + let device = Arc::new(Device::Tun(tun_device)); + println!("========TUN网卡配置========"); + Ok(( + DeviceWriter::new(device.clone(), in_ips, address), + DeviceReader::new(device), + )) + } +} + +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)>, +) -> io::Result<(DeviceWriter, DeviceReader)> { + println!("========TAP网卡配置========"); + 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()?; + println!("name:{:?}", tap_device.get_name()?); + println!("version:{:x?}", tap_device.get_version()?); + println!("mac:{:x?}", mac); + tap_device.set_ip(address, netmask)?; + tap_device.set_metric(1)?; + tap_device.set_mtu(1420)?; + 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)?; + let tap = Arc::new(Device::Tap((tap_device, mac))); + println!("========TAP网卡配置========"); + Ok(( + DeviceWriter::new(tap.clone(), in_ips, address), + DeviceReader::new(tap) + )) +} + +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)>, ) -> io::Result<(DeviceWriter, DeviceReader)> { + match device_type { + DeviceType::Tun => { + create_tun(address, netmask, gateway, in_ips) + } + DeviceType::Tap => { + create_tap(address, netmask, gateway, in_ips) + } + } +} + +pub fn delete_device(device_type: DeviceType) { + match device_type { + DeviceType::Tun => { + delete_tun() + } + DeviceType::Tap => { + delete_tap() + } + } +} +