feat(quic): replace probe UDP data plane with QUIC datagrams

This commit is contained in:
justme committed 2026-10-10 02:59:56 +08:00
1 parent 4609048865
commit b964dc2bbc
53 files changed
+2413 -411

No files matched your search

@@ -3,7 +3,7 @@ using System.Security.Cryptography;
namespace MoShiro.Protocol;
public enum UdpPacketType : byte
public enum MeasurementDatagramType : byte
{
EchoRequest = 1,
EchoReply = 2,
@@ -12,7 +12,7 @@ public enum UdpPacketType : byte
Data = 3,
}
public readonly record struct UdpHeader(UdpPacketType Type, long SessionId, uint StreamId, uint Seq, long SendTsUs);
public readonly record struct MeasurementDatagramHeader(MeasurementDatagramType Type, long SessionId, uint StreamId, uint Seq, long SendTsUs);
/// <summary>
/// 数据面的 UDP 包(Fleet 之外的线格式):
@@ -20,7 +20,7 @@ public readonly record struct UdpHeader(UdpPacketType Type, long SessionId, uint
/// mac = HMAC-SHA256(session_key, 前面全部字节) 截断到 16 字节。所有整数小端。
/// 接收方对不合法的包静默丢弃并计数,不回复(防放大)。
/// </summary>
public static class UdpPacket
public static class MeasurementDatagram
{
public const ushort Magic = 0x4D4E; // "MN"
public const byte Version = 1;
@@ -30,19 +30,19 @@ public static class UdpPacket
public const int MaxBytes = 1472;
/// <summary>检查长度、magic、version、type 并解析头部(不校验 MAC)。</summary>
public static bool TryParseHeader(ReadOnlySpan<byte> packet, out UdpHeader header)
public static bool TryParseHeader(ReadOnlySpan<byte> packet, out MeasurementDatagramHeader header)
{
header = default;
if (packet.Length is < MinBytes or > MaxBytes
|| BinaryPrimitives.ReadUInt16LittleEndian(packet) != Magic
|| packet[2] != Version
|| packet[3] is < (byte)UdpPacketType.EchoRequest or > (byte)UdpPacketType.Data)
|| packet[3] is < (byte)MeasurementDatagramType.EchoRequest or > (byte)MeasurementDatagramType.Data)
{
return false;
}
header = new UdpHeader(
(UdpPacketType)packet[3],
header = new MeasurementDatagramHeader(
(MeasurementDatagramType)packet[3],
BinaryPrimitives.ReadInt64LittleEndian(packet[4..]),
BinaryPrimitives.ReadUInt32LittleEndian(packet[12..]),
BinaryPrimitives.ReadUInt32LittleEndian(packet[16..]),
@@ -51,7 +51,7 @@ public static class UdpPacket
}
/// <summary>写入整个包(长度就是 <paramref name="destination"/> 的长度),填充为零,末尾是 MAC。</summary>
public static void Write(Span<byte> destination, in UdpHeader header, ReadOnlySpan<byte> key)
public static void Write(Span<byte> destination, in MeasurementDatagramHeader header, ReadOnlySpan<byte> key)
{
if (destination.Length is < MinBytes or > MaxBytes)
{
@@ -19,8 +19,8 @@ public static class TcpWire
public static void WriteAuth(Span<byte> destination, long sessionId, uint streamId, ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> key)
{
BinaryPrimitives.WriteUInt16LittleEndian(destination, UdpPacket.Magic);
destination[2] = UdpPacket.Version;
BinaryPrimitives.WriteUInt16LittleEndian(destination, MeasurementDatagram.Magic);
destination[2] = MeasurementDatagram.Version;
BinaryPrimitives.WriteInt64LittleEndian(destination[3..], sessionId);
BinaryPrimitives.WriteUInt32LittleEndian(destination[11..], streamId);
nonce[..NonceBytes].CopyTo(destination[15..]);
@@ -35,7 +35,7 @@ public static class TcpWire
sessionId = 0;
streamId = 0;
nonce = default;
if (frame.Length != AuthBytes || BinaryPrimitives.ReadUInt16LittleEndian(frame) != UdpPacket.Magic || frame[2] != UdpPacket.Version)
if (frame.Length != AuthBytes || BinaryPrimitives.ReadUInt16LittleEndian(frame) != MeasurementDatagram.Magic || frame[2] != MeasurementDatagram.Version)
{
return false;
}