Files
MoShiro/backend/tests/MoShiro.Backend.Tests/AgentDataPlaneTests.cs
T

79 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Net;
using System.Net.Sockets;
using MoShiro.Measurement;
using MoShiro.Protocol;
using MoShiro.TestSupport;
namespace MoShiro.Backend.Tests;
/// <summary>数据面协议拒绝错误首帧、伪造包、重放包和垃圾数据。</summary>
[Trait("Category", "Slow")]
public sealed class AgentDataPlaneTests : IClassFixture<BackendFixture>
{
private readonly BackendFixture _backend;
public AgentDataPlaneTests(BackendFixture backend)
{
_backend = backend;
}
private async Task<(AgentHarness Agent, DialerSimulator Dialer, LineTask Udp)> LineAsync()
{
AgentHarness agent = await AgentHarness.StartAsync(_backend);
await agent.OverrideLineTasksAsync(rateHz: 30);
DialerSimulator dialer = await agent.ConnectDialerAsync();
LineTaskSet set = await dialer.WaitForTasksAsync(s => s.Tasks.Any(t => t.Kind == "quic_ping" && t.Port == agent.App.QuicPorts[0]));
return (agent, dialer, set.Tasks.Single(t => t.Kind == "quic_ping"));
}
[Fact]
public async Task TcpDataPlane_ClosesConnectionsWithoutAValidFirstFrame()
{
(AgentHarness agent, DialerSimulator dialer, _) = await LineAsync();
await using (agent)
await using (dialer)
{
using var client = new TcpClient();
await client.ConnectAsync(IPAddress.Loopback, agent.App.TcpPorts[0]);
await client.GetStream().WriteAsync(new byte[TcpWire.AuthBytes]); // 全零:magic 不对
byte[] buffer = new byte[16];
Assert.Equal(0, await ReadOrResetAsync(client.GetStream(), buffer)); // 连接被关闭:没有任何字节(Windows 上可能是 RST)
await BackendFixture.EventuallyAsync(() => Task.FromResult(agent.App.Counters.DroppedInvalid >= 1));
}
}
[Fact]
public async Task DataPlane_DropsForgedReplayedAndGarbagePackets_WithoutAnswering()
{
(AgentHarness agent, DialerSimulator dialer, LineTask udp) = await LineAsync();
await using (agent)
await using (dialer)
{
long before = agent.App.Counters.DroppedInvalid;
await dialer.SendRawUdpAsync([1, 2, 3]);
await dialer.SendRawUdpAsync(new byte[64]);
await dialer.SendForgedEchoAsync(udp, 1);
await BackendFixture.EventuallyAsync(() => Task.FromResult(agent.App.Counters.DroppedInvalid - before >= 3), because: "garbage and forged packets are counted");
// 重放:同一个序号发两次,只有第一次被接受
await dialer.SendEchoAsync(udp, 500);
await BackendFixture.EventuallyAsync(() => Task.FromResult(agent.App.Counters.PacketsOut >= 1));
long dropped = agent.App.Counters.DroppedInvalid;
await dialer.SendEchoAsync(udp, 500);
await BackendFixture.EventuallyAsync(() => Task.FromResult(agent.App.Counters.DroppedInvalid > dropped), because: "a replayed packet is dropped");
}
}
private static async Task<int> ReadOrResetAsync(Stream stream, byte[] buffer)
{
try
{
return await stream.ReadAsync(buffer).AsTask().WaitAsync(TimeSpan.FromSeconds(10));
}
catch (IOException)
{
return 0;
}
}
}