41 lines
1.8 KiB
C#
41 lines
1.8 KiB
C#
using System.Net;
|
|
using System.Net.Sockets;
|
|
using MoShiro.Protocol;
|
|
|
|
namespace MoShiro.Backend.Application;
|
|
|
|
/// <summary>
|
|
/// 自动识别 Agent 的对外地址:Agent 上报本机的公网地址,注册请求的来源地址作为补充(来源是私网或隧道出口时不用)。
|
|
/// 管理员手填的(<c>*_manual</c>)永远优先;已经选中的自动地址还在候选里就不换,不会因为网卡顺序变化来回改。
|
|
/// </summary>
|
|
public static class AgentAddressPolicy
|
|
{
|
|
/// <summary>返回要写入的 <c>(public_host, ipv6_host)</c>;没有候选的那一项是 null(保持不变)。</summary>
|
|
public static (string? PublicHost, string? Ipv6Host) Choose(AgentRecord current, IReadOnlyList<string> reported, string? observed)
|
|
{
|
|
var v4 = new List<string>();
|
|
var v6 = new List<string>();
|
|
foreach (string text in reported.Append(observed ?? ""))
|
|
{
|
|
if (!IPAddress.TryParse(text, out IPAddress? address))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (address.AddressFamily == AddressFamily.InterNetwork && PublicAddress.IsPublicIpv4(address) && !v4.Contains(address.ToString()))
|
|
{
|
|
v4.Add(address.ToString());
|
|
}
|
|
else if (address.AddressFamily == AddressFamily.InterNetworkV6 && PublicAddress.IsGlobalIpv6(address) && !v6.Contains(address.ToString()))
|
|
{
|
|
v6.Add(address.ToString());
|
|
}
|
|
}
|
|
|
|
return (current.PublicHostManual ? null : Pick(v4, current.PublicHost), current.Ipv6HostManual ? null : Pick(v6, current.Ipv6Host));
|
|
}
|
|
|
|
private static string? Pick(List<string> candidates, string current) =>
|
|
candidates.Count == 0 ? null : candidates.Contains(current) ? current : candidates[0];
|
|
}
|