62 lines
3.0 KiB
C#
62 lines
3.0 KiB
C#
#: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<AsnRange>();
|
||
|
|
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)");
|
||
|
|
}
|