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

101 lines
2.9 KiB
Rust

use crate::enhanced_tunnel::quic_over::quic_client::QuicTunnelClient;
use crate::utils::task_control::TaskGroup;
use pnet_packet::ip::{IpNextHeaderProtocol, IpNextHeaderProtocols};
use std::fmt;
use std::net::{Ipv4Addr, SocketAddr};
use std::str::FromStr;
pub(crate) mod tcp_port_mapping;
pub(crate) mod udp_port_mapping;
pub(crate) async fn port_mapping_start(
task_group: &TaskGroup,
list: Vec<PortMapping>,
quic_tunnel_client: QuicTunnelClient,
) -> anyhow::Result<()> {
tcp_port_mapping::start(task_group, &list, quic_tunnel_client.clone()).await?;
udp_port_mapping::start(task_group, &list, quic_tunnel_client).await?;
Ok(())
}
#[derive(Debug, Clone)]
pub struct PortMapping {
pub protocol: IpNextHeaderProtocol,
pub src_addr: SocketAddr,
pub virtual_target_ip: Ipv4Addr,
pub dst_host: String,
pub dst_port: u16,
}
impl fmt::Display for PortMapping {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}://{}-{}-{}:{}",
protocol_to_str(self.protocol),
self.src_addr,
self.virtual_target_ip,
self.dst_host,
self.dst_port
)
}
}
impl FromStr for PortMapping {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (proto_str, rest) = s.split_once("://").ok_or("missing '://'")?;
let protocol =
str_to_protocol(proto_str).ok_or_else(|| format!("unknown protocol: {}", proto_str))?;
let mut parts = rest.splitn(3, '-');
let src_addr = parts
.next()
.ok_or("missing src_addr")?
.parse::<SocketAddr>()
.map_err(|e| format!("invalid src_addr: {}", e))?;
let virtual_target_ip = parts
.next()
.ok_or("missing virtual_target_ip")?
.parse::<Ipv4Addr>()
.map_err(|e| format!("invalid virtual_target_ip: {}", e))?;
let dst = parts.next().ok_or("missing destination")?;
let (dst_host, dst_port) = dst.rsplit_once(':').ok_or("missing dst port")?;
let dst_port = dst_port
.parse::<u16>()
.map_err(|e| format!("invalid dst_port: {}", e))?;
if dst_port == 0 {
return Err("invalid dst port: 0".to_string());
}
Ok(Self {
protocol,
src_addr,
virtual_target_ip,
dst_host: dst_host.to_string(),
dst_port,
})
}
}
fn protocol_to_str(p: IpNextHeaderProtocol) -> &'static str {
match p {
IpNextHeaderProtocols::Tcp => "tcp",
IpNextHeaderProtocols::Udp => "udp",
_ => "unknown",
}
}
fn str_to_protocol(s: &str) -> Option<IpNextHeaderProtocol> {
match s.to_ascii_lowercase().as_str() {
"tcp" => Some(IpNextHeaderProtocols::Tcp),
"udp" => Some(IpNextHeaderProtocols::Udp),
_ => None,
}
}