"me-web?" 0.11.0: the name of the block your address belongs to
- 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
This commit is contained in:
1 parent
340b2678ef
commit
aa031c6012
132 files changed
+825
-29
No files matched your search
@@ -1,6 +1,8 @@
|
||||
using System.Buffers.Binary;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace MeWeb.Core.Knowledge;
|
||||
|
||||
@@ -12,6 +14,13 @@ public class Carrier
|
||||
|
||||
public static class Sources
|
||||
{
|
||||
static readonly HashSet<string> Allocations = ["ALLOCATED PA", "ALLOCATED UNSPECIFIED", "ALLOCATED-BY-RIR"];
|
||||
static readonly UInt128 WideV4 = 2048;
|
||||
static readonly UInt128 NarrowV4 = 256;
|
||||
static readonly UInt128 WideV6 = UInt128.One << 88;
|
||||
static readonly UInt128 NarrowV6 = UInt128.One << 80;
|
||||
const int Repeated = 3;
|
||||
|
||||
public static IEnumerable<AsnRange> IpToAsn(Stream gzip)
|
||||
{
|
||||
var names = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
@@ -46,6 +55,73 @@ public static class Sources
|
||||
return seen.ToDictionary(p => p.Key, p => p.Value.MaxBy(n => n.Value).Key);
|
||||
}
|
||||
|
||||
public static IEnumerable<RegistryRange> RipeBlocks(Stream gzip)
|
||||
{
|
||||
using var reader = new StreamReader(new GZipStream(gzip, CompressionMode.Decompress), Encoding.Latin1);
|
||||
RegistryRange range = null;
|
||||
string status = null;
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) is not null)
|
||||
{
|
||||
if (line.Length == 0)
|
||||
{
|
||||
if (range?.Name is not null && !Allocations.Contains(status ?? "")) yield return range;
|
||||
range = null;
|
||||
status = null;
|
||||
continue;
|
||||
}
|
||||
if (range is null)
|
||||
{
|
||||
range = RipeRange(line);
|
||||
continue;
|
||||
}
|
||||
if (line.StartsWith("netname:", StringComparison.Ordinal)) range.Name ??= Value(line);
|
||||
else if (line.StartsWith("country:", StringComparison.Ordinal)) range.Country ??= Value(line).ToUpperInvariant();
|
||||
else if (line.StartsWith("status:", StringComparison.Ordinal)) status ??= Value(line);
|
||||
}
|
||||
if (range?.Name is not null && !Allocations.Contains(status ?? "")) yield return range;
|
||||
}
|
||||
|
||||
public static List<RegistryRange> RipeSelection(IEnumerable<RegistryRange> blocks)
|
||||
{
|
||||
var counts = new Dictionary<string, int>(StringComparer.Ordinal);
|
||||
foreach (var block in blocks)
|
||||
if (block.End - block.Start >= (block.V6 ? NarrowV6 : NarrowV4) - 1) counts[block.Name] = counts.GetValueOrDefault(block.Name) + 1;
|
||||
var names = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
var kept = new List<RegistryRange>();
|
||||
foreach (var block in blocks)
|
||||
{
|
||||
var size = block.End - block.Start;
|
||||
if (size < (block.V6 ? NarrowV6 : NarrowV4) - 1 || (size < (block.V6 ? WideV6 : WideV4) - 1 && counts[block.Name] < Repeated)) continue;
|
||||
block.Name = Intern(names, block.Name);
|
||||
block.Country = Intern(names, block.Country ?? "");
|
||||
kept.Add(block);
|
||||
}
|
||||
return kept;
|
||||
}
|
||||
|
||||
static RegistryRange RipeRange(string line)
|
||||
{
|
||||
if (line.StartsWith("inetnum:", StringComparison.Ordinal))
|
||||
{
|
||||
var parts = Value(line).Split('-', StringSplitOptions.TrimEntries);
|
||||
if (parts.Length != 2 || !IPAddress.TryParse(parts[0], out var first) || !IPAddress.TryParse(parts[1], out var last)) return null;
|
||||
if (first.AddressFamily != AddressFamily.InterNetwork || last.AddressFamily != AddressFamily.InterNetwork) return null;
|
||||
return new RegistryRange { Start = BinaryPrimitives.ReadUInt32BigEndian(first.GetAddressBytes()), End = BinaryPrimitives.ReadUInt32BigEndian(last.GetAddressBytes()) };
|
||||
}
|
||||
if (!line.StartsWith("inet6num:", StringComparison.Ordinal) || !IPNetwork.TryParse(Value(line), out var network)) return null;
|
||||
var start = BinaryPrimitives.ReadUInt128BigEndian(network.BaseAddress.GetAddressBytes());
|
||||
var span = network.PrefixLength == 0 ? UInt128.MaxValue : (UInt128.One << (128 - network.PrefixLength)) - 1;
|
||||
return new RegistryRange { V6 = true, Start = start, End = start | span };
|
||||
}
|
||||
|
||||
static string Value(string line)
|
||||
{
|
||||
var text = line.AsSpan(line.IndexOf(':') + 1);
|
||||
var comment = text.IndexOf('#');
|
||||
return (comment < 0 ? text : text[..comment]).Trim().ToString();
|
||||
}
|
||||
|
||||
public static List<Carrier> Carriers(TextReader textpb)
|
||||
{
|
||||
var list = new List<Carrier>();
|
||||
|
||||
Reference in new issue
Block a user