From 6489237233f63a289b47e6c0d63105689c706c3e Mon Sep 17 00:00:00 2001 From: lbl <1791778603@qq.com> Date: Thu, 20 Aug 2026 21:48:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A9=BA=E8=BD=BD=E8=8D=B7?= =?UTF-8?q?=E5=8C=85=E8=B6=8A=E7=95=8C=20panic=20=E6=9D=80=E6=AD=BB?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=9D=A2=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对端构造的零载荷包(头部长度恰好等于 HEAD_LENGTH)会使 TunDataInbound/InternalNatInbound 的 data[0] 索引越界 panic, tokio 任务终止后连接永久静默死亡。两处 send 均增加空切片检查, 畸形包静默丢弃。补充空包/短包不 panic 的测试。 --- vnt-core/src/nat/internal_nat/mod.rs | 2 +- vnt-core/src/tun/sender.rs | 38 +++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/vnt-core/src/nat/internal_nat/mod.rs b/vnt-core/src/nat/internal_nat/mod.rs index 55c73cc..fcd5344 100644 --- a/vnt-core/src/nat/internal_nat/mod.rs +++ b/vnt-core/src/nat/internal_nat/mod.rs @@ -53,7 +53,7 @@ impl InternalNatInbound { }) } pub async fn send(&self, data: &[u8], net: &NetworkAddr) -> anyhow::Result<()> { - if data[0] >> 4 != 4 { + if data.is_empty() || data[0] >> 4 != 4 { return Ok(()); } let Some(ipv4) = Ipv4Packet::new(data) else { diff --git a/vnt-core/src/tun/sender.rs b/vnt-core/src/tun/sender.rs index 06679ae..875fb92 100644 --- a/vnt-core/src/tun/sender.rs +++ b/vnt-core/src/tun/sender.rs @@ -20,7 +20,7 @@ impl TunDataInbound { impl TunDataInbound { pub async fn send(&self, data: TransmissionBytes, net: &NetworkAddr) -> anyhow::Result<()> { - if data[0] >> 4 != 4 { + if data.is_empty() || data[0] >> 4 != 4 { return Ok(()); } let Some(ipv4) = Ipv4Packet::new(data.as_ref()) else { @@ -38,3 +38,39 @@ impl TunDataInbound { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::nat::AllowSubnetExternalRoute; + use crate::tun::tun_channel; + use std::net::Ipv4Addr; + + fn test_net() -> NetworkAddr { + NetworkAddr { + gateway: Ipv4Addr::new(10, 26, 0, 1), + broadcast: Ipv4Addr::new(10, 26, 0, 255), + ip: Ipv4Addr::new(10, 26, 0, 2), + prefix_len: 24, + } + } + + /// 对端构造的零载荷/畸形包必须被静默丢弃,不能 panic 杀死数据面任务 + #[tokio::test] + async fn test_send_empty_or_short_packet_does_not_panic() { + let (tun_inbound, _receiver) = tun_channel(); + let inbound = TunDataInbound::new(tun_inbound, AllowSubnetExternalRoute::new(vec![])); + + // 零载荷包(头部被剥离后为空) + inbound + .send(TransmissionBytes::zeroed(0), &test_net()) + .await + .unwrap(); + + // 过短的包(不足 IPv4 头) + inbound + .send(TransmissionBytes::zeroed(3), &test_net()) + .await + .unwrap(); + } +}