mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 10:14:35 +00:00
fix peer establish direct conn with subnet proxy to one of local interface (#1782)
* fix peer establish direct conn with subnet proxy to one of local interface * fix peer mgr ref loop
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::net::IpAddr;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::{
|
||||
hash::Hasher,
|
||||
sync::{Arc, Mutex},
|
||||
@@ -257,6 +257,13 @@ impl GlobalCtx {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ip_local_virtual_ip(&self, ip: &IpAddr) -> bool {
|
||||
match ip {
|
||||
IpAddr::V4(v4) => self.get_ipv4().map(|x| x.address() == *v4).unwrap_or(false),
|
||||
IpAddr::V6(v6) => self.get_ipv6().map(|x| x.address() == *v6).unwrap_or(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_network_identity(&self) -> NetworkIdentity {
|
||||
self.config.get_network_identity()
|
||||
}
|
||||
@@ -303,18 +310,6 @@ impl GlobalCtx {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_port_in_running_listeners(&self, port: u16, is_udp: bool) -> bool {
|
||||
let check_proto = |listener_proto: &str| {
|
||||
let listener_is_udp = matches!(listener_proto, "udp" | "wg");
|
||||
listener_is_udp == is_udp
|
||||
};
|
||||
self.running_listeners
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|x| x.port() == Some(port) && check_proto(x.scheme()))
|
||||
}
|
||||
|
||||
pub fn get_vpn_portal_cidr(&self) -> Option<cidr::Ipv4Cidr> {
|
||||
self.config.get_vpn_portal_config().map(|x| x.client_cidr)
|
||||
}
|
||||
@@ -447,6 +442,46 @@ impl GlobalCtx {
|
||||
// NOTICE: p2p only is conflict with latency first
|
||||
self.config.get_flags().latency_first && !self.p2p_only
|
||||
}
|
||||
|
||||
fn is_port_in_running_listeners(&self, port: u16, is_udp: bool) -> bool {
|
||||
let check_proto = |listener_proto: &str| {
|
||||
let listener_is_udp = matches!(listener_proto, "udp" | "wg");
|
||||
listener_is_udp == is_udp
|
||||
};
|
||||
self.running_listeners
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|x| x.port() == Some(port) && check_proto(x.scheme()))
|
||||
}
|
||||
|
||||
#[tracing::instrument(ret, skip(self))]
|
||||
pub fn should_deny_proxy(&self, dst_addr: &SocketAddr, is_udp: bool) -> bool {
|
||||
let _g = self.net_ns.guard();
|
||||
let ip = dst_addr.ip();
|
||||
// first check if ip is virtual ip
|
||||
// then try bind this ip, if succ means it is local ip
|
||||
let dst_is_local_virtual_ip = self.is_ip_local_virtual_ip(&ip);
|
||||
// this is an expensive operation, should be called sparingly
|
||||
// 1. tcp/kcp/quic call this only after proxy conn is established
|
||||
// 2. udp cache the result in nat entry
|
||||
let dst_is_local_phy_ip = std::net::UdpSocket::bind(format!("{}:0", ip)).is_ok();
|
||||
|
||||
tracing::trace!(
|
||||
"check should_deny_proxy: dst_addr={}, dst_is_local_virtual_ip={}, dst_is_local_phy_ip={}, is_udp={}",
|
||||
dst_addr,
|
||||
dst_is_local_virtual_ip,
|
||||
dst_is_local_phy_ip,
|
||||
is_udp
|
||||
);
|
||||
|
||||
if dst_is_local_virtual_ip || dst_is_local_phy_ip {
|
||||
// if is local ip, make sure the port is not one of the listening ports
|
||||
self.is_port_in_running_listeners(dst_addr.port(), is_udp)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -74,7 +74,7 @@ impl NetNSGuard {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct NetNS {
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
@@ -1321,7 +1321,10 @@ impl StunInfoCollectorTrait for MockStunInfoCollector {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tunnel::{udp::UdpTunnelListener, TunnelListener};
|
||||
use crate::{
|
||||
common::scoped_task::ScopedTask,
|
||||
tunnel::{udp::UdpTunnelListener, TunnelListener},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -1406,11 +1409,11 @@ mod tests {
|
||||
use stun_codec::rfc5389::attributes::XorMappedAddress;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
async fn spawn_tcp_stun_server() -> SocketAddr {
|
||||
async fn spawn_tcp_stun_server() -> (SocketAddr, ScopedTask<()>) {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let server_addr = listener.local_addr().unwrap();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let task = tokio::spawn(async move {
|
||||
let (mut stream, peer_addr) = listener.accept().await.unwrap();
|
||||
|
||||
let req = TcpStunClient::tcp_read_stun_message(&mut stream, Duration::from_secs(2))
|
||||
@@ -1430,11 +1433,11 @@ mod tests {
|
||||
stream.write_all(rsp_buf.as_slice()).await.unwrap();
|
||||
});
|
||||
|
||||
server_addr
|
||||
(server_addr, task.into())
|
||||
}
|
||||
|
||||
let server1 = spawn_tcp_stun_server().await;
|
||||
let server2 = spawn_tcp_stun_server().await;
|
||||
let (server1, _t1) = spawn_tcp_stun_server().await;
|
||||
let (server2, _t2) = spawn_tcp_stun_server().await;
|
||||
|
||||
let stun_servers = vec![server1.to_string(), server2.to_string()];
|
||||
let detector = TcpNatTypeDetector::new(stun_servers, 1);
|
||||
@@ -1469,7 +1472,7 @@ mod tests {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let server_addr = listener.local_addr().unwrap();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let _t = ScopedTask::from(tokio::spawn(async move {
|
||||
for _ in 0..8 {
|
||||
let Ok((mut stream, peer_addr)) = listener.accept().await else {
|
||||
break;
|
||||
@@ -1491,7 +1494,7 @@ mod tests {
|
||||
let rsp_buf = encoder.encode_into_bytes(resp_msg).unwrap();
|
||||
stream.write_all(rsp_buf.as_slice()).await.unwrap();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
let collector = StunInfoCollector::new(vec![], vec![server_addr.to_string()], vec![]);
|
||||
collector.set_tcp_stun_servers(vec![server_addr.to_string()]);
|
||||
|
||||
Reference in New Issue
Block a user