From 5b7384fddd914f572dc4cccd67a726123f1799c1 Mon Sep 17 00:00:00 2001 From: "Sijie.Sun" Date: Fri, 22 Aug 2025 23:33:21 +0800 Subject: [PATCH] disable nat4 hole punch (#1277) --- Cargo.lock | 2 +- .../frontend-lib/src/components/Config.vue | 1 + easytier-web/frontend-lib/src/locales/cn.yaml | 5 ++++- easytier-web/frontend-lib/src/locales/en.yaml | 5 ++++- .../frontend-lib/src/types/network.ts | 2 ++ easytier/locales/app.yml | 3 +++ easytier/src/common/config.rs | 1 + .../src/connector/udp_hole_punch/common.rs | 22 +++++++++++++++++-- easytier/src/connector/udp_hole_punch/mod.rs | 9 ++++++-- easytier/src/easytier-core.rs | 11 +++++++++- easytier/src/launcher.rs | 4 ++++ easytier/src/proto/common.proto | 3 +++ easytier/src/proto/web.proto | 2 ++ 13 files changed, 62 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d2857b..e54ed04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9244,7 +9244,7 @@ checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.7.7", "base64 0.22.1", "bytes", "h2", diff --git a/easytier-web/frontend-lib/src/components/Config.vue b/easytier-web/frontend-lib/src/components/Config.vue index 71c6b68..d84164e 100644 --- a/easytier-web/frontend-lib/src/components/Config.vue +++ b/easytier-web/frontend-lib/src/components/Config.vue @@ -165,6 +165,7 @@ const bool_flags: BoolFlag[] = [ { field: 'proxy_forward_by_system', help: 'proxy_forward_by_system_help' }, { field: 'disable_encryption', help: 'disable_encryption_help' }, { field: 'disable_udp_hole_punching', help: 'disable_udp_hole_punching_help' }, + { field: 'disable_sym_hole_punching', help: 'disable_sym_hole_punching_help' }, { field: 'enable_magic_dns', help: 'enable_magic_dns_help' }, { field: 'enable_private_mode', help: 'enable_private_mode_help' }, ] diff --git a/easytier-web/frontend-lib/src/locales/cn.yaml b/easytier-web/frontend-lib/src/locales/cn.yaml index ac8af2b..324ed58 100644 --- a/easytier-web/frontend-lib/src/locales/cn.yaml +++ b/easytier-web/frontend-lib/src/locales/cn.yaml @@ -127,6 +127,9 @@ disable_encryption_help: 禁用对等节点通信的加密,默认为false, disable_udp_hole_punching: 禁用UDP打洞 disable_udp_hole_punching_help: 禁用UDP打洞功能 +disable_sym_hole_punching: 禁用对称NAT打洞 +disable_sym_hole_punching_help: 禁用对称NAT的打洞(生日攻击),将对称NAT视为锥形NAT处理 + enable_magic_dns: 启用魔法DNS enable_magic_dns_help: | 启用魔法DNS,允许通过EasyTier的DNS服务器访问其他节点的虚拟IPv4地址, 如 node1.et.net。 @@ -324,4 +327,4 @@ web: confirm_password: 确认新密码 language: 语言 theme: 主题 - logout: 退出登录 \ No newline at end of file + logout: 退出登录 \ No newline at end of file diff --git a/easytier-web/frontend-lib/src/locales/en.yaml b/easytier-web/frontend-lib/src/locales/en.yaml index a887eb4..e3fbfa1 100644 --- a/easytier-web/frontend-lib/src/locales/en.yaml +++ b/easytier-web/frontend-lib/src/locales/en.yaml @@ -126,6 +126,9 @@ disable_encryption_help: Disable encryption for peers communication, default is disable_udp_hole_punching: Disable UDP Hole Punching disable_udp_hole_punching_help: Disable udp hole punching +disable_sym_hole_punching: Disable Symmetric NAT Hole Punching +disable_sym_hole_punching_help: Disable special hole punching handling for symmetric NAT (based on birthday attack), treat symmetric NAT as cone NAT + enable_magic_dns: Enable Magic DNS enable_magic_dns_help: | Enable magic dns, all nodes in the network can access each other by domain name, e.g.: node1.et.net. @@ -324,4 +327,4 @@ web: confirm_password: Confirm New Password language: Language theme: Theme - logout: Logout \ No newline at end of file + logout: Logout \ No newline at end of file diff --git a/easytier-web/frontend-lib/src/types/network.ts b/easytier-web/frontend-lib/src/types/network.ts index b6d1d44..95c8fb4 100644 --- a/easytier-web/frontend-lib/src/types/network.ts +++ b/easytier-web/frontend-lib/src/types/network.ts @@ -51,6 +51,7 @@ export interface NetworkConfig { proxy_forward_by_system?: boolean disable_encryption?: boolean disable_udp_hole_punching?: boolean + disable_sym_hole_punching?: boolean enable_relay_network_whitelist?: boolean relay_network_whitelist: string[] @@ -122,6 +123,7 @@ export function DEFAULT_NETWORK_CONFIG(): NetworkConfig { proxy_forward_by_system: false, disable_encryption: false, disable_udp_hole_punching: false, + disable_sym_hole_punching: false, enable_relay_network_whitelist: false, relay_network_whitelist: [], enable_manual_routes: false, diff --git a/easytier/locales/app.yml b/easytier/locales/app.yml index 67a0743..e7817ef 100644 --- a/easytier/locales/app.yml +++ b/easytier/locales/app.yml @@ -151,6 +151,9 @@ core_clap: disable_udp_hole_punching: en: "disable udp hole punching" zh-CN: "禁用UDP打洞功能" + disable_sym_hole_punching: + en: "if true, disable udp nat hole punching for symmetric nat (NAT4), which is based on birthday attack and may be blocked by ISP." + zh-CN: "如果为true,则禁用基于生日攻击的对称NAT (NAT4) UDP 打洞功能,该打洞方式可能会被运营商封锁" relay_all_peer_rpc: en: "relay all peer rpc packets, even if the peer is not in the relay network whitelist. this can help peers not in relay network whitelist to establish p2p connection." zh-CN: "转发所有对等节点的RPC数据包,即使对等节点不在转发网络白名单中。这可以帮助白名单外网络中的对等节点建立P2P连接。" diff --git a/easytier/src/common/config.rs b/easytier/src/common/config.rs index 364d672..2382c28 100644 --- a/easytier/src/common/config.rs +++ b/easytier/src/common/config.rs @@ -49,6 +49,7 @@ pub fn gen_default_flags() -> Flags { foreign_relay_bps_limit: u64::MAX, multi_thread_count: 2, encryption_algorithm: "aes-gcm".to_string(), + disable_sym_hole_punching: false, } } diff --git a/easytier/src/connector/udp_hole_punch/common.rs b/easytier/src/connector/udp_hole_punch/common.rs index 975a9fe..c469641 100644 --- a/easytier/src/connector/udp_hole_punch/common.rs +++ b/easytier/src/connector/udp_hole_punch/common.rs @@ -111,7 +111,24 @@ impl UdpNatType { } } - pub(crate) fn get_punch_hole_method(&self, other: Self) -> UdpPunchClientMethod { + pub(crate) fn get_punch_hole_method( + &self, + other: Self, + global_ctx: ArcGlobalCtx, + ) -> UdpPunchClientMethod { + // Check if symmetric NAT hole punching is disabled + let disable_sym_hole_punching = global_ctx.get_flags().disable_sym_hole_punching; + + // If symmetric NAT hole punching is disabled, treat symmetric as cone + if disable_sym_hole_punching && self.is_sym() { + // Convert symmetric to cone type for hole punching logic + if other.is_sym() { + return UdpPunchClientMethod::None; + } else { + return UdpPunchClientMethod::ConeToCone; + } + } + if other.is_unknown() { if self.is_sym() { return UdpPunchClientMethod::SymToCone; @@ -163,8 +180,9 @@ impl UdpNatType { other: Self, my_peer_id: PeerId, dst_peer_id: PeerId, + global_ctx: ArcGlobalCtx, ) -> bool { - match self.get_punch_hole_method(other) { + match self.get_punch_hole_method(other, global_ctx) { UdpPunchClientMethod::None => false, UdpPunchClientMethod::ConeToCone | UdpPunchClientMethod::SymToCone => true, UdpPunchClientMethod::EasySymToEasySym => my_peer_id < dst_peer_id, diff --git a/easytier/src/connector/udp_hole_punch/mod.rs b/easytier/src/connector/udp_hole_punch/mod.rs index d9fc36c..6d3ca9f 100644 --- a/easytier/src/connector/udp_hole_punch/mod.rs +++ b/easytier/src/connector/udp_hole_punch/mod.rs @@ -466,7 +466,9 @@ impl PeerTaskLauncher for UdpHolePunchPeerTaskLauncher { continue; } - if !my_nat_type.can_punch_hole_as_client(peer_nat_type, my_peer_id, peer_id) { + let global_ctx = data.peer_mgr.get_global_ctx(); + if !my_nat_type.can_punch_hole_as_client(peer_nat_type, my_peer_id, peer_id, global_ctx) + { continue; } @@ -493,7 +495,10 @@ impl PeerTaskLauncher for UdpHolePunchPeerTaskLauncher { item: Self::CollectPeerItem, ) -> JoinHandle> { let data = data.clone(); - let punch_method = item.my_nat_type.get_punch_hole_method(item.dst_nat_type); + let global_ctx = data.peer_mgr.get_global_ctx(); + let punch_method = item + .my_nat_type + .get_punch_hole_method(item.dst_nat_type, global_ctx); match punch_method { UdpPunchClientMethod::ConeToCone => tokio::spawn(data.cone_to_cone(item)), UdpPunchClientMethod::SymToCone => tokio::spawn(data.sym_to_cone(item)), diff --git a/easytier/src/easytier-core.rs b/easytier/src/easytier-core.rs index f8f6760..c7616f1 100644 --- a/easytier/src/easytier-core.rs +++ b/easytier/src/easytier-core.rs @@ -288,7 +288,6 @@ struct NetworkOptions { long, env = "ET_ENCRYPTION_ALGORITHM", help = t!("core_clap.encryption_algorithm").to_string(), - default_value = "aes-gcm", value_parser = get_avaliable_encrypt_methods() )] encryption_algorithm: Option, @@ -425,6 +424,15 @@ struct NetworkOptions { )] disable_udp_hole_punching: Option, + #[arg( + long, + env = "ET_DISABLE_SYM_HOLE_PUNCHING", + help = t!("core_clap.disable_sym_hole_punching").to_string(), + num_args = 0..=1, + default_missing_value = "true" + )] + disable_sym_hole_punching: Option, + #[arg( long, env = "ET_RELAY_ALL_PEER_RPC", @@ -919,6 +927,7 @@ impl NetworkOptions { f.enable_relay_foreign_network_kcp = self .enable_relay_foreign_network_kcp .unwrap_or(f.enable_relay_foreign_network_kcp); + f.disable_sym_hole_punching = self.disable_sym_hole_punching.unwrap_or(false); cfg.set_flags(f); if !self.exit_nodes.is_empty() { diff --git a/easytier/src/launcher.rs b/easytier/src/launcher.rs index fcaffae..5304286 100644 --- a/easytier/src/launcher.rs +++ b/easytier/src/launcher.rs @@ -771,6 +771,10 @@ impl NetworkConfig { flags.disable_udp_hole_punching = disable_udp_hole_punching; } + if let Some(disable_sym_hole_punching) = self.disable_sym_hole_punching { + flags.disable_sym_hole_punching = disable_sym_hole_punching; + } + if let Some(enable_magic_dns) = self.enable_magic_dns { flags.accept_dns = enable_magic_dns; } diff --git a/easytier/src/proto/common.proto b/easytier/src/proto/common.proto index 8e01dc1..41ce4ee 100644 --- a/easytier/src/proto/common.proto +++ b/easytier/src/proto/common.proto @@ -52,6 +52,9 @@ message FlagsInConfig { // encryption algorithm to use, empty string means default (aes-gcm) string encryption_algorithm = 29; + + // disable symmetric nat hole punching, treat symmetric as cone when enabled + bool disable_sym_hole_punching = 30; } message RpcDescriptor { diff --git a/easytier/src/proto/web.proto b/easytier/src/proto/web.proto index 78a30f9..9b73856 100644 --- a/easytier/src/proto/web.proto +++ b/easytier/src/proto/web.proto @@ -73,6 +73,8 @@ message NetworkConfig { optional bool enable_quic_proxy = 45; optional bool disable_quic_input = 46; repeated PortForwardConfig port_forwards = 48; + + optional bool disable_sym_hole_punching = 49; } message PortForwardConfig {