Files
vnt/vnt-core/src/tun/general.rs
T
2026-02-10 18:20:39 +08:00

237 lines
6.7 KiB
Rust

use crate::enhanced_tunnel::outbound::EnhancedOutbound;
use crate::protocol::ip_packet_protocol::HEAD_LENGTH;
use crate::protocol::transmission::TransmissionBytes;
use crate::utils::task_control::{SubTask, TaskGroup};
use anyhow::{Context, bail};
use bytes::BytesMut;
use futures::{SinkExt, StreamExt};
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tokio::sync::mpsc::{Receiver, Sender};
use tun_rs::async_framed::{Decoder, DeviceFramedRead, DeviceFramedWrite, Encoder};
use tun_rs::{AsyncDevice, DeviceBuilder};
#[derive(Clone)]
pub struct DeviceIOManager {
task_group: TaskGroup,
device: DeviceMutex,
}
type DeviceMutex = Arc<tokio::sync::Mutex<(Option<DeviceTask>, Option<(Ipv4Addr, u8)>)>>;
pub struct DeviceTask {
device: Arc<AsyncDevice>,
task_recv: SubTask,
task_send: SubTask,
}
#[derive(Debug, Default)]
pub struct DeviceConfig {
pub tun_name: Option<String>,
#[cfg(unix)]
pub tun_fd: Option<i32>,
pub mtu: Option<u16>,
}
impl DeviceConfig {
pub fn set_tun_name(mut self, tun_name: String) -> Self {
self.tun_name = Some(tun_name);
self
}
#[cfg(unix)]
pub fn set_tun_fd(mut self, tun_fd: i32) -> Self {
self.tun_fd = Some(tun_fd);
self
}
pub fn set_mtu(mut self, mtu: u16) -> Self {
self.mtu = Some(mtu);
self
}
}
#[derive(Clone)]
pub struct TunInbound {
pub(crate) sender: Sender<TransmissionBytes>,
}
pub struct TunReceiver {
receiver: Receiver<TransmissionBytes>,
}
pub fn tun_channel() -> (TunInbound, TunReceiver) {
let (sender, receiver) = tokio::sync::mpsc::channel(1024);
(TunInbound { sender }, TunReceiver { receiver })
}
impl DeviceIOManager {
pub fn new(task_group: TaskGroup) -> DeviceIOManager {
Self {
task_group,
device: Arc::new(Default::default()),
}
}
pub async fn stop_task(&self) {
let mut guard = self.device.lock().await;
if let Some(dev) = guard.0.take() {
dev.task_recv.stop().await;
dev.task_send.stop().await;
}
}
pub async fn start_task(
&self,
device_config: DeviceConfig,
receiver: TunReceiver,
enhanced_outbound: EnhancedOutbound,
) -> anyhow::Result<()> {
self.stop_task().await;
let task = create(
&self.task_group,
device_config,
receiver.receiver,
enhanced_outbound,
)?;
self.device.lock().await.0.replace(task);
Ok(())
}
#[cfg(not(target_os = "android"))]
pub async fn tun_if_index(&self) -> anyhow::Result<u32> {
let guard = self.device.lock().await;
if let Some(v) = &guard.0 {
Ok(v.device.if_index()?)
} else {
bail!("device doesn't exist")
}
}
pub async fn set_network(&self, ip: Ipv4Addr, prefix_len: u8) -> anyhow::Result<()> {
let mut guard = self.device.lock().await;
let Some(dev) = guard.0.as_ref() else {
bail!("未启动tun")
};
if let Some(v) = guard.1.as_ref()
&& v.0 == ip
&& v.1 == prefix_len
{
return Ok(());
}
dev.device
.set_network_address(ip, prefix_len, None)
.context("设置IP失败")?;
guard.1 = Some((ip, prefix_len));
Ok(())
}
}
fn create_tun(config: DeviceConfig) -> anyhow::Result<AsyncDevice> {
#[cfg(unix)]
if let Some(fd) = config.tun_fd {
// SAFETY: Caller must ensure fd is a valid, open file descriptor for a TUN device.
// Using an invalid fd may cause undefined behavior.
unsafe { return Ok(AsyncDevice::from_fd(fd)?) }
}
let mut builder = DeviceBuilder::new();
if let Some(tun_name) = config.tun_name {
builder = builder.name(tun_name);
}
if let Some(mtu) = config.mtu {
builder = builder.mtu(mtu);
}
#[cfg(windows)]
{
builder = builder.metric(1);
}
#[cfg(target_os = "linux")]
{
builder = builder.offload(true);
}
let dev = builder.build_async().context("创建tun失败")?;
#[cfg(target_os = "linux")]
{
_ = dev.set_tx_queue_len(1000);
}
Ok(dev)
}
fn create(
task_group: &TaskGroup,
config: DeviceConfig,
receiver: Receiver<TransmissionBytes>,
enhanced_outbound: EnhancedOutbound,
) -> anyhow::Result<DeviceTask> {
let device = Arc::new(create_tun(config)?);
let device_framed_read = DeviceFramedRead::new(device.clone(), BytesCodec::new());
let device_framed_write = DeviceFramedWrite::new(device.clone(), BytesCodec::new());
let task_recv = task_group.spawn(async move {
if let Err(e) = in_tun_loop(receiver, device_framed_write).await {
log::error!("in_tun_loop error: {e:?}")
}
});
let task_send = task_group.spawn(async move {
if let Err(e) = out_tun_loop(device_framed_read, enhanced_outbound).await {
log::error!("out_tun_loop error: {e:?}");
}
});
Ok(DeviceTask {
device,
task_recv,
task_send,
})
}
async fn in_tun_loop(
mut receiver: Receiver<TransmissionBytes>,
mut device_framed_write: DeviceFramedWrite<BytesCodec, Arc<AsyncDevice>>,
) -> anyhow::Result<()> {
while let Some(data) = receiver.recv().await {
match device_framed_write.send(data).await {
Ok(_) => {}
Err(e) => {
log::error!("send to tun error: {:?}", e);
return Err(anyhow::anyhow!(e));
}
}
}
Ok(())
}
async fn out_tun_loop(
mut device_framed_read: DeviceFramedRead<BytesCodec, Arc<AsyncDevice>>,
enhanced_outbound: EnhancedOutbound,
) -> anyhow::Result<()> {
while let Some(rs) = device_framed_read.next().await {
let bytes_mut = rs?;
enhanced_outbound.ipv4_outbound(bytes_mut).await;
}
Ok(())
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
pub struct BytesCodec(());
impl BytesCodec {
pub fn new() -> BytesCodec {
BytesCodec(())
}
}
impl Decoder for BytesCodec {
type Item = TransmissionBytes;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<TransmissionBytes>, io::Error> {
if !buf.is_empty() {
let mut bytes = TransmissionBytes::new_offset(HEAD_LENGTH);
bytes.put(buf)?;
buf.clear();
Ok(Some(bytes))
} else {
Ok(None)
}
}
}
impl Encoder<TransmissionBytes> for BytesCodec {
type Error = io::Error;
fn encode(&mut self, data: TransmissionBytes, buf: &mut BytesMut) -> Result<(), io::Error> {
buf.reserve(data.len());
buf.extend_from_slice(&data);
Ok(())
}
}