fix wg client hang after some time (#297)

wg portal doesn't know client disconnect causing msg overstocked in queue, make
entire peer packet process pipeline hang.
This commit is contained in:
Sijie.Sun 2024-08-31 12:44:12 +08:00 committed by GitHub
parent 6964fb71fc
commit 2058dbc470
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 43 additions and 9 deletions

View File

@ -187,10 +187,6 @@ pub enum SocksError {
#[error("Error with reply: {0}.")] #[error("Error with reply: {0}.")]
ReplyError(#[from] ReplyError), ReplyError(#[from] ReplyError),
#[cfg(feature = "socks4")]
#[error("Error with reply: {0}.")]
ReplySocks4Error(#[from] socks4::ReplyError),
#[error("Argument input error: `{0}`.")] #[error("Argument input error: `{0}`.")]
ArgumentInputError(&'static str), ArgumentInputError(&'static str),

View File

@ -19,6 +19,13 @@ impl MpscTunnelSender {
self.0.send(item).await.with_context(|| "send error")?; self.0.send(item).await.with_context(|| "send error")?;
Ok(()) Ok(())
} }
pub fn try_send(&self, item: ZCPacket) -> Result<(), TunnelError> {
self.0.try_send(item).map_err(|e| match e {
tachyonix::TrySendError::Full(_) => TunnelError::BufferFull,
tachyonix::TrySendError::Closed(_) => TunnelError::Shutdown,
})
}
} }
pub struct MpscTunnel<T> { pub struct MpscTunnel<T> {

View File

@ -1,6 +1,7 @@
use std::{ use std::{
net::{Ipv4Addr, SocketAddr}, net::{Ipv4Addr, SocketAddr},
sync::Arc, sync::Arc,
time::Duration,
}; };
use anyhow::Context; use anyhow::Context;
@ -9,7 +10,7 @@ use cidr::Ipv4Inet;
use dashmap::DashMap; use dashmap::DashMap;
use futures::StreamExt; use futures::StreamExt;
use pnet::packet::ipv4::Ipv4Packet; use pnet::packet::ipv4::Ipv4Packet;
use tokio::task::JoinSet; use tokio::{task::JoinSet, time::timeout};
use tracing::Level; use tracing::Level;
use crate::{ use crate::{
@ -23,7 +24,7 @@ use crate::{
mpsc::{MpscTunnel, MpscTunnelSender}, mpsc::{MpscTunnel, MpscTunnelSender},
packet_def::{PacketType, ZCPacket, ZCPacketType}, packet_def::{PacketType, ZCPacket, ZCPacketType},
wireguard::{WgConfig, WgTunnelListener}, wireguard::{WgConfig, WgTunnelListener},
Tunnel, TunnelListener, Tunnel, TunnelError, TunnelListener,
}, },
}; };
@ -92,7 +93,25 @@ impl WireGuardImpl {
info.remote_addr.clone(), info.remote_addr.clone(),
)); ));
while let Some(Ok(msg)) = stream.next().await { let mut map_key = None;
loop {
let msg = match timeout(Duration::from_secs(120), stream.next()).await {
Ok(Some(Ok(msg))) => msg,
Ok(Some(Err(err))) => {
tracing::error!(?err, "Failed to receive from wg client");
break;
}
Ok(None) => {
tracing::info!("Wireguard client disconnected");
break;
}
Err(err) => {
tracing::error!(?err, "Timeout while receiving from wg client");
break;
}
};
assert_eq!(msg.packet_type(), ZCPacketType::WG); assert_eq!(msg.packet_type(), ZCPacketType::WG);
let inner = msg.inner(); let inner = msg.inner();
let Some(i) = Ipv4Packet::new(&inner) else { let Some(i) = Ipv4Packet::new(&inner) else {
@ -104,6 +123,7 @@ impl WireGuardImpl {
endpoint_addr: remote_addr.parse().ok(), endpoint_addr: remote_addr.parse().ok(),
sink: mpsc_tunnel.get_sink(), sink: mpsc_tunnel.get_sink(),
}); });
map_key = Some(i.get_source());
wg_peer_ip_table.insert(i.get_source(), client_entry.clone()); wg_peer_ip_table.insert(i.get_source(), client_entry.clone());
ip_registered = true; ip_registered = true;
} }
@ -114,6 +134,11 @@ impl WireGuardImpl {
.await; .await;
} }
if map_key.is_some() {
tracing::info!(?map_key, "Removing wg client from table");
wg_peer_ip_table.remove(&map_key.unwrap());
}
peer_mgr peer_mgr
.get_global_ctx() .get_global_ctx()
.issue_event(GlobalCtxEvent::VpnPortalClientDisconnected( .issue_event(GlobalCtxEvent::VpnPortalClientDisconnected(
@ -157,9 +182,15 @@ impl WireGuardImpl {
ZCPacketType::WG, ZCPacketType::WG,
); );
if let Err(ret) = entry.sink.send(packet).await { match entry.sink.try_send(packet) {
tracing::debug!(?ret, "Failed to send packet to wg client"); Ok(_) => {
tracing::trace!("Sent packet to wg client");
} }
Err(e) => {
tracing::debug!(?e, "Failed to send packet to wg client");
}
}
None None
} }
} }