add tcp hole punching (#1713)

add tcp hole punching and tcp stun test
This commit is contained in:
KKRainbow
2025-12-28 21:35:30 +08:00
committed by GitHub
parent 37531507db
commit c19cd1bff3
29 changed files with 1502 additions and 300 deletions
+11 -11
View File
@@ -134,25 +134,25 @@ impl FakeTcpTunnelListener {
IpAddr::V6(ip) => (None, Some(ip)),
};
let ret = self
.stack_map
.entry(interface_name.to_string())
.or_insert_with(|| {
let tun = create_tun(interface_name, None, local_socket_addr);
let ret = match self.stack_map.entry(interface_name.to_string()) {
dashmap::Entry::Occupied(entry) => entry.get().clone(),
dashmap::Entry::Vacant(entry) => {
let tun = create_tun(interface_name, None, local_socket_addr)?;
tracing::info!(
?local_socket_addr,
"create new stack with interface_name: {:?}",
interface_name
);
// TODO: Get local MAC address of the interface
Arc::new(Mutex::new(stack::Stack::new(
let stack = Arc::new(Mutex::new(stack::Stack::new(
tun,
local_ip.unwrap_or(Ipv4Addr::UNSPECIFIED),
local_ip6,
accept_result.mac,
)))
})
.clone();
)));
entry.insert(stack.clone());
stack
}
};
Ok(ret)
}
@@ -314,7 +314,7 @@ impl crate::tunnel::TunnelConnector for FakeTcpTunnelConnector {
IpAddr::V6(ip) => (None, Some(ip)),
};
let tun = create_tun(&interface_name, Some(remote_addr), local_addr);
let tun = create_tun(&interface_name, Some(remote_addr), local_addr)?;
let local_ip = local_ip.unwrap_or("0.0.0.0".parse().unwrap());
let mut stack = stack::Stack::new(tun, local_ip, local_ip6, mac);
let driver_type = stack.driver_type();
+16 -16
View File
@@ -1,6 +1,6 @@
pub mod pnet;
use std::{net::SocketAddr, sync::Arc};
use std::{io, net::SocketAddr, sync::Arc};
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
@@ -10,19 +10,19 @@ cfg_if::cfg_if! {
interface_name: &str,
src_addr: Option<SocketAddr>,
dst_addr: SocketAddr,
) -> Arc<dyn super::stack::Tun> {
) -> io::Result<Arc<dyn super::stack::Tun>> {
match linux_bpf::LinuxBpfTun::new(interface_name, src_addr, dst_addr) {
Ok(tun) => Arc::new(tun),
Ok(tun) => Ok(Arc::new(tun)),
Err(e) => {
tracing::warn!(
?e,
interface_name,
"LinuxBpfTun init failed, falling back to PnetTun"
);
Arc::new(pnet::PnetTun::new(
Ok(Arc::new(pnet::PnetTun::new(
interface_name,
pnet::create_packet_filter(src_addr, dst_addr),
))
)?))
}
}
}
@@ -33,19 +33,19 @@ cfg_if::cfg_if! {
interface_name: &str,
src_addr: Option<SocketAddr>,
dst_addr: SocketAddr,
) -> Arc<dyn super::stack::Tun> {
) -> io::Result<Arc<dyn super::stack::Tun>> {
match macos_bpf::MacosBpfTun::new(interface_name, src_addr, dst_addr) {
Ok(tun) => Arc::new(tun),
Ok(tun) => Ok(Arc::new(tun)),
Err(e) => {
tracing::warn!(
?e,
interface_name,
"MacosBpfTun init failed, falling back to PnetTun"
);
Arc::new(pnet::PnetTun::new(
Ok(Arc::new(pnet::PnetTun::new(
interface_name,
pnet::create_packet_filter(src_addr, dst_addr),
))
)?))
}
}
}
@@ -56,19 +56,19 @@ cfg_if::cfg_if! {
_interface_name: &str,
_src_addr: Option<SocketAddr>,
local_addr: SocketAddr,
) -> Arc<dyn super::stack::Tun> {
) -> io::Result<Arc<dyn super::stack::Tun>> {
match windivert::WinDivertTun::new(local_addr) {
Ok(tun) => Arc::new(tun),
Ok(tun) => Ok(Arc::new(tun)),
Err(e) => {
tracing::warn!(
?e,
?local_addr,
"WinDivertTun init failed, falling back to PnetTun"
);
Arc::new(pnet::PnetTun::new(
Ok(Arc::new(pnet::PnetTun::new(
local_addr.to_string().as_str(),
pnet::create_packet_filter(None, local_addr),
))
)?))
}
}
}
@@ -77,11 +77,11 @@ cfg_if::cfg_if! {
interface_name: &str,
src_addr: Option<SocketAddr>,
dst_addr: SocketAddr,
) -> Arc<dyn super::stack::Tun> {
Arc::new(pnet::PnetTun::new(
) -> io::Result<Arc<dyn super::stack::Tun>> {
Ok(Arc::new(pnet::PnetTun::new(
interface_name,
pnet::create_packet_filter(src_addr, dst_addr),
))
)?))
}
}
}
+14 -16
View File
@@ -1,4 +1,5 @@
use std::{
io,
net::{IpAddr, SocketAddr},
sync::{
atomic::{AtomicU32, Ordering},
@@ -145,14 +146,11 @@ struct InterfaceWorker {
}
impl InterfaceWorker {
fn new(interface: NetworkInterface) -> Arc<Self> {
fn new(interface: NetworkInterface) -> io::Result<Arc<Self>> {
let (tx, mut rx) = match datalink::channel(&interface, Default::default()) {
Ok(pnet::datalink::Channel::Ethernet(tx, rx)) => (tx, rx),
Ok(_) => panic!("Unhandled channel type"),
Err(e) => panic!(
"An error occurred when creating the datalink channel: {}",
e
),
Ok(_) => return Err(io::Error::other("Unhandled channel type")),
Err(e) => return Err(io::Error::other(e)),
};
let subscribers = Arc::new(DashMap::<u32, Subscriber>::new());
@@ -187,10 +185,10 @@ impl InterfaceWorker {
}
});
Arc::new(Self {
Ok(Arc::new(Self {
tx: Mutex::new(tx),
subscribers,
})
}))
}
fn subscribe(&self, filter: PacketFilter, sender: tokio::sync::mpsc::Sender<Vec<u8>>) -> u32 {
@@ -207,13 +205,13 @@ impl InterfaceWorker {
static INTERFACE_MANAGERS: Lazy<DashMap<String, Weak<InterfaceWorker>>> = Lazy::new(DashMap::new);
fn get_or_create_worker(interface_name: &str) -> Arc<InterfaceWorker> {
fn get_or_create_worker(interface_name: &str) -> io::Result<Arc<InterfaceWorker>> {
// Check if we have an active worker
if let Some(worker) = INTERFACE_MANAGERS
.get(interface_name)
.and_then(|w| w.upgrade())
{
return worker;
return Ok(worker);
}
// Need to create new worker.
@@ -229,9 +227,9 @@ fn get_or_create_worker(interface_name: &str) -> Arc<InterfaceWorker> {
.find(|iface| iface.name == interface_name)
.expect("Network interface not found");
let worker = InterfaceWorker::new(interface);
let worker = InterfaceWorker::new(interface)?;
INTERFACE_MANAGERS.insert(interface_name.to_string(), Arc::downgrade(&worker));
worker
Ok(worker)
}
pub struct PnetTun {
@@ -241,17 +239,17 @@ pub struct PnetTun {
}
impl PnetTun {
pub fn new(interface_name: &str, filter: PacketFilter) -> Self {
pub fn new(interface_name: &str, filter: PacketFilter) -> io::Result<Self> {
tracing::debug!(interface_name, "Creating new PnetTun");
let worker = get_or_create_worker(interface_name);
let worker = get_or_create_worker(interface_name)?;
let (tx, rx) = tokio::sync::mpsc::channel(1024);
let id = worker.subscribe(filter, tx);
Self {
Ok(Self {
worker,
subscription_id: id,
recv_queue: Mutex::new(rx),
}
})
}
}