mirror of
https://github.com/Stone-Red-Code/ARP-Scanner.git
synced 2026-09-04 00:46:04 +02:00
Update project to .NET 8 and auto update mac db
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>ARP_Scanner</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -10,14 +10,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ArpLookup" Version="2.0.3" />
|
||||
<PackageReference Include="CuteUtils" Version="1.0.0" />
|
||||
<PackageReference Include="IPAddressRange" Version="6.0.0" />
|
||||
<PackageReference Include="Stone_Red-C-Sharp-Utilities" Version="1.0.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="mac-vendors.csv">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace ARP_Scanner;
|
||||
|
||||
internal class MacDatabase
|
||||
{
|
||||
public DateTime LastUpdate { get; set; }
|
||||
public List<MacInformation> MacInformations { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ARP_Scanner;
|
||||
|
||||
internal class MacInformation
|
||||
{
|
||||
[JsonPropertyName("macPrefix")]
|
||||
public required string MacPrefix { get; set; }
|
||||
|
||||
[JsonPropertyName("vendorName")]
|
||||
public required string VendorName { get; set; }
|
||||
|
||||
[JsonPropertyName("private")]
|
||||
public bool? Private { get; set; }
|
||||
|
||||
[JsonPropertyName("blockType")]
|
||||
public required string BlockType { get; set; }
|
||||
|
||||
[JsonPropertyName("lastUpdate")]
|
||||
public required string LastUpdate { get; set; }
|
||||
}
|
||||
@@ -1,57 +1,95 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using CuteUtils.Misc;
|
||||
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ARP_Scanner;
|
||||
|
||||
internal class MacVendorLookup
|
||||
internal partial class MacVendorLookup
|
||||
{
|
||||
public readonly string[] header;
|
||||
private readonly string[][] fields;
|
||||
private const string macLookupUrl = "https://maclookup.app/downloads/json-database/get-db";
|
||||
private readonly HttpClient httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(20) };
|
||||
|
||||
public MacVendorLookup(string csvPath)
|
||||
private MacDatabase macDatabase = new MacDatabase();
|
||||
|
||||
public async Task Initialize()
|
||||
{
|
||||
if (!File.Exists(csvPath))
|
||||
string cachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "macDatabase.json");
|
||||
|
||||
// Snap support
|
||||
string? snapUserCommon = Environment.GetEnvironmentVariable("SNAP_USER_COMMON");
|
||||
|
||||
if (snapUserCommon is not null)
|
||||
{
|
||||
header = Array.Empty<string>();
|
||||
fields = Array.Empty<string[]>();
|
||||
cachePath = Path.Combine(snapUserCommon, "macDatabase.json");
|
||||
}
|
||||
|
||||
if (File.Exists(cachePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
macDatabase = JsonSerializer.Deserialize<MacDatabase>(File.ReadAllText(cachePath)) ?? new MacDatabase();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ConsoleExt.WriteLine($"Failed to read MAC database cache: {ex.Message}", ConsoleColor.Red);
|
||||
}
|
||||
}
|
||||
|
||||
// Update MAC database if it's older than a week
|
||||
if (macDatabase.LastUpdate > DateTime.Now.AddDays(-7))
|
||||
{
|
||||
ConsoleExt.WriteLine("Using cached MAC database...", ConsoleColor.DarkYellow);
|
||||
return;
|
||||
}
|
||||
|
||||
string[] lines = File.ReadAllLines(csvPath);
|
||||
ConsoleExt.WriteLine("Downloading MAC database from maclookup.app...", ConsoleColor.DarkYellow);
|
||||
|
||||
header = lines[0].Split(',');
|
||||
fields = lines.Skip(1).Select(l => Regex.Split(l, ",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))")).ToArray();
|
||||
}
|
||||
List<MacInformation>? newMacInformations = null;
|
||||
|
||||
public string[] GetInformation(string macAdress)
|
||||
{
|
||||
string[]? data = Array.Find(fields, f => macAdress.StartsWith(f[0]));
|
||||
|
||||
if (fields.Length == 0 || header.Length == 0)
|
||||
try
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
newMacInformations = await httpClient.GetFromJsonAsync<List<MacInformation>>(macLookupUrl);
|
||||
}
|
||||
else if (data is null)
|
||||
catch (Exception ex)
|
||||
{
|
||||
string[] result = new string[header.Length - 1];
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
ConsoleExt.WriteLine($"Failed to download MAC database: {ex.Message}", ConsoleColor.Red);
|
||||
}
|
||||
|
||||
if (newMacInformations is null)
|
||||
{
|
||||
if (macDatabase.MacInformations.Count != 0)
|
||||
{
|
||||
result[i] = "Unknown";
|
||||
ConsoleExt.WriteLine("Failed to download MAC database, using cache...", ConsoleColor.DarkYellow);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsoleExt.WriteLine("Failed to download MAC database and no cache found, using empty database...", ConsoleColor.Red);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
for (int i = 1; i < header.Length; i++)
|
||||
{
|
||||
result.Add($"{data[i]}");
|
||||
}
|
||||
return result.ToArray();
|
||||
ConsoleExt.WriteLine("MAC database downloaded successfully!", ConsoleColor.Green);
|
||||
|
||||
_ = Directory.CreateDirectory(Path.GetDirectoryName(cachePath)!);
|
||||
|
||||
macDatabase.MacInformations = newMacInformations;
|
||||
macDatabase.LastUpdate = DateTime.Now;
|
||||
File.WriteAllText(cachePath, JsonSerializer.Serialize(macDatabase));
|
||||
}
|
||||
}
|
||||
|
||||
public string[] GetHeader()
|
||||
public MacInformation GetInformation(string macAdress)
|
||||
{
|
||||
return header!.Skip(1).ToArray();
|
||||
macAdress = macAdress.Replace("-", ":")[..8].ToUpper();
|
||||
|
||||
return macDatabase.MacInformations.Find(m => m.MacPrefix == macAdress) ?? new MacInformation()
|
||||
{
|
||||
MacPrefix = macAdress,
|
||||
VendorName = "Unknown",
|
||||
BlockType = "Unknown",
|
||||
Private = false,
|
||||
LastUpdate = "Unknown"
|
||||
};
|
||||
}
|
||||
}
|
||||
+14
-12
@@ -1,9 +1,8 @@
|
||||
using ArpLookup;
|
||||
|
||||
using NetTools;
|
||||
using CuteUtils.Misc;
|
||||
|
||||
using Stone_Red_Utilities.CollectionExtentions;
|
||||
using Stone_Red_Utilities.ConsoleExtentions;
|
||||
using NetTools;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
@@ -15,7 +14,7 @@ internal static class Program
|
||||
{
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
MacVendorLookup macVendorLookup = new MacVendorLookup("mac-vendors.csv");
|
||||
MacVendorLookup macVendorLookup = new MacVendorLookup();
|
||||
|
||||
if (!Arp.IsSupported)
|
||||
{
|
||||
@@ -29,14 +28,16 @@ internal static class Program
|
||||
return;
|
||||
}
|
||||
|
||||
await macVendorLookup.Initialize();
|
||||
|
||||
long ipAddressesCount = ipAddressRange.Count();
|
||||
long processedIpAddressesCount = 0;
|
||||
int numberOfDigits = ipAddressesCount.ToString().Length;
|
||||
|
||||
List<string> header = new List<string>() { "IP", "MAC" };
|
||||
ConcurrentBag<string[]> activeHosts = new ConcurrentBag<string[]>();
|
||||
List<string> header = ["IP", "MAC"];
|
||||
ConcurrentBag<string[]> activeHosts = [];
|
||||
|
||||
header.AddRange(macVendorLookup.GetHeader());
|
||||
header.AddRange([nameof(MacInformation.VendorName), nameof(MacInformation.BlockType), nameof(MacInformation.Private), nameof(MacInformation.LastUpdate)]);
|
||||
|
||||
ConsoleExt.WriteLine("Starting scan...", ConsoleColor.DarkYellow);
|
||||
|
||||
@@ -60,10 +61,11 @@ internal static class Program
|
||||
{
|
||||
string formattedMac = BitConverter.ToString(mac.GetAddressBytes());
|
||||
|
||||
List<string> info = new List<string> { ipAddress.ToString(), formattedMac };
|
||||
info.AddRange(macVendorLookup.GetInformation(formattedMac));
|
||||
MacInformation macInformation = macVendorLookup.GetInformation(formattedMac);
|
||||
|
||||
List<string> info = [ipAddress.ToString(), formattedMac, macInformation.VendorName, macInformation.BlockType, macInformation.Private.ToString() ?? "Unknown", macInformation.LastUpdate];
|
||||
ConsoleExt.WriteLine($"Progress: {localProcessedIpAddressesCount.ToString().PadLeft(numberOfDigits)}/{ipAddressesCount} [{100d / ipAddressesCount * localProcessedIpAddressesCount,6:##0.00}%] | Active: {ipAddress}", ConsoleColor.Green);
|
||||
activeHosts.Add(info.ToArray());
|
||||
activeHosts.Add([.. info]);
|
||||
}
|
||||
else if (fail)
|
||||
{
|
||||
@@ -79,9 +81,9 @@ internal static class Program
|
||||
{
|
||||
Console.WriteLine(Environment.NewLine + "Active hosts:");
|
||||
|
||||
List<string[]>? activeHostsTable = activeHosts.ToList();
|
||||
List<string[]>? activeHostsTable = [.. activeHosts];
|
||||
|
||||
activeHostsTable.Insert(0, header.ToArray());
|
||||
activeHostsTable.Insert(0, [.. header]);
|
||||
|
||||
activeHostsTable.ToArray().To2D().PrintTable(TableStyle.List);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user