refactor: handle quic proxy internally instead of use external udp port (#1743)

* deprecate quic_listen_port, add disable_relay_quic and enable_relay_foreign_network_quic
* add set_src_modified to TcpProxyForWrappedSrcTrait
* prioritize quic over kcp
This commit is contained in:
Luna Yao
2026-02-02 04:53:40 +01:00
committed by GitHub
parent 21f4a944a7
commit cd2cf56358
21 changed files with 1419 additions and 530 deletions
+1 -49
View File
@@ -1,5 +1,5 @@
use std::net::{Ipv4Addr, Ipv6Addr};
use std::sync::atomic::{AtomicU16, Ordering};
use std::sync::atomic::Ordering;
use std::time::Instant;
use std::{
net::IpAddr,
@@ -59,7 +59,6 @@ pub struct AclFilter {
// Use ArcSwap for lock-free atomic replacement during hot reload
acl_processor: ArcSwap<AclProcessor>,
acl_enabled: Arc<AtomicBool>,
quic_udp_port: AtomicU16,
// Track allowed outbound packets and automatically allow their corresponding inbound response
// packets, even if they would normally be dropped by ACL rules
@@ -80,7 +79,6 @@ impl AclFilter {
Self {
acl_processor: ArcSwap::from(Arc::new(AclProcessor::new(Acl::default()))),
acl_enabled: Arc::new(AtomicBool::new(false)),
quic_udp_port: AtomicU16::new(0),
outbound_allow_records,
clean_task: tokio::spawn(async move {
let max_life = std::time::Duration::from_secs(30);
@@ -295,40 +293,6 @@ impl AclFilter {
processor.increment_stat(AclStatKey::PacketsTotal);
}
fn check_is_quic_packet(
&self,
packet_info: &PacketInfo,
my_ipv4: &Option<Ipv4Addr>,
my_ipv6: &Option<Ipv6Addr>,
) -> bool {
if packet_info.protocol != Protocol::Udp {
return false;
}
let quic_port = self.get_quic_udp_port();
if quic_port == 0 {
return false;
}
// quic input
if packet_info.dst_port == Some(quic_port)
&& (packet_info.dst_ip == my_ipv4.unwrap_or(Ipv4Addr::UNSPECIFIED)
|| packet_info.dst_ip == my_ipv6.unwrap_or(Ipv6Addr::UNSPECIFIED))
{
return true;
}
// quic output
if packet_info.src_port == Some(quic_port)
&& (packet_info.src_ip == my_ipv4.unwrap_or(Ipv4Addr::UNSPECIFIED)
|| packet_info.src_ip == my_ipv6.unwrap_or(Ipv6Addr::UNSPECIFIED))
{
return true;
}
false
}
/// Common ACL processing logic
pub fn process_packet_with_acl(
&self,
@@ -360,10 +324,6 @@ impl AclFilter {
}
};
if self.check_is_quic_packet(&packet_info, &my_ipv4, &my_ipv6) {
return true;
}
let chain_type = if is_in {
if packet_info.dst_ip == my_ipv4.unwrap_or(Ipv4Addr::UNSPECIFIED)
|| packet_info.dst_ip == my_ipv6.unwrap_or(Ipv6Addr::UNSPECIFIED)
@@ -424,12 +384,4 @@ impl AclFilter {
}
}
}
pub fn get_quic_udp_port(&self) -> u16 {
self.quic_udp_port.load(Ordering::Relaxed)
}
pub fn set_quic_udp_port(&self, port: u16) {
self.quic_udp_port.store(port, Ordering::Relaxed);
}
}
@@ -169,6 +169,7 @@ impl ForeignNetworkEntry {
let mut flags = config.get_flags();
flags.disable_relay_kcp = !global_ctx.get_flags().enable_relay_foreign_network_kcp;
flags.disable_relay_quic = !global_ctx.get_flags().enable_relay_foreign_network_quic;
config.set_flags(flags);
config.set_mapped_listeners(Some(global_ctx.config.get_mapped_listeners()));
+48
View File
@@ -1489,6 +1489,54 @@ impl PeerManager {
true
}
pub async fn check_allow_quic_to_dst(&self, dst_ip: &IpAddr) -> bool {
let route = self.get_route();
let Some(dst_peer_id) = route.get_peer_id_by_ip(dst_ip).await else {
return false;
};
let Some(peer_info) = route.get_peer_info(dst_peer_id).await else {
return false;
};
// check dst allow quic input
if !peer_info
.feature_flag
.map(|x| x.quic_input)
.unwrap_or(false)
{
return false;
}
let next_hop_policy = Self::get_next_hop_policy(self.global_ctx.get_flags().latency_first);
// check relay node allow relay quic.
let Some(next_hop_id) = route
.get_next_hop_with_policy(dst_peer_id, next_hop_policy)
.await
else {
return false;
};
if next_hop_id == dst_peer_id {
// dst p2p, no need to relay
return true;
}
let Some(next_hop_info) = route.get_peer_info(next_hop_id).await else {
return false;
};
// check next hop allow quic relay
if next_hop_info
.feature_flag
.map(|x| x.no_relay_quic)
.unwrap_or(false)
{
return false;
}
true
}
pub async fn update_exit_nodes(&self) {
let exit_nodes = self.global_ctx.config.get_exit_nodes();
*self.exit_nodes.write().await = exit_nodes;
+5 -2
View File
@@ -123,6 +123,7 @@ fn is_foreign_network_info_newer(
}
impl RoutePeerInfo {
#[allow(deprecated)]
pub fn new() -> Self {
Self {
peer_id: 0,
@@ -141,9 +142,10 @@ impl RoutePeerInfo {
feature_flag: None,
peer_route_id: 0,
network_length: 24,
quic_port: None,
ipv6_addr: None,
groups: Vec::new(),
quic_port: None,
}
}
@@ -191,10 +193,11 @@ impl RoutePeerInfo {
.map(|x| x.network_length() as u32)
.unwrap_or(24),
quic_port: global_ctx.get_quic_proxy_port().map(|x| x as u32),
ipv6_addr: global_ctx.get_ipv6().map(|x| x.into()),
groups: global_ctx.get_acl_groups(my_peer_id),
..Default::default()
}
}