using System.Collections.Concurrent; using System.Net; using System.Net.NetworkInformation; using Backend.Helper; using Models.Handler; using Models.Model.Backend; namespace Backend.Handler; public class ScanSettings { public int Start; public int End; public int ThreadNumber; public EventWaitHandle? Handle; } public class IpScanner { private readonly ConcurrentQueue _discardedQueue; private readonly ConcurrentQueue _preFilteredQueue; private readonly ConcurrentQueue _resumeQueue; private readonly DbHandler _dbHandler; private bool _stop; private int _timeout; public IpScanner(ConcurrentQueue discardedQueue, ConcurrentQueue resumeQueue, DbHandler dbHandler, ConcurrentQueue preFilteredQueue) { _dbHandler = dbHandler; _preFilteredQueue = preFilteredQueue; _discardedQueue = discardedQueue; _resumeQueue = resumeQueue; SetTimeout(16); } public void SetTimeout(int milliseconds) { _timeout = milliseconds; } public List Start(int threads) { int threadsAmount = 0; if (threads % 2 == 0) { threadsAmount = 256 / threads; } WaitHandle[] waitHandle = new WaitHandle[64]; int counter = 0; List waitHandles = []; for (int i = 0; i < threads; i++) { EventWaitHandle handle = new(false, EventResetMode.ManualReset); ScanSettings scanSettings = new() { Start = threadsAmount * i, End = threadsAmount * i + threadsAmount, ThreadNumber = i, Handle = handle }; if (counter < 64) { waitHandle[counter] = handle; counter++; Thread f = new (Scan!); f.Start(scanSettings); Console.WriteLine($"Scanner thread ({i}) started"); Thread.Sleep(128); continue; } counter = 0; waitHandles.Add(waitHandle); waitHandle = new WaitHandle[64]; } return waitHandles; } private void Scan(object obj) { ScanSettings scanSettings = (ScanSettings)obj; ScannerResumeObject resumeObject = new(); resumeObject.ThreadNumber = scanSettings.ThreadNumber; resumeObject.StartRange = scanSettings.Start; resumeObject.EndRange = scanSettings.End; ScannerResumeObject? resumeNow = _dbHandler.GetResumeObject(scanSettings.ThreadNumber); int secondByte = 0; int thirdByte = 0; int fourthByte = 0; if (resumeNow is not null) { if (resumeNow.Completed) { return; } scanSettings.Start = resumeNow.FirstByte; scanSettings.End = resumeNow.EndRange; secondByte = resumeNow.SecondByte; thirdByte = resumeNow.ThirdByte; fourthByte = resumeNow.FourthByte; } else { CreateResumeObject(scanSettings.ThreadNumber, scanSettings.Start, scanSettings.End, scanSettings.Start, secondByte, thirdByte, fourthByte, false, false, Operations.Insert); } // Empty buffer so we use the lowest abstracted ping.Send() method. byte[] buf = []; using Ping ping = new(); int x = 0; for (int i = scanSettings.Start; i < scanSettings.End; i++) { if (i is 0 or 10 or 127 or 256) continue; if (i is >= 224 and <= 239) continue; for (int j = secondByte; j < 256; j++) { if (i == 169 && j == 254) continue; if (i == 192 && j == 168) continue; if (i == 198 && j == 18 || j == 19) continue; if (i == 172 && j is >= 16 and <= 31) continue; for (int k = thirdByte; k < 256; k++) { if (i == 192 && k == 2) continue; if (i == 192 && j == 88 && k == 99) continue; if (_discardedQueue.Count >= 2000) { Thread.Sleep(1000); } if (_preFilteredQueue.Count >= 2000) { Thread.Sleep(1000); } for (int l = fourthByte; l < 256; l++) { if (x == 75_000) { CreateResumeObject(scanSettings.ThreadNumber, scanSettings.Start, scanSettings.End, i, j, k, l, false, false, Operations.Update); x = 0; } x++; if (_stop) { resumeObject.FourthByte = l; break; } Ip ip = new() { Ip1 = i, Ip2 = j, Ip3 = k, Ip4 = l }; IPStatus responseCode = IPStatus.Unknown; try { // Sometimes, if the pinger gets a Destination Unreachable Communication administratively prohibited response, the pinger will throw an exception. // https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol?useskin=vector#Control_messages _ = IPAddress.TryParse(ip.ToString(), out IPAddress? address); if (address is not null) { responseCode = ping.Send(address, _timeout, buf, null).Status; //Thread.Sleep(4); } } catch { // } if (responseCode != IPStatus.Success) { _discardedQueue.Enqueue(CreateDiscardedQueueItem(ip, (int)responseCode)); continue; } _preFilteredQueue.Enqueue(CreateUnfilteredQueueItem(ip, (int)responseCode)); } if (_stop) { resumeObject.ThirdByte = k; break; } } if (_stop) { resumeObject.SecondByte = j; break; } } if (_stop) { resumeObject.FirstByte = i; break; } Console.WriteLine($"Thread ({scanSettings.ThreadNumber}) is at index ({i}) out of ({scanSettings.End}). Remaining ({scanSettings.End - i})"); } if (_stop) { resumeObject.Paused = true; } else { resumeObject.Completed = true; } resumeObject.Operation = Operations.Update; _resumeQueue.Enqueue(resumeObject); scanSettings.Handle!.Set(); } private void CreateResumeObject(int threadNumber, int startRange, int endRange, int firstByte, int secondByte, int thirdByte, int fourthByte, bool paused, bool completed, Operations operation) { ScannerResumeObject resumeObject = new(); resumeObject.ThreadNumber = threadNumber; resumeObject.StartRange = startRange; resumeObject.EndRange = endRange; resumeObject.FirstByte = firstByte; resumeObject.SecondByte = secondByte; resumeObject.ThirdByte = thirdByte; resumeObject.FourthByte = fourthByte; resumeObject.Paused = paused; resumeObject.Completed = completed; resumeObject.Operation = operation; _resumeQueue.Enqueue(resumeObject); } private static Discarded CreateDiscardedQueueItem(Ip ip, int responseCode) { return new() { Ip = ip, ResponseCode = responseCode }; } private static FilterQueueItem CreateUnfilteredQueueItem(Ip ip, int responseCode) { FilterQueueItem filterQueueItem = new() { Ip = ip, ResponseCode = responseCode }; return filterQueueItem; } public void Stop() { _stop = true; } }