From 216cf16310d88b303dc450b36f157074870cd0d9 Mon Sep 17 00:00:00 2001 From: lbl <1791778603@qq.com> Date: Thu, 20 Aug 2026 21:30:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=AD=E7=BB=A7=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E6=8E=A2=E6=B5=8B=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MsgType 的 TryFrom 与枚举判别值不一致:RelayProbe 写 18 却被解码为 RelayProbeReply,真正的 Reply(19) 被当非法类型丢弃,改为 18/19 与枚举一致 - RelayProbeReply 回复 TTL 由 1 改为 2:TTL=1 时中继节点 decr 后即被丢弃, 回复永远到不了发起方,中继路由(metric=2)无法建立 - 补充 MsgType 全变体 round-trip 与中继 TTL 语义测试 --- vnt-core/src/protocol/ip_packet_protocol.rs | 66 ++++++++++++++++++++- vnt-core/src/tunnel_core/p2p/inbound.rs | 3 +- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/vnt-core/src/protocol/ip_packet_protocol.rs b/vnt-core/src/protocol/ip_packet_protocol.rs index 1a16c34..19d95fb 100644 --- a/vnt-core/src/protocol/ip_packet_protocol.rs +++ b/vnt-core/src/protocol/ip_packet_protocol.rs @@ -140,9 +140,9 @@ impl TryFrom for MsgType { 14 => MsgType::RpcReq, 15 => MsgType::RpcRes, - 16 => MsgType::RelayProbe, 17 => MsgType::Quic, - 18 => MsgType::RelayProbeReply, + 18 => MsgType::RelayProbe, + 19 => MsgType::RelayProbeReply, _ => { return Err(io::Error::new( io::ErrorKind::InvalidInput, @@ -304,3 +304,65 @@ impl NetPacket { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn msg_type_round_trip() { + let all = [ + MsgType::Turn, + MsgType::Broadcast, + MsgType::ExcludeBroadcast, + MsgType::TargetBroadcast, + MsgType::Ping, + MsgType::Pong, + MsgType::PingTurn, + MsgType::PongTurn, + MsgType::PunchStart1, + MsgType::PunchStart2, + MsgType::PunchReq, + MsgType::PunchRes, + MsgType::PushClientIps, + MsgType::RpcReq, + MsgType::RpcRes, + MsgType::Quic, + MsgType::RelayProbe, + MsgType::RelayProbeReply, + ]; + for msg_type in all { + let byte = u8::from(msg_type); + assert_eq!( + MsgType::try_from(byte).unwrap(), + msg_type, + "round trip failed for {msg_type:?} ({byte})" + ); + } + // 未分配的取值必须报错 + assert!(MsgType::try_from(0u8).is_err()); + assert!(MsgType::try_from(16u8).is_err()); + assert!(MsgType::try_from(20u8).is_err()); + } + + /// 中继转发语义:包每经过一跳 curr_ttl 减 1,curr_ttl >= 1 时才继续转发, + /// 接收方以 metric = max_ttl - curr_ttl 计算路由距离。 + #[test] + fn relay_reply_survives_one_hop() { + let mut packet = + NetPacket::new(BytesMut::from(&[0u8; HEAD_LENGTH][..])).unwrap(); + packet.set_msg_type(MsgType::RelayProbeReply); + // 目标方回复时 TTL 必须允许一次中继 + packet.set_ttl(2); + + // 中继节点:decr 后 curr_ttl == 1,满足转发条件 ttl >= 1 + packet.decr_ttl(); + assert_eq!(packet.ttl(), 1); + assert!(packet.ttl() >= 1, "relay node would drop this packet"); + + // 发起方:decr 后 curr_ttl == 0,metric = 2(经由一个中继) + packet.decr_ttl(); + assert_eq!(packet.ttl(), 0); + assert_eq!(packet.max_ttl() - packet.ttl(), 2); + } +} diff --git a/vnt-core/src/tunnel_core/p2p/inbound.rs b/vnt-core/src/tunnel_core/p2p/inbound.rs index 8608dbc..8f15f75 100644 --- a/vnt-core/src/tunnel_core/p2p/inbound.rs +++ b/vnt-core/src/tunnel_core/p2p/inbound.rs @@ -270,7 +270,8 @@ impl P2pInboundHandler { self.packet_crypto.encrypt_reserve(), ))?; packet.set_msg_type(MsgType::RelayProbeReply); - packet.set_ttl(1); + // 与 RelayProbe 对称:允许中继一次,到达发起方时 curr_ttl 为 0,metric = 2 + packet.set_ttl(2); packet.set_src_id(ctx.dest_ip.into()); packet.set_dest_id(ctx.src_ip.into()); self.packet_crypto.encrypt_in_place(&mut packet)?;