Files
justme 0d532caf08
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/verify Pipeline was successful
ci/woodpecker/push/dev-image Pipeline was successful
fix(nodes): locate agents behind a proxy and retry missing countries [CI]
2026-10-18 00:06:39 +08:00

60 lines
2.5 KiB
C#

using System.Net;
using Microsoft.AspNetCore.Http;
using MoShiro.Backend.Api;
using MoShiro.Backend.Application;
namespace MoShiro.Backend.Tests;
/// <summary>真实来源地址:只有从可信代理连进来的请求才采信转发头,而且取最右边第一个不可信的地址。</summary>
public sealed class ClientAddressTests
{
private static string Resolve(string? trusted, string remote, string? forwarded, string? header = null)
{
var resolver = new ClientAddressResolver(new BackendOptions { TrustedProxies = trusted, TrustedProxyHeader = header });
var http = new DefaultHttpContext();
http.Connection.RemoteIpAddress = IPAddress.Parse(remote);
if (forwarded is not null)
{
http.Request.Headers[header ?? "X-Forwarded-For"] = forwarded;
}
return resolver.Resolve(http);
}
[Fact]
public void WithoutTrustedProxies_TheSocketAddressIsUsed_AndTheHeaderIsIgnored() =>
Assert.Equal("203.0.113.9", Resolve(null, "203.0.113.9", "1.2.3.4"));
[Fact]
public void FromATrustedProxy_TheForwardedClientIsUsed() =>
Assert.Equal("198.51.100.7", Resolve("10.0.0.0/8", "10.1.2.3", "198.51.100.7"));
[Fact]
public void FromAnUntrustedPeer_TheHeaderIsIgnored() =>
Assert.Equal("203.0.113.9", Resolve("10.0.0.0/8", "203.0.113.9", "1.2.3.4"));
[Fact]
public void TheChainIsWalkedFromTheRight_SoAClientCannotForgeItsAddress() =>
Assert.Equal("198.51.100.7", Resolve("10.0.0.0/8,127.0.0.1", "10.1.2.3", "6.6.6.6, 198.51.100.7, 10.9.9.9"));
[Fact]
public void AGarbageHeader_FallsBackToTheSocketAddress() =>
Assert.Equal("10.1.2.3", Resolve("10.0.0.0/8", "10.1.2.3", "not-an-ip"));
[Fact]
public void ASingleAddressAndACustomHeaderWork() =>
Assert.Equal("198.51.100.7", Resolve("127.0.0.1", "127.0.0.1", "198.51.100.7", "CF-Connecting-IP"));
[Fact]
public void AMalformedTrustedProxyEntry_FailsAtStartup() =>
Assert.Throws<InvalidOperationException>(() => new ClientAddressResolver(new BackendOptions { TrustedProxies = "banana" }));
[Fact]
public void TheFleetLinkAsksTheSameResolver_SoANodeBehindAProxyKeepsItsRealAddress()
{
Fleet.Server.IClientAddressSource source = new ClientAddressResolver(new BackendOptions { TrustedProxies = "127.0.0.1" });
Assert.Equal("198.51.100.7", source.Resolve(IPAddress.Parse("127.0.0.1"), _ => ["198.51.100.7"]));
Assert.Equal("203.0.113.9", source.Resolve(IPAddress.Parse("203.0.113.9"), _ => ["198.51.100.7"]));
}
}