using PacketDotNet; using Parsing_Packets.Models; using SharpPcap; using System.Net.NetworkInformation; using System.Text; using System.Text.Json; namespace Parsing_Packets.Helpers; internal static class HelperPhysicalAddress { private static string GetPhysicalAddress(PhysicalAddress physicalAddress, char c) { StringBuilder results = new(); string d = physicalAddress.ToString().ToLower(); for (int i = 0; i < d.Length; i += 2) _ = results.Append(d[i]).Append(d[i + 1]).Append(c); results = results.Remove(results.Length - 1, 1); return results.ToString(); } private static string GetPhysicalAddress(PhysicalAddress physicalAddress) => $"{GetPhysicalAddress(physicalAddress, '-')} | {GetPhysicalAddress(physicalAddress, ':')}"; private static void WriteAllText(ILogger logger, string file, string physicalAddress, string ipv4Address, List collection, Dictionary> keyValuePairs) { logger.LogInformation(""); if (collection.Count == 2) collection[1] = DateTime.Now.ToString("yyyy-MM-dd_HH-mm"); else if (collection.Count == 0) { collection.Add($"block-{physicalAddress[^2..]}"); collection.Add(DateTime.Now.ToString("yyyy-MM-dd_HH-mm")); } if (collection.Count > 1) { logger.LogInformation(collection[0]); logger.LogInformation(collection[1]); } if (collection.Remove(ipv4Address)) collection[1] = DateTime.Now.ToString("yyyy-MM-dd_HH-mm"); collection.Add(ipv4Address); logger.LogInformation(ipv4Address); logger.LogInformation(physicalAddress); string json = JsonSerializer.Serialize(keyValuePairs, HelperPhysicalAddressDictionarySourceGenerationContext.Default.DictionaryStringListString); File.WriteAllText(file, json); } private static void AddPacket(PhysicalAddressConfiguration physicalAddressConfiguration, ILogger logger, string file, List history, string physicalAddress, string ipv4Address, bool isSuggestion) { List? collection; string key = $"{physicalAddress} - {ipv4Address}"; if (!history.Contains(key)) { Dictionary> keyValuePairs = GetKeyValuePairs(file); if (!keyValuePairs.TryGetValue(physicalAddress, out collection)) { keyValuePairs.Add(physicalAddress, []); if (!keyValuePairs.TryGetValue(physicalAddress, out collection)) throw new Exception(); } if (ipv4Address.StartsWith(physicalAddressConfiguration.IPV4Filter) && (collection.Count < 2 || (!isSuggestion && collection[^1] != ipv4Address))) WriteAllText(logger, file, physicalAddress, ipv4Address, collection, keyValuePairs); } history.Add(key); if (history.Count > physicalAddressConfiguration.RemoveHistoryAfter) history.RemoveAt(0); } private static void AddArpPacket(PhysicalAddressConfiguration physicalAddressConfiguration, ILogger logger, string file, List history, EthernetPacket ethernetPacket, ArpPacket arpPacket) { string ipv4Address = arpPacket.SenderProtocolAddress.ToString(); string physicalAddress = GetPhysicalAddress(ethernetPacket.SourceHardwareAddress); AddPacket(physicalAddressConfiguration, logger, file, history, physicalAddress, ipv4Address, isSuggestion: false); } private static void AddDhcpPacket(PhysicalAddressConfiguration physicalAddressConfiguration, ILogger logger, string file, List history, DhcpV4Packet dhcpV4Packet) { string ipv4Address; string physicalAddress; if (dhcpV4Packet.MessageType is DhcpV4MessageType.Request or DhcpV4MessageType.Ack) { ipv4Address = dhcpV4Packet.ClientAddress.ToString(); physicalAddress = GetPhysicalAddress(dhcpV4Packet.ClientHardwareAddress); bool isSuggestion = dhcpV4Packet.MessageType is DhcpV4MessageType.Request; AddPacket(physicalAddressConfiguration, logger, file, history, physicalAddress, ipv4Address, isSuggestion); } else { ipv4Address = dhcpV4Packet.ClientAddress.ToString(); physicalAddress = GetPhysicalAddress(dhcpV4Packet.ClientHardwareAddress); AddPacket(physicalAddressConfiguration, logger, file, history, physicalAddress, ipv4Address, isSuggestion: true); } } private static void AddIpv4Packet(PhysicalAddressConfiguration physicalAddressConfiguration, ILogger logger, string file, List history, EthernetPacket ethernetPacket, IPv4Packet ipv4Packet) { string ipv4Address = ipv4Packet.SourceAddress.ToString(); string physicalAddress = GetPhysicalAddress(ethernetPacket.SourceHardwareAddress); AddPacket(physicalAddressConfiguration, logger, file, history, physicalAddress, ipv4Address, isSuggestion: true); } private static void ParseEthernetPacket(PhysicalAddressConfiguration physicalAddressConfiguration, ILogger logger, string file, List history, EthernetPacket ethernetPacket) { for (int i = 0; i < 1; i++) { if (physicalAddressConfiguration.UseARP && ethernetPacket?.PayloadPacket is ArpPacket arpPacket) { if (arpPacket.Operation != ArpOperation.Response) continue; AddArpPacket(physicalAddressConfiguration, logger, file, history, ethernetPacket, arpPacket); } else if (ethernetPacket?.PayloadPacket is IPv4Packet ipv4Packet) { if (ipv4Packet.SourceAddress.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) continue; if (!ipv4Packet.SourceAddress.ToString().StartsWith(physicalAddressConfiguration.IPV4Filter)) continue; if (ipv4Packet.PayloadPacket is UdpPacket udpPacket && udpPacket.PayloadPacket is DhcpV4Packet dhcpV4Packet) AddDhcpPacket(physicalAddressConfiguration, logger, file, history, dhcpV4Packet); else AddIpv4Packet(physicalAddressConfiguration, logger, file, history, ethernetPacket, ipv4Packet); } } } private static Dictionary> GetKeyValuePairs(string file) { Dictionary> keyValuePairs; if (!File.Exists(file)) keyValuePairs = []; else { string json = File.ReadAllText(file); keyValuePairs = JsonSerializer.Deserialize(json, HelperPhysicalAddressDictionarySourceGenerationContext.Default.DictionaryStringListString) ?? []; } return keyValuePairs; } internal static bool ParsePackets(AppSettings appSettings, ILogger logger, CancellationToken stoppingToken) { ILiveDevice? liveDevice = null; Version version = Pcap.SharpPcapVersion; CaptureDeviceList devices = CaptureDeviceList.Instance; logger.LogInformation("PacketDotNet example using SharpPcap {version}", version); if (devices.Count < 1) logger.LogInformation("No devices were found on this machine"); else { Packet packet; RawCapture rawCapture; GetPacketStatus status; List history = []; if (!Directory.Exists(appSettings.PhysicalAddressConfiguration.Directory)) _ = Directory.CreateDirectory(appSettings.PhysicalAddressConfiguration.Directory); string file = Path.Combine(appSettings.PhysicalAddressConfiguration.Directory, ".json"); logger.LogInformation(""); logger.LogInformation("The following devices are available on this machine:"); logger.LogInformation("----------------------------------------------------"); logger.LogInformation(""); foreach (ILiveDevice? device in devices) { logger.LogInformation("{Name} {Description}", device.Name, device.Description); if (device.Name != appSettings.PhysicalAddressConfiguration.DeviceName) continue; liveDevice = device; } if (liveDevice is null) logger.LogInformation("No devices matched {DeviceName}", appSettings.PhysicalAddressConfiguration.DeviceName); else { logger.LogInformation(""); liveDevice.Open(DeviceModes.Promiscuous, appSettings.PhysicalAddressConfiguration.ReadTimeoutMilliseconds); logger.LogInformation("-- Listening on {Name} {Description}", liveDevice.Name, liveDevice.Description); while (!stoppingToken.IsCancellationRequested) { status = liveDevice.GetNextPacket(out PacketCapture e); if (status != GetPacketStatus.PacketRead) continue; rawCapture = e.GetPacket(); packet = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data); if (packet is not EthernetPacket ethernetPacket) continue; ParseEthernetPacket(appSettings.PhysicalAddressConfiguration, logger, file, history, ethernetPacket); } } } return true; } }