mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 02:09:06 +00:00
support mapping subnet proxy (#978)
- **support mapping subproxy network cidr** - **add command line option for proxy network mapping** - **fix Instance leak in tests.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
mem::MaybeUninit,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddrV4},
|
||||
sync::Arc,
|
||||
sync::{Arc, Weak},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
@@ -34,7 +34,7 @@ use super::{
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
struct IcmpNatKey {
|
||||
dst_ip: std::net::IpAddr,
|
||||
real_dst_ip: std::net::IpAddr,
|
||||
icmp_id: u16,
|
||||
icmp_seq: u16,
|
||||
}
|
||||
@@ -45,15 +45,22 @@ struct IcmpNatEntry {
|
||||
my_peer_id: PeerId,
|
||||
src_ip: IpAddr,
|
||||
start_time: std::time::Instant,
|
||||
mapped_dst_ip: std::net::Ipv4Addr,
|
||||
}
|
||||
|
||||
impl IcmpNatEntry {
|
||||
fn new(src_peer_id: PeerId, my_peer_id: PeerId, src_ip: IpAddr) -> Result<Self, Error> {
|
||||
fn new(
|
||||
src_peer_id: PeerId,
|
||||
my_peer_id: PeerId,
|
||||
src_ip: IpAddr,
|
||||
mapped_dst_ip: Ipv4Addr,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
src_peer_id,
|
||||
my_peer_id,
|
||||
src_ip,
|
||||
start_time: std::time::Instant::now(),
|
||||
mapped_dst_ip,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -65,10 +72,10 @@ type NewPacketReceiver = tokio::sync::mpsc::UnboundedReceiver<IcmpNatKey>;
|
||||
#[derive(Debug)]
|
||||
pub struct IcmpProxy {
|
||||
global_ctx: ArcGlobalCtx,
|
||||
peer_manager: Arc<PeerManager>,
|
||||
peer_manager: Weak<PeerManager>,
|
||||
|
||||
cidr_set: CidrSet,
|
||||
socket: std::sync::Mutex<Option<socket2::Socket>>,
|
||||
socket: std::sync::Mutex<Option<Arc<socket2::Socket>>>,
|
||||
|
||||
nat_table: IcmpNatTable,
|
||||
|
||||
@@ -78,7 +85,10 @@ pub struct IcmpProxy {
|
||||
icmp_sender: Arc<std::sync::Mutex<Option<UnboundedSender<ZCPacket>>>>,
|
||||
}
|
||||
|
||||
fn socket_recv(socket: &Socket, buf: &mut [MaybeUninit<u8>]) -> Result<(usize, IpAddr), Error> {
|
||||
fn socket_recv(
|
||||
socket: &Socket,
|
||||
buf: &mut [MaybeUninit<u8>],
|
||||
) -> Result<(usize, IpAddr), std::io::Error> {
|
||||
let (size, addr) = socket.recv_from(buf)?;
|
||||
let addr = match addr.as_socket() {
|
||||
None => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
||||
@@ -87,15 +97,32 @@ fn socket_recv(socket: &Socket, buf: &mut [MaybeUninit<u8>]) -> Result<(usize, I
|
||||
Ok((size, addr))
|
||||
}
|
||||
|
||||
fn socket_recv_loop(socket: Socket, nat_table: IcmpNatTable, sender: UnboundedSender<ZCPacket>) {
|
||||
fn socket_recv_loop(
|
||||
socket: Arc<Socket>,
|
||||
nat_table: IcmpNatTable,
|
||||
sender: UnboundedSender<ZCPacket>,
|
||||
) {
|
||||
let mut buf = [0u8; 8192];
|
||||
let data: &mut [MaybeUninit<u8>] = unsafe { std::mem::transmute(&mut buf[..]) };
|
||||
|
||||
loop {
|
||||
let Ok((len, peer_ip)) = socket_recv(&socket, data) else {
|
||||
continue;
|
||||
let (len, peer_ip) = match socket_recv(&socket, data) {
|
||||
Ok((len, peer_ip)) => (len, peer_ip),
|
||||
Err(e) => {
|
||||
tracing::error!("recv icmp packet failed: {:?}", e);
|
||||
if sender.is_closed() {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if len <= 0 {
|
||||
tracing::error!("recv empty packet, len: {}", len);
|
||||
return;
|
||||
}
|
||||
|
||||
if !peer_ip.is_ipv4() {
|
||||
continue;
|
||||
}
|
||||
@@ -114,7 +141,7 @@ fn socket_recv_loop(socket: Socket, nat_table: IcmpNatTable, sender: UnboundedSe
|
||||
}
|
||||
|
||||
let key = IcmpNatKey {
|
||||
dst_ip: peer_ip,
|
||||
real_dst_ip: peer_ip,
|
||||
icmp_id: icmp_packet.get_identifier(),
|
||||
icmp_seq: icmp_packet.get_sequence_number(),
|
||||
};
|
||||
@@ -128,12 +155,11 @@ fn socket_recv_loop(socket: Socket, nat_table: IcmpNatTable, sender: UnboundedSe
|
||||
continue;
|
||||
};
|
||||
|
||||
let src_v4 = ipv4_packet.get_source();
|
||||
let payload_len = len - ipv4_packet.get_header_length() as usize * 4;
|
||||
let id = ipv4_packet.get_identification();
|
||||
let _ = compose_ipv4_packet(
|
||||
&mut buf[..],
|
||||
&src_v4,
|
||||
&v.mapped_dst_ip,
|
||||
&dest_ip,
|
||||
IpNextHeaderProtocols::Icmp,
|
||||
payload_len,
|
||||
@@ -176,7 +202,7 @@ impl IcmpProxy {
|
||||
let cidr_set = CidrSet::new(global_ctx.clone());
|
||||
let ret = Self {
|
||||
global_ctx,
|
||||
peer_manager,
|
||||
peer_manager: Arc::downgrade(&peer_manager),
|
||||
cidr_set,
|
||||
socket: std::sync::Mutex::new(None),
|
||||
|
||||
@@ -208,7 +234,7 @@ impl IcmpProxy {
|
||||
let socket = self.create_raw_socket();
|
||||
match socket {
|
||||
Ok(socket) => {
|
||||
self.socket.lock().unwrap().replace(socket);
|
||||
self.socket.lock().unwrap().replace(Arc::new(socket));
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!("create icmp socket failed: {:?}", e);
|
||||
@@ -241,7 +267,7 @@ impl IcmpProxy {
|
||||
let (sender, mut receiver) = tokio::sync::mpsc::unbounded_channel();
|
||||
self.icmp_sender.lock().unwrap().replace(sender.clone());
|
||||
if let Some(socket) = self.socket.lock().unwrap().as_ref() {
|
||||
let socket = socket.try_clone()?;
|
||||
let socket = socket.clone();
|
||||
let nat_table = self.nat_table.clone();
|
||||
thread::spawn(|| {
|
||||
socket_recv_loop(socket, nat_table, sender);
|
||||
@@ -254,7 +280,11 @@ impl IcmpProxy {
|
||||
while let Some(msg) = receiver.recv().await {
|
||||
let hdr = msg.peer_manager_header().unwrap();
|
||||
let to_peer_id = hdr.to_peer_id.into();
|
||||
let ret = peer_manager.send_msg(msg, to_peer_id).await;
|
||||
let Some(pm) = peer_manager.upgrade() else {
|
||||
tracing::warn!("peer manager is gone, icmp proxy send loop exit");
|
||||
return;
|
||||
};
|
||||
let ret = pm.send_msg(msg, to_peer_id).await;
|
||||
if ret.is_err() {
|
||||
tracing::error!("send icmp packet to peer failed: {:?}", ret);
|
||||
}
|
||||
@@ -271,9 +301,12 @@ impl IcmpProxy {
|
||||
}
|
||||
});
|
||||
|
||||
self.peer_manager
|
||||
.add_packet_process_pipeline(Box::new(self.clone()))
|
||||
.await;
|
||||
let Some(pm) = self.peer_manager.upgrade() else {
|
||||
tracing::warn!("peer manager is gone, icmp proxy init failed");
|
||||
return Err(anyhow::anyhow!("peer manager is gone").into());
|
||||
};
|
||||
|
||||
pm.add_packet_process_pipeline(Box::new(self.clone())).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -361,7 +394,11 @@ impl IcmpProxy {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !self.cidr_set.contains_v4(ipv4.get_destination())
|
||||
let mut real_dst_ip = ipv4.get_destination();
|
||||
|
||||
if !self
|
||||
.cidr_set
|
||||
.contains_v4(ipv4.get_destination(), &mut real_dst_ip)
|
||||
&& !is_exit_node
|
||||
&& !(self.global_ctx.no_tun()
|
||||
&& Some(ipv4.get_destination())
|
||||
@@ -416,7 +453,7 @@ impl IcmpProxy {
|
||||
let icmp_seq = icmp_packet.get_sequence_number();
|
||||
|
||||
let key = IcmpNatKey {
|
||||
dst_ip: ipv4.get_destination().into(),
|
||||
real_dst_ip: real_dst_ip.into(),
|
||||
icmp_id,
|
||||
icmp_seq,
|
||||
};
|
||||
@@ -425,6 +462,7 @@ impl IcmpProxy {
|
||||
hdr.from_peer_id.into(),
|
||||
hdr.to_peer_id.into(),
|
||||
ipv4.get_source().into(),
|
||||
ipv4.get_destination(),
|
||||
)
|
||||
.ok()?;
|
||||
|
||||
@@ -432,10 +470,24 @@ impl IcmpProxy {
|
||||
tracing::info!("icmp nat table entry replaced: {:?}", old);
|
||||
}
|
||||
|
||||
if let Err(e) = self.send_icmp_packet(ipv4.get_destination(), &icmp_packet) {
|
||||
if let Err(e) = self.send_icmp_packet(real_dst_ip, &icmp_packet) {
|
||||
tracing::error!("send icmp packet failed: {:?}", e);
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for IcmpProxy {
|
||||
fn drop(&mut self) {
|
||||
tracing::info!(
|
||||
"dropping icmp proxy, {:?}",
|
||||
self.socket.lock().unwrap().as_ref()
|
||||
);
|
||||
self.socket.lock().unwrap().as_ref().and_then(|s| {
|
||||
tracing::info!("shutting down icmp socket");
|
||||
let _ = s.shutdown(std::net::Shutdown::Both);
|
||||
Some(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ async fn handle_kcp_output(
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NatDstKcpConnector {
|
||||
pub(crate) kcp_endpoint: Arc<KcpEndpoint>,
|
||||
pub(crate) peer_mgr: Arc<PeerManager>,
|
||||
pub(crate) peer_mgr: Weak<PeerManager>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -120,10 +120,14 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
dst: Some(nat_dst.into()),
|
||||
};
|
||||
|
||||
let Some(peer_mgr) = self.peer_mgr.upgrade() else {
|
||||
return Err(anyhow::anyhow!("peer manager is not available").into());
|
||||
};
|
||||
|
||||
let (dst_peers, _) = match nat_dst {
|
||||
SocketAddr::V4(addr) => {
|
||||
let ip = addr.ip();
|
||||
self.peer_mgr.get_msg_dst_peer(&ip).await
|
||||
peer_mgr.get_msg_dst_peer(&ip).await
|
||||
}
|
||||
SocketAddr::V6(_) => return Err(anyhow::anyhow!("ipv6 is not supported").into()),
|
||||
};
|
||||
@@ -162,7 +166,7 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
retry_remain -= 1;
|
||||
|
||||
let kcp_endpoint = self.kcp_endpoint.clone();
|
||||
let peer_mgr = self.peer_mgr.clone();
|
||||
let my_peer_id = peer_mgr.my_peer_id();
|
||||
let dst_peer = dst_peers[0];
|
||||
let conn_data_clone = conn_data.clone();
|
||||
|
||||
@@ -170,7 +174,7 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
kcp_endpoint
|
||||
.connect(
|
||||
Duration::from_secs(10),
|
||||
peer_mgr.my_peer_id(),
|
||||
my_peer_id,
|
||||
dst_peer,
|
||||
Bytes::from(conn_data_clone.encode_to_vec()),
|
||||
)
|
||||
@@ -194,6 +198,7 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
_global_ctx: &GlobalCtx,
|
||||
hdr: &PeerManagerHeader,
|
||||
_ipv4: &Ipv4Packet,
|
||||
_real_dst_ip: &mut Ipv4Addr,
|
||||
) -> bool {
|
||||
return hdr.from_peer_id == hdr.to_peer_id;
|
||||
}
|
||||
@@ -301,7 +306,7 @@ impl KcpProxySrc {
|
||||
peer_manager.clone(),
|
||||
NatDstKcpConnector {
|
||||
kcp_endpoint: kcp_endpoint.clone(),
|
||||
peer_mgr: peer_manager.clone(),
|
||||
peer_mgr: Arc::downgrade(&peer_manager),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -342,6 +347,7 @@ pub struct KcpProxyDst {
|
||||
kcp_endpoint: Arc<KcpEndpoint>,
|
||||
peer_manager: Arc<PeerManager>,
|
||||
proxy_entries: Arc<DashMap<ConnId, TcpProxyEntry>>,
|
||||
cidr_set: Arc<CidrSet>,
|
||||
tasks: JoinSet<()>,
|
||||
}
|
||||
|
||||
@@ -357,11 +363,12 @@ impl KcpProxyDst {
|
||||
output_receiver,
|
||||
false,
|
||||
));
|
||||
|
||||
let cidr_set = CidrSet::new(peer_manager.get_global_ctx());
|
||||
Self {
|
||||
kcp_endpoint: Arc::new(kcp_endpoint),
|
||||
peer_manager,
|
||||
proxy_entries: Arc::new(DashMap::new()),
|
||||
cidr_set: Arc::new(cidr_set),
|
||||
tasks,
|
||||
}
|
||||
}
|
||||
@@ -371,6 +378,7 @@ impl KcpProxyDst {
|
||||
mut kcp_stream: KcpStream,
|
||||
global_ctx: ArcGlobalCtx,
|
||||
proxy_entries: Arc<DashMap<ConnId, TcpProxyEntry>>,
|
||||
cidr_set: Arc<CidrSet>,
|
||||
) -> Result<()> {
|
||||
let mut conn_data = kcp_stream.conn_data().clone();
|
||||
let parsed_conn_data = KcpConnData::decode(&mut conn_data)
|
||||
@@ -383,6 +391,16 @@ impl KcpProxyDst {
|
||||
))?
|
||||
.into();
|
||||
|
||||
match dst_socket.ip() {
|
||||
IpAddr::V4(dst_v4_ip) => {
|
||||
let mut real_ip = dst_v4_ip;
|
||||
if cidr_set.contains_v4(dst_v4_ip, &mut real_ip) {
|
||||
dst_socket.set_ip(real_ip.into());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let conn_id = kcp_stream.conn_id();
|
||||
proxy_entries.insert(
|
||||
conn_id,
|
||||
@@ -424,6 +442,7 @@ impl KcpProxyDst {
|
||||
let kcp_endpoint = self.kcp_endpoint.clone();
|
||||
let global_ctx = self.peer_manager.get_global_ctx().clone();
|
||||
let proxy_entries = self.proxy_entries.clone();
|
||||
let cidr_set = self.cidr_set.clone();
|
||||
self.tasks.spawn(async move {
|
||||
while let Ok(conn) = kcp_endpoint.accept().await {
|
||||
let stream = KcpStream::new(&kcp_endpoint, conn)
|
||||
@@ -432,8 +451,10 @@ impl KcpProxyDst {
|
||||
|
||||
let global_ctx = global_ctx.clone();
|
||||
let proxy_entries = proxy_entries.clone();
|
||||
let cidr_set = cidr_set.clone();
|
||||
tokio::spawn(async move {
|
||||
let _ = Self::handle_one_in_stream(stream, global_ctx, proxy_entries).await;
|
||||
let _ = Self::handle_one_in_stream(stream, global_ctx, proxy_entries, cidr_set)
|
||||
.await;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use dashmap::DashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
@@ -20,8 +21,10 @@ pub mod kcp_proxy;
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CidrSet {
|
||||
global_ctx: ArcGlobalCtx,
|
||||
cidr_set: Arc<Mutex<Vec<cidr::IpCidr>>>,
|
||||
cidr_set: Arc<Mutex<Vec<cidr::Ipv4Cidr>>>,
|
||||
tasks: JoinSet<()>,
|
||||
|
||||
mapped_to_real: Arc<DashMap<cidr::Ipv4Cidr, cidr::Ipv4Cidr>>,
|
||||
}
|
||||
|
||||
impl CidrSet {
|
||||
@@ -30,6 +33,8 @@ impl CidrSet {
|
||||
global_ctx,
|
||||
cidr_set: Arc::new(Mutex::new(vec![])),
|
||||
tasks: JoinSet::new(),
|
||||
|
||||
mapped_to_real: Arc::new(DashMap::new()),
|
||||
};
|
||||
ret.run_cidr_updater();
|
||||
ret
|
||||
@@ -38,15 +43,23 @@ impl CidrSet {
|
||||
fn run_cidr_updater(&mut self) {
|
||||
let global_ctx = self.global_ctx.clone();
|
||||
let cidr_set = self.cidr_set.clone();
|
||||
let mapped_to_real = self.mapped_to_real.clone();
|
||||
self.tasks.spawn(async move {
|
||||
let mut last_cidrs = vec![];
|
||||
loop {
|
||||
let cidrs = global_ctx.get_proxy_cidrs();
|
||||
let cidrs = global_ctx.config.get_proxy_cidrs();
|
||||
if cidrs != last_cidrs {
|
||||
last_cidrs = cidrs.clone();
|
||||
mapped_to_real.clear();
|
||||
cidr_set.lock().unwrap().clear();
|
||||
for cidr in cidrs.iter() {
|
||||
cidr_set.lock().unwrap().push(cidr.clone());
|
||||
let real_cidr = cidr.cidr;
|
||||
let mapped = cidr.mapped_cidr.unwrap_or(real_cidr.clone());
|
||||
cidr_set.lock().unwrap().push(mapped.clone());
|
||||
|
||||
if mapped != real_cidr {
|
||||
mapped_to_real.insert(mapped.clone(), real_cidr.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
@@ -54,11 +67,23 @@ impl CidrSet {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn contains_v4(&self, ip: std::net::Ipv4Addr) -> bool {
|
||||
let ip = ip.into();
|
||||
pub fn contains_v4(&self, ipv4: std::net::Ipv4Addr, real_ip: &mut std::net::Ipv4Addr) -> bool {
|
||||
let ip = ipv4.into();
|
||||
let s = self.cidr_set.lock().unwrap();
|
||||
for cidr in s.iter() {
|
||||
if cidr.contains(&ip) {
|
||||
if let Some(real_cidr) = self.mapped_to_real.get(&cidr).map(|v| v.value().clone()) {
|
||||
let origin_network_bits = real_cidr.first().address().to_bits();
|
||||
let network_mask = cidr.mask().to_bits();
|
||||
|
||||
let mut converted_ip = ipv4.to_bits();
|
||||
converted_ip &= !network_mask;
|
||||
converted_ip |= origin_network_bits;
|
||||
|
||||
*real_ip = std::net::Ipv4Addr::from(converted_ip);
|
||||
} else {
|
||||
*real_ip = ipv4;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,12 +237,9 @@ impl AsyncTcpConnector for Socks5KcpConnector {
|
||||
let Some(kcp_endpoint) = self.kcp_endpoint.upgrade() else {
|
||||
return Err(anyhow::anyhow!("kcp endpoint is not ready").into());
|
||||
};
|
||||
let Some(peer_mgr) = self.peer_mgr.upgrade() else {
|
||||
return Err(anyhow::anyhow!("peer mgr is not ready").into());
|
||||
};
|
||||
let c = NatDstKcpConnector {
|
||||
kcp_endpoint,
|
||||
peer_mgr,
|
||||
peer_mgr: self.peer_mgr.clone(),
|
||||
};
|
||||
println!("connect to kcp endpoint, addr = {:?}", addr);
|
||||
let ret = c
|
||||
|
||||
@@ -52,6 +52,7 @@ pub(crate) trait NatDstConnector: Send + Sync + Clone + 'static {
|
||||
global_ctx: &GlobalCtx,
|
||||
hdr: &PeerManagerHeader,
|
||||
ipv4: &Ipv4Packet,
|
||||
real_dst_ip: &mut Ipv4Addr,
|
||||
) -> bool;
|
||||
fn transport_type(&self) -> TcpProxyEntryTransportType;
|
||||
}
|
||||
@@ -99,10 +100,11 @@ impl NatDstConnector for NatDstTcpConnector {
|
||||
global_ctx: &GlobalCtx,
|
||||
hdr: &PeerManagerHeader,
|
||||
ipv4: &Ipv4Packet,
|
||||
real_dst_ip: &mut Ipv4Addr,
|
||||
) -> bool {
|
||||
let is_exit_node = hdr.is_exit_node();
|
||||
|
||||
if !cidr_set.contains_v4(ipv4.get_destination())
|
||||
if !cidr_set.contains_v4(ipv4.get_destination(), real_dst_ip)
|
||||
&& !is_exit_node
|
||||
&& !(global_ctx.no_tun()
|
||||
&& Some(ipv4.get_destination())
|
||||
@@ -125,7 +127,8 @@ type NatDstEntryState = TcpProxyEntryState;
|
||||
pub struct NatDstEntry {
|
||||
id: uuid::Uuid,
|
||||
src: SocketAddr,
|
||||
dst: SocketAddr,
|
||||
real_dst: SocketAddr,
|
||||
mapped_dst: SocketAddr,
|
||||
start_time: Instant,
|
||||
start_time_local: chrono::DateTime<chrono::Local>,
|
||||
tasks: Mutex<JoinSet<()>>,
|
||||
@@ -133,11 +136,12 @@ pub struct NatDstEntry {
|
||||
}
|
||||
|
||||
impl NatDstEntry {
|
||||
pub fn new(src: SocketAddr, dst: SocketAddr) -> Self {
|
||||
pub fn new(src: SocketAddr, real_dst: SocketAddr, mapped_dst: SocketAddr) -> Self {
|
||||
Self {
|
||||
id: uuid::Uuid::new_v4(),
|
||||
src,
|
||||
dst,
|
||||
real_dst,
|
||||
mapped_dst,
|
||||
start_time: Instant::now(),
|
||||
start_time_local: chrono::Local::now(),
|
||||
tasks: Mutex::new(JoinSet::new()),
|
||||
@@ -148,7 +152,7 @@ impl NatDstEntry {
|
||||
fn into_pb(&self, transport_type: TcpProxyEntryTransportType) -> TcpProxyEntry {
|
||||
TcpProxyEntry {
|
||||
src: Some(self.src.clone().into()),
|
||||
dst: Some(self.dst.clone().into()),
|
||||
dst: Some(self.real_dst.clone().into()),
|
||||
start_time: self.start_time_local.timestamp() as u64,
|
||||
state: self.state.load().into(),
|
||||
transport_type: transport_type.into(),
|
||||
@@ -396,7 +400,7 @@ impl<C: NatDstConnector> NicPacketFilter for TcpProxy<C> {
|
||||
drop(entry);
|
||||
assert_eq!(nat_entry.src, dst_addr);
|
||||
|
||||
let IpAddr::V4(ip) = nat_entry.dst.ip() else {
|
||||
let IpAddr::V4(ip) = nat_entry.mapped_dst.ip() else {
|
||||
panic!("v4 nat entry src ip is not v4");
|
||||
};
|
||||
|
||||
@@ -416,7 +420,7 @@ impl<C: NatDstConnector> NicPacketFilter for TcpProxy<C> {
|
||||
let dst = ip_packet.get_destination();
|
||||
|
||||
let mut tcp_packet = MutableTcpPacket::new(ip_packet.payload_mut()).unwrap();
|
||||
tcp_packet.set_source(nat_entry.dst.port());
|
||||
tcp_packet.set_source(nat_entry.real_dst.port());
|
||||
|
||||
Self::update_tcp_packet_checksum(&mut tcp_packet, &ip, &dst);
|
||||
drop(tcp_packet);
|
||||
@@ -537,7 +541,6 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
}
|
||||
}
|
||||
tracing::error!("smoltcp stack sink exited");
|
||||
panic!("smoltcp stack sink exited");
|
||||
});
|
||||
|
||||
let peer_mgr = self.peer_manager.clone();
|
||||
@@ -559,7 +562,6 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
}
|
||||
}
|
||||
tracing::error!("smoltcp stack stream exited");
|
||||
panic!("smoltcp stack stream exited");
|
||||
});
|
||||
|
||||
let interface_config = smoltcp::iface::Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||
@@ -607,7 +609,7 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
let mut tcp_listener = self.get_proxy_listener().await?;
|
||||
|
||||
let global_ctx = self.global_ctx.clone();
|
||||
let tasks = self.tasks.clone();
|
||||
let tasks = Arc::downgrade(&self.tasks);
|
||||
let syn_map = self.syn_map.clone();
|
||||
let conn_map = self.conn_map.clone();
|
||||
let addr_conn_map = self.addr_conn_map.clone();
|
||||
@@ -644,7 +646,7 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
tracing::info!(
|
||||
?socket_addr,
|
||||
"tcp connection accepted for proxy, nat dst: {:?}",
|
||||
entry.dst
|
||||
entry.real_dst
|
||||
);
|
||||
assert_eq!(entry.state.load(), NatDstEntryState::SynReceived);
|
||||
|
||||
@@ -658,6 +660,11 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
let old_nat_val = conn_map.insert(entry_clone.id, entry_clone.clone());
|
||||
assert!(old_nat_val.is_none());
|
||||
|
||||
let Some(tasks) = tasks.upgrade() else {
|
||||
tracing::error!("tcp proxy tasks is dropped, exit accept loop");
|
||||
break;
|
||||
};
|
||||
|
||||
tasks.lock().unwrap().spawn(Self::connect_to_nat_dst(
|
||||
connector.clone(),
|
||||
global_ctx.clone(),
|
||||
@@ -697,14 +704,14 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
tracing::warn!("set_nodelay failed, ignore it: {:?}", e);
|
||||
}
|
||||
|
||||
let nat_dst = if Some(nat_entry.dst.ip())
|
||||
let nat_dst = if Some(nat_entry.real_dst.ip())
|
||||
== global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address()))
|
||||
{
|
||||
format!("127.0.0.1:{}", nat_entry.dst.port())
|
||||
format!("127.0.0.1:{}", nat_entry.real_dst.port())
|
||||
.parse()
|
||||
.unwrap()
|
||||
} else {
|
||||
nat_entry.dst
|
||||
nat_entry.real_dst
|
||||
};
|
||||
|
||||
let _guard = global_ctx.net_ns.guard();
|
||||
@@ -818,10 +825,15 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !self
|
||||
.connector
|
||||
.check_packet_from_peer(&self.cidr_set, &self.global_ctx, &hdr, &ipv4)
|
||||
{
|
||||
let mut real_dst_ip = ipv4.get_destination();
|
||||
|
||||
if !self.connector.check_packet_from_peer(
|
||||
&self.cidr_set,
|
||||
&self.global_ctx,
|
||||
&hdr,
|
||||
&ipv4,
|
||||
&mut real_dst_ip,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -839,12 +851,13 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
if is_tcp_syn && !is_tcp_ack {
|
||||
let dest_ip = ip_packet.get_destination();
|
||||
let dest_port = tcp_packet.get_destination();
|
||||
let dst = SocketAddr::V4(SocketAddrV4::new(dest_ip, dest_port));
|
||||
let mapped_dst = SocketAddr::V4(SocketAddrV4::new(dest_ip, dest_port));
|
||||
let real_dst = SocketAddr::V4(SocketAddrV4::new(real_dst_ip, dest_port));
|
||||
|
||||
let old_val = self
|
||||
.syn_map
|
||||
.insert(src, Arc::new(NatDstEntry::new(src, dst)));
|
||||
tracing::info!(src = ?src, dst = ?dst, old_entry = ?old_val, "tcp syn received");
|
||||
.insert(src, Arc::new(NatDstEntry::new(src, real_dst, mapped_dst)));
|
||||
tracing::info!(src = ?src, ?real_dst, ?mapped_dst, old_entry = ?old_val, "tcp syn received");
|
||||
} else if !self.addr_conn_map.contains_key(&src) && !self.syn_map.contains_key(&src) {
|
||||
// if not in syn map and addr conn map, may forwarding n2n packet
|
||||
return None;
|
||||
|
||||
@@ -139,6 +139,8 @@ impl UdpNatEntry {
|
||||
self: Arc<Self>,
|
||||
mut packet_sender: Sender<ZCPacket>,
|
||||
virtual_ipv4: Ipv4Addr,
|
||||
real_ipv4: Ipv4Addr,
|
||||
mapped_ipv4: Ipv4Addr,
|
||||
) {
|
||||
let (s, mut r) = tachyonix::channel(128);
|
||||
|
||||
@@ -197,6 +199,10 @@ impl UdpNatEntry {
|
||||
src_v4.set_ip(virtual_ipv4);
|
||||
}
|
||||
|
||||
if *src_v4.ip() == real_ipv4 {
|
||||
src_v4.set_ip(mapped_ipv4);
|
||||
}
|
||||
|
||||
let Ok(_) = Self::compose_ipv4_packet(
|
||||
&self_clone,
|
||||
&mut packet_sender,
|
||||
@@ -266,7 +272,10 @@ impl UdpProxy {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !self.cidr_set.contains_v4(ipv4.get_destination())
|
||||
let mut real_dst_ip = ipv4.get_destination();
|
||||
if !self
|
||||
.cidr_set
|
||||
.contains_v4(ipv4.get_destination(), &mut real_dst_ip)
|
||||
&& !is_exit_node
|
||||
&& !(self.global_ctx.no_tun()
|
||||
&& Some(ipv4.get_destination())
|
||||
@@ -322,6 +331,8 @@ impl UdpProxy {
|
||||
nat_entry.clone(),
|
||||
self.sender.clone(),
|
||||
self.global_ctx.get_ipv4().map(|x| x.address())?,
|
||||
real_dst_ip,
|
||||
ipv4.get_destination(),
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -335,7 +346,7 @@ impl UdpProxy {
|
||||
.parse()
|
||||
.unwrap()
|
||||
} else {
|
||||
SocketAddr::new(ipv4.get_destination().into(), udp_packet.get_destination())
|
||||
SocketAddr::new(real_dst_ip.into(), udp_packet.get_destination())
|
||||
};
|
||||
|
||||
let send_ret = {
|
||||
|
||||
Reference in New Issue
Block a user