CDNs found by themselves, and servers followed through time
PrivaPub now finds CDNs three ways, best first: the address ranges the CDNs publish (Cloudflare, Fastly, Amazon CloudFront, Bunny, Gcore, Imperva), downloaded daily by CdnUpdater and kept in CdnRangeSet; the CDN's fingerprint in the responses it already gets from a server (EdgeHintsHandler on the federation client); and the networks that carry only a CDN. The fixed ASN list is gone; ASNs shared with plain hosting (AWS, DataPacket) no longer hide a server. A server's Geo records the CDN, its domain and how it was found, and weekly snapshots now keep the city and coordinates too. Servers through time (ServerPlaces): /instances/:host/history lists a server's weekly snapshots, a CDN-fronted server's geo names the CDN's domain and where the server was before it (before_cdn), and /api/privapub/v1/cdns and /cdns/:domain group servers by CDN with week by week who joined and who left. Owner decisions recorded in ROADMAP. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
5d7edc4a4c
commit
436f7da464
26 files changed
+1159
-62
No files matched your search
@@ -1,4 +1,4 @@
|
||||
using MongoDB.Entities;
|
||||
using MongoDB.Entities;
|
||||
|
||||
using PrivaPub.Infrastructure.Geo;
|
||||
using PrivaPub.Infrastructure.Http;
|
||||
@@ -18,12 +18,17 @@ namespace PrivaPub.Federation.Objects
|
||||
readonly IFederationHttp _http;
|
||||
readonly IGeoLocator _geo;
|
||||
readonly IConnectedAddresses _addresses;
|
||||
readonly ICdnRanges _cdnRanges;
|
||||
readonly IEdgeHints _edges;
|
||||
|
||||
public InstanceDescriber(IFederationHttp http, IGeoLocator geo = default, IConnectedAddresses addresses = default)
|
||||
public InstanceDescriber(IFederationHttp http, IGeoLocator geo = default, IConnectedAddresses addresses = default, ICdnRanges cdnRanges = default,
|
||||
IEdgeHints edges = default)
|
||||
{
|
||||
_http = http;
|
||||
_geo = geo;
|
||||
_addresses = addresses;
|
||||
_cdnRanges = cdnRanges;
|
||||
_edges = edges;
|
||||
}
|
||||
|
||||
public JobKind Kind => JobKind.DescribeInstance;
|
||||
@@ -145,35 +150,57 @@ namespace PrivaPub.Federation.Objects
|
||||
.Modify(s => s.RegistrationMode, instance?.RegistrationMode)
|
||||
.Modify(s => s.Languages, instance?.Languages)
|
||||
.Modify(s => s.Country, instance?.Geo?.Country)
|
||||
.Modify(s => s.City, instance?.Geo?.City)
|
||||
.Modify(s => s.Latitude, instance?.Geo?.Latitude)
|
||||
.Modify(s => s.Longitude, instance?.Geo?.Longitude)
|
||||
.Modify(s => s.Asn, instance?.Geo?.Asn)
|
||||
.Modify(s => s.Cdn, instance?.Geo?.Cdn)
|
||||
.Modify(s => s.CdnDomain, instance?.Geo?.CdnDomain)
|
||||
.Modify(s => s.CdnSource, instance?.Geo?.CdnSource)
|
||||
.Modify(s => s.Ipv6, instance?.Geo?.Ipv6)
|
||||
.Option(o => o.IsUpsert = true)
|
||||
.ExecuteAsync(token);
|
||||
return facts != default;
|
||||
}
|
||||
|
||||
// Where the address we reached sits, and the CDN in front of it, found by its published ranges, then by the
|
||||
// fingerprint in the responses we just got, then by a network that carries only a CDN.
|
||||
InstanceGeo Locate(string host)
|
||||
{
|
||||
var reached = _addresses?.Of(new Uri(Address($"https://{host}/")).Host);
|
||||
var reachedHost = new Uri(Address($"https://{host}/")).Host;
|
||||
var reached = _addresses?.Of(reachedHost);
|
||||
var fix = reached == default ? default : _geo?.Locate(reached);
|
||||
if (fix == default)
|
||||
var (cdn, cdnSource) = Cdn(reached, reachedHost, fix?.Asn, _cdnRanges, _edges);
|
||||
if (fix == default && cdn == default)
|
||||
return default;
|
||||
return new InstanceGeo
|
||||
{
|
||||
Country = fix.Country,
|
||||
City = fix.City,
|
||||
Latitude = fix.Latitude,
|
||||
Longitude = fix.Longitude,
|
||||
Asn = fix.Asn,
|
||||
AsnOrg = fix.AsnOrg,
|
||||
Cdn = CdnNetworks.Of(fix.Asn),
|
||||
Ipv6 = reached.AddressFamily == AddressFamily.InterNetworkV6,
|
||||
Source = _geo.Source,
|
||||
Country = fix?.Country,
|
||||
City = fix?.City,
|
||||
Latitude = fix?.Latitude,
|
||||
Longitude = fix?.Longitude,
|
||||
Asn = fix?.Asn,
|
||||
AsnOrg = fix?.AsnOrg,
|
||||
Cdn = cdn?.Name,
|
||||
CdnDomain = cdn?.Domain,
|
||||
CdnSource = cdnSource,
|
||||
Ipv6 = reached?.AddressFamily == AddressFamily.InterNetworkV6,
|
||||
Source = _geo?.Source,
|
||||
LocatedAt = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
|
||||
public static (CdnProvider Cdn, string Source) Cdn(System.Net.IPAddress address, string host, int? asn, ICdnRanges ranges, IEdgeHints edges)
|
||||
{
|
||||
if (ranges?.Of(address) is { } listed)
|
||||
return (listed, "ranges");
|
||||
if (edges?.Of(host) is { } hinted)
|
||||
return (hinted, "headers");
|
||||
if (CdnCatalog.OfAsn(asn) is { } network)
|
||||
return (network, "asn");
|
||||
return default;
|
||||
}
|
||||
|
||||
//where an https address is fetched from: itself, except in tests, which point it at a plain-http peer
|
||||
protected virtual string Address(string url) => url;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user