合并tun、tap配置,减少重复代码

This commit is contained in:
lubeilin
2023-06-23 15:29:03 +08:00
parent 4bbd5282ee
commit b640bc50ef
14 changed files with 760 additions and 562 deletions
-58
View File
@@ -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
))
}
-13
View File
@@ -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!()
}
-21
View File
@@ -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};
-101
View File
@@ -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<TapDevice>, Arc<Mutex<()>>);
impl TapWriter {
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
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<TapDevice>);
impl TapReader {
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
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();
}
-57
View File
@@ -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(())
}
-72
View File
@@ -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(())
}
-21
View File
@@ -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;
-72
View File
@@ -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<usize> {
self.0.read(buf)
}
}
#[derive(Clone)]
pub struct TunWriter(pub(crate) Writer, pub(crate) bool, pub(crate) Arc<Mutex<Device>>);
impl TunWriter {
pub fn write(&self, packet: &[u8]) -> io::Result<()> {
if self.1 {
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);
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(());
}
}
-147
View File
@@ -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<TunDevice>, Arc<Mutex<()>>);
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<TunDevice>);
impl TunReader {
pub fn next(&self) -> io::Result<TunPacket> {
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(_) => {}
}
}
}
+121
View File
@@ -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) {}
+114
View File
@@ -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) {}
+32
View File
@@ -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,
}
+144
View File
@@ -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<Mutex<Device>>,
pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
ip: Arc<AtomicCell<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,
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::<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);
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, &ethernet_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<usize> {
self.0.read(buf)
}
}
+349
View File
@@ -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<Device>,
lock: Arc<Mutex<()>>,
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
ip: Arc<AtomicCell<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,
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(&ethernet_packet.buffer)?;
}
}
Ok(())
}
pub fn change_ip(
&self,
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
old_netmask: Ipv4Addr,
old_gateway: Ipv4Addr,
) -> io::Result<()> {
let _guard = self.lock.lock();
let dev: &dyn IFace = match self.device.as_ref() {
Device::Tun(dev) => {
dev as &dyn IFace
}
Device::Tap((dev, _)) => {
dev as &dyn IFace
}
};
if let Err(e) =
dev.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
{
log::warn!("{:?}", e);
}
dev.set_ip(address, netmask)?;
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<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)>,
) -> 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()
}
}
}