37 lines
1.3 KiB
C#
37 lines
1.3 KiB
C#
using System.Globalization;
|
|||
|
|
|
||
|
|
namespace PrivaPub.Federation.Crawler
|
||
|
|
{
|
||
|
|
public static class PeerHosts
|
||
|
|
{
|
||
|
|
static readonly IdnMapping Idn = new();
|
||
|
|
static readonly string[] Unreachable = { ".onion", ".i2p", ".local", ".localhost", ".internal" };
|
||
|
|
static readonly string[] Reserved = { ".test", ".invalid", ".example" };
|
||
|
|
|
||
|
|
//names from a peers list we could ever talk to: DNS names, ASCII (punycode), no addresses, ports or hidden services;
|
||
|
|
//the reserved test names only on a test network
|
||
|
|
public static IEnumerable<string> Filter(IEnumerable<string> names, Func<string, bool> allowed, bool testNetwork = false) =>
|
||
|
|
names
|
||
|
|
.Select(Normalise)
|
||
|
|
.Where(host => host != default && (testNetwork || !Reserved.Any(suffix => host.EndsWith(suffix, StringComparison.Ordinal))) && allowed(host))
|
||
|
|
.Distinct(StringComparer.Ordinal);
|
||
|
|
|
||
|
|
public static string Normalise(string name)
|
||
|
|
{
|
||
|
|
var host = name?.Trim().TrimEnd('.').ToLowerInvariant();
|
||
|
|
if (string.IsNullOrEmpty(host) || host.Length > 253 || !host.Contains('.') || host.Contains(':') || host.Contains('/'))
|
||
|
|
return default;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
host = Idn.GetAscii(host);
|
||
|
|
}
|
||
|
|
catch (ArgumentException)
|
||
|
|
{
|
||
|
|
return default;
|
||
|
|
}
|
||
|
|
if (Uri.CheckHostName(host) != UriHostNameType.Dns || Unreachable.Any(suffix => host.EndsWith(suffix, StringComparison.Ordinal)))
|
||
|
|
return default;
|
||
|
|
return host;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|