mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 02:09:06 +00:00
support quic proxy (#993)
QUIC proxy works like kcp proxy, it can proxy TCP streams and transfer data with QUIC. QUIC has better congestion algorithm (BBR) for network with both high loss rate and high bandwidth. QUIC proxy can be enabled by passing `--enable-quic-proxy` to easytier in the client side. The proxy status can be viewed by `easytier-cli proxy`.
This commit is contained in:
@@ -124,19 +124,16 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
return Err(anyhow::anyhow!("peer manager is not available").into());
|
||||
};
|
||||
|
||||
let (dst_peers, _) = match nat_dst {
|
||||
SocketAddr::V4(addr) => {
|
||||
let ip = addr.ip();
|
||||
peer_mgr.get_msg_dst_peer(&ip).await
|
||||
}
|
||||
let dst_peer_id = match nat_dst {
|
||||
SocketAddr::V4(addr) => peer_mgr.get_peer_map().get_peer_id_by_ipv4(addr.ip()).await,
|
||||
SocketAddr::V6(_) => return Err(anyhow::anyhow!("ipv6 is not supported").into()),
|
||||
};
|
||||
|
||||
tracing::trace!("kcp nat dst: {:?}, dst peers: {:?}", nat_dst, dst_peers);
|
||||
let Some(dst_peer) = dst_peer_id else {
|
||||
return Err(anyhow::anyhow!("no peer found for nat dst: {}", nat_dst).into());
|
||||
};
|
||||
|
||||
if dst_peers.len() != 1 {
|
||||
return Err(anyhow::anyhow!("no dst peer found for nat dst: {}", nat_dst).into());
|
||||
}
|
||||
tracing::trace!("kcp nat dst: {:?}, dst peers: {:?}", nat_dst, dst_peer);
|
||||
|
||||
let mut connect_tasks: JoinSet<std::result::Result<ConnId, anyhow::Error>> = JoinSet::new();
|
||||
let mut retry_remain = 5;
|
||||
@@ -167,7 +164,6 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
|
||||
let kcp_endpoint = self.kcp_endpoint.clone();
|
||||
let my_peer_id = peer_mgr.my_peer_id();
|
||||
let dst_peer = dst_peers[0];
|
||||
let conn_data_clone = conn_data.clone();
|
||||
|
||||
connect_tasks.spawn(async move {
|
||||
@@ -200,7 +196,7 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
_ipv4: &Ipv4Packet,
|
||||
_real_dst_ip: &mut Ipv4Addr,
|
||||
) -> bool {
|
||||
return hdr.from_peer_id == hdr.to_peer_id;
|
||||
return hdr.from_peer_id == hdr.to_peer_id && hdr.is_kcp_src_modified();
|
||||
}
|
||||
|
||||
fn transport_type(&self) -> TcpProxyEntryTransportType {
|
||||
@@ -211,32 +207,41 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
#[derive(Clone)]
|
||||
struct TcpProxyForKcpSrc(Arc<TcpProxy<NatDstKcpConnector>>);
|
||||
|
||||
pub struct KcpProxySrc {
|
||||
kcp_endpoint: Arc<KcpEndpoint>,
|
||||
peer_manager: Arc<PeerManager>,
|
||||
|
||||
tcp_proxy: TcpProxyForKcpSrc,
|
||||
tasks: JoinSet<()>,
|
||||
#[async_trait::async_trait]
|
||||
pub(crate) trait TcpProxyForKcpSrcTrait: Send + Sync + 'static {
|
||||
type Connector: NatDstConnector;
|
||||
fn get_tcp_proxy(&self) -> &Arc<TcpProxy<Self::Connector>>;
|
||||
async fn check_dst_allow_kcp_input(&self, dst_ip: &Ipv4Addr) -> bool;
|
||||
}
|
||||
|
||||
impl TcpProxyForKcpSrc {
|
||||
#[async_trait::async_trait]
|
||||
impl TcpProxyForKcpSrcTrait for TcpProxyForKcpSrc {
|
||||
type Connector = NatDstKcpConnector;
|
||||
|
||||
fn get_tcp_proxy(&self) -> &Arc<TcpProxy<Self::Connector>> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
async fn check_dst_allow_kcp_input(&self, dst_ip: &Ipv4Addr) -> bool {
|
||||
let peer_map: Arc<crate::peers::peer_map::PeerMap> =
|
||||
self.0.get_peer_manager().get_peer_map();
|
||||
let Some(dst_peer_id) = peer_map.get_peer_id_by_ipv4(dst_ip).await else {
|
||||
return false;
|
||||
};
|
||||
let Some(feature_flag) = peer_map.get_peer_feature_flag(dst_peer_id).await else {
|
||||
let Some(peer_info) = peer_map.get_route_peer_info(dst_peer_id).await else {
|
||||
return false;
|
||||
};
|
||||
feature_flag.kcp_input
|
||||
peer_info.feature_flag.map(|x| x.kcp_input).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl NicPacketFilter for TcpProxyForKcpSrc {
|
||||
impl<C: NatDstConnector, T: TcpProxyForKcpSrcTrait<Connector = C>> NicPacketFilter for T {
|
||||
async fn try_process_packet_from_nic(&self, zc_packet: &mut ZCPacket) -> bool {
|
||||
let ret = self.0.try_process_packet_from_nic(zc_packet).await;
|
||||
let ret = self
|
||||
.get_tcp_proxy()
|
||||
.try_process_packet_from_nic(zc_packet)
|
||||
.await;
|
||||
if ret {
|
||||
return true;
|
||||
}
|
||||
@@ -263,29 +268,45 @@ impl NicPacketFilter for TcpProxyForKcpSrc {
|
||||
}
|
||||
} else {
|
||||
// if not syn packet, only allow established connection
|
||||
if !self.0.is_tcp_proxy_connection(SocketAddr::new(
|
||||
IpAddr::V4(ip_packet.get_source()),
|
||||
tcp_packet.get_source(),
|
||||
)) {
|
||||
if !self
|
||||
.get_tcp_proxy()
|
||||
.is_tcp_proxy_connection(SocketAddr::new(
|
||||
IpAddr::V4(ip_packet.get_source()),
|
||||
tcp_packet.get_source(),
|
||||
))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(my_ipv4) = self.0.get_global_ctx().get_ipv4() {
|
||||
if let Some(my_ipv4) = self.get_tcp_proxy().get_global_ctx().get_ipv4() {
|
||||
// this is a net-to-net packet, only allow it when smoltcp is enabled
|
||||
// because the syn-ack packet will not be through and handled by the tun device when
|
||||
// the source ip is in the local network
|
||||
if ip_packet.get_source() != my_ipv4.address() && !self.0.is_smoltcp_enabled() {
|
||||
if ip_packet.get_source() != my_ipv4.address()
|
||||
&& !self.get_tcp_proxy().is_smoltcp_enabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
zc_packet.mut_peer_manager_header().unwrap().to_peer_id = self.0.get_my_peer_id().into();
|
||||
|
||||
let hdr = zc_packet.mut_peer_manager_header().unwrap();
|
||||
hdr.to_peer_id = self.get_tcp_proxy().get_my_peer_id().into();
|
||||
if self.get_tcp_proxy().get_transport_type() == TcpProxyEntryTransportType::Kcp {
|
||||
hdr.set_kcp_src_modified(true);
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KcpProxySrc {
|
||||
kcp_endpoint: Arc<KcpEndpoint>,
|
||||
peer_manager: Arc<PeerManager>,
|
||||
|
||||
tcp_proxy: TcpProxyForKcpSrc,
|
||||
tasks: JoinSet<()>,
|
||||
}
|
||||
|
||||
impl KcpProxySrc {
|
||||
pub async fn new(peer_manager: Arc<PeerManager>) -> Self {
|
||||
let mut kcp_endpoint = create_kcp_endpoint();
|
||||
|
||||
Reference in New Issue
Block a user