79 lines
3.2 KiB
C#
79 lines
3.2 KiB
C#
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, ProbeSimulator Probe, LineTask Udp)> LineAsync()
|
||
{
|
||
AgentHarness agent = await AgentHarness.StartAsync(_backend);
|
||
await agent.OverrideLineTasksAsync(rateHz: 30);
|
||
ProbeSimulator probe = await agent.ConnectProbeAsync();
|
||
LineTaskSet set = await probe.WaitForTasksAsync(s => s.Tasks.Any(t => t.Kind == "udp_echo" && t.Port == agent.App.QuicPorts[0]));
|
||
return (agent, probe, set.Tasks.Single(t => t.Kind == "udp_echo"));
|
||
}
|
||
|
||
[Fact]
|
||
public async Task TcpDataPlane_ClosesConnectionsWithoutAValidFirstFrame()
|
||
{
|
||
(AgentHarness agent, ProbeSimulator probe, _) = await LineAsync();
|
||
await using (agent)
|
||
await using (probe)
|
||
{
|
||
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, ProbeSimulator probe, LineTask udp) = await LineAsync();
|
||
await using (agent)
|
||
await using (probe)
|
||
{
|
||
long before = agent.App.Counters.DroppedInvalid;
|
||
await probe.SendRawUdpAsync([1, 2, 3]);
|
||
await probe.SendRawUdpAsync(new byte[64]);
|
||
await probe.SendForgedEchoAsync(udp, 1);
|
||
await BackendFixture.EventuallyAsync(() => Task.FromResult(agent.App.Counters.DroppedInvalid - before >= 3), because: "garbage and forged packets are counted");
|
||
|
||
// 重放:同一个序号发两次,只有第一次被接受
|
||
await probe.SendEchoAsync(udp, 500);
|
||
await BackendFixture.EventuallyAsync(() => Task.FromResult(agent.App.Counters.PacketsOut >= 1));
|
||
long dropped = agent.App.Counters.DroppedInvalid;
|
||
await probe.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;
|
||
}
|
||
}
|
||
}
|