fix packet split on udp tunnel and avoid tcp proxy access rpc portal (#2107)

* distinct control / data when forward packets
* fix rpc split for udp tunnel
* feat(easytier-web): pass public ip in validate token webhook
* protect rpc port from subnet proxy
This commit is contained in:
KKRainbow
2026-04-13 11:03:09 +08:00
committed by GitHub
parent ec7ddd3bad
commit 5b35c51da9
11 changed files with 602 additions and 79 deletions
+14 -4
View File
@@ -27,8 +27,8 @@ use crate::{
instance_manage::InstanceManageRpcService, logger::LoggerRpcService,
mapped_listener_manage::MappedListenerManageRpcService,
peer_center::PeerCenterManageRpcService, peer_manage::PeerManageRpcService,
port_forward_manage::PortForwardManageRpcService, proxy::TcpProxyRpcService,
stats::StatsRpcService, vpn_portal::VpnPortalRpcService,
port_forward_manage::PortForwardManageRpcService, protected_port,
proxy::TcpProxyRpcService, stats::StatsRpcService, vpn_portal::VpnPortalRpcService,
},
tunnel::{TunnelListener, tcp::TcpTunnelListener},
web_client::{DefaultHooks, WebClientHooks},
@@ -36,6 +36,7 @@ use crate::{
pub struct ApiRpcServer<T: TunnelListener + 'static> {
rpc_server: StandAloneServer<T>,
protected_tcp_port: Option<u16>,
}
impl ApiRpcServer<TcpTunnelListener> {
@@ -44,14 +45,17 @@ impl ApiRpcServer<TcpTunnelListener> {
rpc_portal_whitelist: Option<Vec<IpCidr>>,
instance_manager: Arc<NetworkInstanceManager>,
) -> anyhow::Result<Self> {
let rpc_addr = parse_rpc_portal(rpc_portal)?;
let mut server = Self::from_tunnel(
TcpTunnelListener::new(
format!("tcp://{}", parse_rpc_portal(rpc_portal)?)
format!("tcp://{}", rpc_addr)
.parse()
.context("failed to parse rpc portal address")?,
),
instance_manager,
);
protected_port::register_protected_tcp_port(rpc_addr.port());
server.protected_tcp_port = Some(rpc_addr.port());
server
.rpc_server
@@ -65,7 +69,10 @@ impl<T: TunnelListener + 'static> ApiRpcServer<T> {
pub fn from_tunnel(tunnel: T, instance_manager: Arc<NetworkInstanceManager>) -> Self {
let rpc_server = StandAloneServer::new(tunnel);
register_api_rpc_service(&instance_manager, rpc_server.registry(), None);
Self { rpc_server }
Self {
rpc_server,
protected_tcp_port: None,
}
}
}
@@ -83,6 +90,9 @@ impl<T: TunnelListener + 'static> ApiRpcServer<T> {
impl<T: TunnelListener + 'static> Drop for ApiRpcServer<T> {
fn drop(&mut self) {
if let Some(port) = self.protected_tcp_port.take() {
protected_port::unregister_protected_tcp_port(port);
}
self.rpc_server.registry().unregister_all();
}
}
+1
View File
@@ -6,6 +6,7 @@ mod mapped_listener_manage;
mod peer_center;
mod peer_manage;
mod port_forward_manage;
pub(crate) mod protected_port;
mod proxy;
mod stats;
mod vpn_portal;
@@ -0,0 +1,61 @@
use std::collections::HashMap;
use std::sync::Mutex;
use once_cell::sync::Lazy;
static PROTECTED_TCP_PORTS: Lazy<Mutex<HashMap<u16, usize>>> =
Lazy::new(|| Mutex::new(HashMap::new()));
pub fn register_protected_tcp_port(port: u16) {
let mut ports = PROTECTED_TCP_PORTS.lock().unwrap();
*ports.entry(port).or_default() += 1;
}
pub fn unregister_protected_tcp_port(port: u16) {
let mut ports = PROTECTED_TCP_PORTS.lock().unwrap();
if let Some(ref_count) = ports.get_mut(&port) {
*ref_count -= 1;
if *ref_count == 0 {
ports.remove(&port);
}
}
}
pub fn is_protected_tcp_port(port: u16) -> bool {
PROTECTED_TCP_PORTS.lock().unwrap().contains_key(&port)
}
#[cfg(test)]
pub fn clear_protected_tcp_ports_for_test() {
PROTECTED_TCP_PORTS.lock().unwrap().clear();
}
#[cfg(test)]
mod tests {
use super::{
clear_protected_tcp_ports_for_test, is_protected_tcp_port, register_protected_tcp_port,
unregister_protected_tcp_port,
};
#[test]
fn protected_tcp_port_registry_is_ref_counted() {
clear_protected_tcp_ports_for_test();
register_protected_tcp_port(15888);
register_protected_tcp_port(15888);
assert!(is_protected_tcp_port(15888));
unregister_protected_tcp_port(15888);
assert!(is_protected_tcp_port(15888));
unregister_protected_tcp_port(15888);
assert!(!is_protected_tcp_port(15888));
}
#[test]
fn unregistering_unknown_port_is_a_noop() {
clear_protected_tcp_ports_for_test();
unregister_protected_tcp_port(15888);
assert!(!is_protected_tcp_port(15888));
}
}