#:project ../src/MeWeb.Core/MeWeb.Core.csproj using System.IO.Compression; using System.Net; using System.Security.Cryptography; using MeWeb.Core.Knowledge; const string Source = "https://iptoasn.com/data/ip2asn-combined.tsv.gz"; var root = FindRoot(); var cache = Path.Combine(root, "tools", "cache"); var output = Path.Combine(root, "artifacts", "knowledge", "ip2asn.bin"); Directory.CreateDirectory(cache); Directory.CreateDirectory(Path.GetDirectoryName(output)); var download = Path.Combine(cache, "ip2asn-combined.tsv.gz"); using var http = new HttpClient(); http.DefaultRequestHeaders.UserAgent.ParseAdd("me-web-knowledge/1 (+https://git.thepra.dev/Arasaka/MeWeb)"); var fresh = !File.Exists(download) || File.GetLastWriteTimeUtc(download) < DateTime.UtcNow.AddHours(-12) || args.Contains("--refresh"); var sourceDate = File.Exists(download) ? new DateTimeOffset(File.GetLastWriteTimeUtc(download), TimeSpan.Zero) : DateTimeOffset.UtcNow; if (fresh) { using var response = await http.GetAsync(Source, HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); sourceDate = response.Content.Headers.LastModified ?? DateTimeOffset.UtcNow; await using (var file = File.Create(download + ".tmp")) await response.Content.CopyToAsync(file); File.Move(download + ".tmp", download, overwrite: true); File.SetLastWriteTimeUtc(download, sourceDate.UtcDateTime); } var hash = Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(download))); var ranges = new List(); using (var reader = new StreamReader(new GZipStream(File.OpenRead(download), CompressionMode.Decompress))) { string line; while ((line = reader.ReadLine()) is not null) { var parts = line.Split('\t'); if (parts.Length < 5 || !uint.TryParse(parts[2], out var number) || number == 0) continue; if (!IPAddress.TryParse(parts[0], out var start) || !IPAddress.TryParse(parts[1], out var end)) continue; ranges.Add(new AsnRange { Start = start, End = end, Number = number, Country = parts[3] == "None" ? "" : parts[3], Name = parts[4] }); } } await using (var file = File.Create(output + ".tmp")) AsnTable.Write(file, sourceDate, ranges); File.Move(output + ".tmp", output, overwrite: true); using var check = File.OpenRead(output); var table = AsnTable.Read(check); var probe = table.Find(IPAddress.Parse("1.1.1.1")); Console.WriteLine($"knowledge: {ranges.Count} routed ranges, {table.Count} networks, source {sourceDate:yyyy-MM-dd HH:mm} UTC, sha256 {hash}"); Console.WriteLine($"knowledge: {output} {new FileInfo(output).Length / 1024} KiB; 1.1.1.1 -> AS{probe?.Number} {probe?.Name}"); File.WriteAllText(Path.Combine(root, "artifacts", "knowledge", "SOURCE.txt"), $"{Source}\nlast-modified {sourceDate:O}\nsha256 {hash}\n"); return 0; static string FindRoot() { var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "MeWeb.slnx"))) dir = dir.Parent; return dir?.FullName ?? throw new InvalidOperationException("run from inside the repository (MeWeb.slnx not found)"); }