v2
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
use crate::context::NetworkAddr;
|
||||
use crate::nat::internal_nat::InternalNatInbound;
|
||||
use crate::protocol::transmission::TransmissionBytes;
|
||||
use crate::tun::TunDataInbound;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum EnhancedTunInbound {
|
||||
Tun(TunDataInbound),
|
||||
Nat(InternalNatInbound),
|
||||
}
|
||||
impl EnhancedTunInbound {
|
||||
pub async fn inbound(&self, data: TransmissionBytes, net: &NetworkAddr) -> anyhow::Result<()> {
|
||||
match self {
|
||||
EnhancedTunInbound::Tun(tun) => tun.send(data, net).await,
|
||||
EnhancedTunInbound::Nat(nat) => nat.send(&data, net).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
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(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
mod general;
|
||||
pub use general::*;
|
||||
mod sender;
|
||||
pub use sender::*;
|
||||
|
||||
pub mod enhanced_tun;
|
||||
@@ -0,0 +1,40 @@
|
||||
use crate::context::NetworkAddr;
|
||||
use crate::nat::AllowSubnetExternalRoute;
|
||||
use crate::protocol::transmission::TransmissionBytes;
|
||||
use crate::tun::TunInbound;
|
||||
use pnet_packet::ipv4::Ipv4Packet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TunDataInbound {
|
||||
allow_subnet: AllowSubnetExternalRoute,
|
||||
tun_inbound: TunInbound,
|
||||
}
|
||||
impl TunDataInbound {
|
||||
pub fn new(tun_inbound: TunInbound, allow_subnet: AllowSubnetExternalRoute) -> Self {
|
||||
Self {
|
||||
allow_subnet,
|
||||
tun_inbound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TunDataInbound {
|
||||
pub async fn send(&self, data: TransmissionBytes, net: &NetworkAddr) -> anyhow::Result<()> {
|
||||
if data[0] >> 4 != 4 {
|
||||
return Ok(());
|
||||
}
|
||||
let Some(ipv4) = Ipv4Packet::new(data.as_ref()) else {
|
||||
return Ok(());
|
||||
};
|
||||
let dest = ipv4.get_destination();
|
||||
if net.network().contains(&dest)
|
||||
|| dest == net.broadcast
|
||||
|| dest.is_broadcast()
|
||||
|| dest.is_multicast()
|
||||
|| self.allow_subnet.allow(&dest)
|
||||
{
|
||||
self.tun_inbound.sender.send(data).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user