mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 02:09:06 +00:00
allow loopback src address in listener (#1730)
This commit is contained in:
@@ -303,6 +303,18 @@ 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> {
|
pub fn get_vpn_portal_cidr(&self) -> Option<cidr::Ipv4Cidr> {
|
||||||
self.config.get_vpn_portal_config().map(|x| x.client_cidr)
|
self.config.get_vpn_portal_config().map(|x| x.client_cidr)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -507,6 +507,15 @@ impl KcpProxyDst {
|
|||||||
Some(dst_socket.ip()) == global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address()));
|
Some(dst_socket.ip()) == global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address()));
|
||||||
|
|
||||||
if send_to_self && global_ctx.no_tun() {
|
if send_to_self && global_ctx.no_tun() {
|
||||||
|
if global_ctx.is_port_in_running_listeners(dst_socket.port(), false)
|
||||||
|
&& global_ctx.is_ip_in_same_network(&src_ip)
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"dst socket {:?} is in running listeners, ignore it",
|
||||||
|
dst_socket
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
dst_socket = format!("127.0.0.1:{}", dst_socket.port()).parse().unwrap();
|
dst_socket = format!("127.0.0.1:{}", dst_socket.port()).parse().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -416,6 +416,15 @@ impl QUICProxyDst {
|
|||||||
|
|
||||||
let send_to_self = Some(*dst_socket.ip()) == ctx.get_ipv4().map(|ip| ip.address());
|
let send_to_self = Some(*dst_socket.ip()) == ctx.get_ipv4().map(|ip| ip.address());
|
||||||
if send_to_self && ctx.no_tun() {
|
if send_to_self && ctx.no_tun() {
|
||||||
|
if ctx.is_port_in_running_listeners(dst_socket.port(), false)
|
||||||
|
&& ctx.is_ip_in_same_network(&src_ip)
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"dst socket {:?} is in running listeners, ignore it",
|
||||||
|
dst_socket
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
dst_socket = format!("127.0.0.1:{}", dst_socket.port()).parse().unwrap();
|
dst_socket = format!("127.0.0.1:{}", dst_socket.port()).parse().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -733,6 +733,18 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
|||||||
let nat_dst = if Some(nat_entry.real_dst.ip())
|
let nat_dst = if Some(nat_entry.real_dst.ip())
|
||||||
== global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address()))
|
== global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address()))
|
||||||
{
|
{
|
||||||
|
if global_ctx.is_port_in_running_listeners(nat_entry.real_dst.port(), false)
|
||||||
|
&& global_ctx.is_ip_in_same_network(&nat_entry.src.ip())
|
||||||
|
{
|
||||||
|
tracing::error!(
|
||||||
|
?nat_entry,
|
||||||
|
"nat dst port {} is in running listeners, ignore it",
|
||||||
|
nat_entry.real_dst.port()
|
||||||
|
);
|
||||||
|
nat_entry.state.store(NatDstEntryState::Closed);
|
||||||
|
Self::remove_entry_from_all_conn_map(conn_map, addr_conn_map, nat_entry);
|
||||||
|
return;
|
||||||
|
}
|
||||||
format!("127.0.0.1:{}", nat_entry.real_dst.port())
|
format!("127.0.0.1:{}", nat_entry.real_dst.port())
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
@@ -298,6 +298,30 @@ impl UdpProxy {
|
|||||||
udp::UdpPacket::new(ipv4.payload())?
|
udp::UdpPacket::new(ipv4.payload())?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: should it be async.
|
||||||
|
let dst_socket = if Some(ipv4.get_destination())
|
||||||
|
== self.global_ctx.get_ipv4().as_ref().map(Ipv4Inet::address)
|
||||||
|
{
|
||||||
|
if self
|
||||||
|
.global_ctx
|
||||||
|
.is_port_in_running_listeners(udp_packet.get_destination(), true)
|
||||||
|
&& self
|
||||||
|
.global_ctx
|
||||||
|
.is_ip_in_same_network(&std::net::IpAddr::V4(ipv4.get_source()))
|
||||||
|
{
|
||||||
|
tracing::debug!(
|
||||||
|
dst_port = udp_packet.get_destination(),
|
||||||
|
"dst socket is in running listeners, ignore it"
|
||||||
|
);
|
||||||
|
return Some(());
|
||||||
|
}
|
||||||
|
format!("127.0.0.1:{}", udp_packet.get_destination())
|
||||||
|
.parse()
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
SocketAddr::new(real_dst_ip.into(), udp_packet.get_destination())
|
||||||
|
};
|
||||||
|
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
?packet,
|
?packet,
|
||||||
?ipv4,
|
?ipv4,
|
||||||
@@ -339,17 +363,6 @@ impl UdpProxy {
|
|||||||
|
|
||||||
nat_entry.mark_active();
|
nat_entry.mark_active();
|
||||||
|
|
||||||
// TODO: should it be async.
|
|
||||||
let dst_socket = if Some(ipv4.get_destination())
|
|
||||||
== self.global_ctx.get_ipv4().as_ref().map(Ipv4Inet::address)
|
|
||||||
{
|
|
||||||
format!("127.0.0.1:{}", udp_packet.get_destination())
|
|
||||||
.parse()
|
|
||||||
.unwrap()
|
|
||||||
} else {
|
|
||||||
SocketAddr::new(real_dst_ip.into(), udp_packet.get_destination())
|
|
||||||
};
|
|
||||||
|
|
||||||
let send_ret = {
|
let send_ret = {
|
||||||
let _g = self.global_ctx.net_ns.guard();
|
let _g = self.global_ctx.net_ns.guard();
|
||||||
nat_entry
|
nat_entry
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||||
sync::{atomic::AtomicBool, Arc, Weak},
|
sync::{atomic::AtomicBool, Arc, Weak},
|
||||||
time::{Instant, SystemTime},
|
time::{Instant, SystemTime},
|
||||||
};
|
};
|
||||||
@@ -416,47 +416,25 @@ impl PeerManager {
|
|||||||
if src.scheme() == "ring" {
|
if src.scheme() == "ring" {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let src_host = match src.socket_addrs(|| Some(1)) {
|
let Ok(Some(addr)) = src.socket_addrs(|| Some(1)).map(|x| x.first().cloned()) else {
|
||||||
Ok(addrs) => addrs,
|
|
||||||
Err(_) => {
|
|
||||||
// if the tunnel is not rely on ip address, skip check
|
// if the tunnel is not rely on ip address, skip check
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let virtual_ipv4 = self.global_ctx.get_ipv4().map(|ip| ip.network());
|
|
||||||
let virtual_ipv6 = self.global_ctx.get_ipv6().map(|ip| ip.network());
|
|
||||||
tracing::info!(
|
|
||||||
?virtual_ipv4,
|
|
||||||
?virtual_ipv6,
|
|
||||||
"check remote addr not from virtual network"
|
|
||||||
);
|
|
||||||
for addr in src_host {
|
|
||||||
// if no-tun is enabled, the src ip of packet in virtual network is converted to loopback address
|
// if no-tun is enabled, the src ip of packet in virtual network is converted to loopback address
|
||||||
if addr.ip().is_loopback()
|
// we already filter out the connection in tcp/quic/kcp proxy so no need check here.
|
||||||
&& !self
|
if addr.ip().is_loopback() {
|
||||||
.allow_loopback_tunnel
|
// allow other loopback address, good for conn from cdn/l4 connection
|
||||||
.load(std::sync::atomic::Ordering::Relaxed)
|
return Ok(());
|
||||||
{
|
|
||||||
anyhow::bail!("tunnel src host is loopback address");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match addr {
|
if self.global_ctx.is_ip_in_same_network(&addr.ip()) {
|
||||||
SocketAddr::V4(addr) => {
|
anyhow::bail!(
|
||||||
if let Some(virtual_ipv4) = virtual_ipv4 {
|
"tunnel src {} is from the same network (ignore this error please)",
|
||||||
if virtual_ipv4.contains(addr.ip()) {
|
addr
|
||||||
anyhow::bail!("tunnel src host is from the virtual network (ignore this error please)");
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SocketAddr::V6(addr) => {
|
|
||||||
if let Some(virtual_ipv6) = virtual_ipv6 {
|
|
||||||
if virtual_ipv6.contains(addr.ip()) {
|
|
||||||
anyhow::bail!("tunnel src host is from the virtual network (ignore this error please)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1481,9 +1481,23 @@ pub async fn relay_bps_limit_test(#[values(100, 200, 400, 800)] bps_limit: u64)
|
|||||||
drop_insts(insts).await;
|
drop_insts(insts).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest::rstest]
|
||||||
|
#[serial_test::serial]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn avoid_tunnel_loop_back_to_virtual_network() {
|
async fn avoid_tunnel_loop_back_to_virtual_network(#[values(true, false)] no_tun: bool) {
|
||||||
let insts = init_three_node("udp").await;
|
let insts = init_three_node_ex(
|
||||||
|
"udp",
|
||||||
|
|cfg| {
|
||||||
|
if matches!(cfg.get_inst_name().as_str(), "inst2" | "inst3") {
|
||||||
|
let mut flags = cfg.get_flags();
|
||||||
|
flags.no_tun = no_tun;
|
||||||
|
cfg.set_flags(flags);
|
||||||
|
}
|
||||||
|
cfg
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let tcp_connector = TcpTunnelConnector::new("tcp://10.144.144.2:11010".parse().unwrap());
|
let tcp_connector = TcpTunnelConnector::new("tcp://10.144.144.2:11010".parse().unwrap());
|
||||||
insts[0]
|
insts[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user