- The provider card now shows the address block your connection belongs to, as the RIPE Database names it, for example "MOBILE-USERS-BLOCK (IT)" on Iliad mobile or "FASTWEB-L3-PAT_NAT (IT)" on a Fastweb shared address. The path shows it under your provider too. - No block is left out: the server keeps every block in the RIPE Database, small and unique ones included, and tells the app the block of the address it sees, never anyone else's. The app also carries about 430,000 of the larger blocks, for when the server can't be reached. - Only each block's range, name and country are used, nothing about people. The data comes from the RIPE NCC's RIPE Database, used with the RIPE NCC's permission; it may lag behind the live database, and the "What this app contacts" sheet gives its date. - The privacy page says that the server's answer now includes that block name; nothing new is stored or sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
109 lines
4.1 KiB
C#
109 lines
4.1 KiB
C#
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace MeWeb.Core.Knowledge;
|
|
|
|
public class ProviderFact
|
|
{
|
|
public string Value { get; set; }
|
|
public decimal? Price { get; set; }
|
|
public string Currency { get; set; }
|
|
public string Basis { get; set; }
|
|
public string Source { get; set; }
|
|
public string Date { get; set; }
|
|
}
|
|
|
|
public class ProviderProfile
|
|
{
|
|
public string Name { get; set; }
|
|
public string Country { get; set; }
|
|
public List<uint> Asns { get; set; } = [];
|
|
public string Sheet { get; set; }
|
|
public ProviderFact Ipv4 { get; set; }
|
|
public ProviderFact PublicAddress { get; set; }
|
|
public ProviderFact Ipv6 { get; set; }
|
|
public ProviderFact Port25 { get; set; }
|
|
}
|
|
|
|
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web)]
|
|
[JsonSerializable(typeof(ProviderProfile))]
|
|
[JsonSerializable(typeof(List<Carrier>))]
|
|
[JsonSerializable(typeof(List<ObservedNetwork>))]
|
|
public partial class KnowledgeJsonContext : JsonSerializerContext
|
|
{
|
|
}
|
|
|
|
public sealed class KnowledgeBase
|
|
{
|
|
readonly Lazy<AsnTable> asn = new(LoadAsn);
|
|
readonly Lazy<List<ProviderProfile>> providers = new(LoadProviders);
|
|
readonly Lazy<NetworkTable> networks = new(LoadNetworks);
|
|
readonly Lazy<RegistryTable> registry = new(LoadRegistry);
|
|
readonly Lazy<Dictionary<string, string>> carriers = new(LoadCarriers);
|
|
readonly Lazy<List<ObservedNetwork>> observed = new(LoadObserved);
|
|
|
|
public bool HasAsnTable => typeof(KnowledgeBase).Assembly.GetManifestResourceInfo("ip2asn.bin") is not null;
|
|
|
|
public AsnTable Asn => asn.Value;
|
|
|
|
public IReadOnlyList<ProviderProfile> Providers => providers.Value;
|
|
|
|
public RegistryTable Registry => registry.Value;
|
|
|
|
public ProviderProfile ProviderFor(uint number) => number == 0 ? null : Providers.FirstOrDefault(p => p.Asns.Contains(number));
|
|
|
|
public ObservedNetwork ObservedFor(uint number, bool mobile) =>
|
|
number == 0 ? null : observed.Value.FirstOrDefault(o => o.Asn == number && o.Line == (mobile ? ObservedNetwork.Mobile : ObservedNetwork.Home));
|
|
|
|
public NetworkInfo NetworkFor(uint number) => number == 0 ? null : networks.Value?.Find(number);
|
|
|
|
public string CarrierFor(string mccMnc) => string.IsNullOrEmpty(mccMnc) ? null : carriers.Value.GetValueOrDefault(mccMnc);
|
|
|
|
public string NameOf(uint number) => NetworkFor(number)?.Organisation ?? Asn?.Find(number)?.Name;
|
|
|
|
static NetworkTable LoadNetworks()
|
|
{
|
|
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("networks.bin");
|
|
return stream is null ? null : NetworkTable.Read(stream);
|
|
}
|
|
|
|
static RegistryTable LoadRegistry()
|
|
{
|
|
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("registry.bin");
|
|
return stream is null ? null : RegistryTable.Read(stream);
|
|
}
|
|
|
|
static Dictionary<string, string> LoadCarriers()
|
|
{
|
|
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("carriers.json");
|
|
if (stream is null) return [];
|
|
var list = JsonSerializer.Deserialize(stream, KnowledgeJsonContext.Default.ListCarrier) ?? [];
|
|
return list.Where(c => c.MccMnc is not null && c.Name is not null).GroupBy(c => c.MccMnc).ToDictionary(g => g.Key, g => g.First().Name);
|
|
}
|
|
|
|
static List<ObservedNetwork> LoadObserved()
|
|
{
|
|
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("observed.json");
|
|
return stream is null ? [] : JsonSerializer.Deserialize(stream, KnowledgeJsonContext.Default.ListObservedNetwork) ?? [];
|
|
}
|
|
|
|
static AsnTable LoadAsn()
|
|
{
|
|
using var stream = typeof(KnowledgeBase).Assembly.GetManifestResourceStream("ip2asn.bin");
|
|
return stream is null ? null : AsnTable.Read(stream);
|
|
}
|
|
|
|
static List<ProviderProfile> LoadProviders()
|
|
{
|
|
var assembly = typeof(KnowledgeBase).Assembly;
|
|
var list = new List<ProviderProfile>();
|
|
foreach (var name in assembly.GetManifestResourceNames().Where(n => n.StartsWith("isp.", StringComparison.Ordinal)).Order(StringComparer.Ordinal))
|
|
{
|
|
using var stream = assembly.GetManifestResourceStream(name);
|
|
var profile = JsonSerializer.Deserialize(stream, KnowledgeJsonContext.Default.ProviderProfile);
|
|
if (profile is not null) list.Add(profile);
|
|
}
|
|
return list;
|
|
}
|
|
}
|