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 _unfilteredQueue; private readonly ConcurrentQueue _resumeQueue; private readonly DbHandler _dbHandler; private bool _stop; private int _timeout; public IpScanner(ConcurrentQueue unfilteredQueue, ConcurrentQueue discardedQueue, ConcurrentQueue resumeQueue, DbHandler dbHandler ) { _dbHandler = dbHandler; _discardedQueue = discardedQueue; _unfilteredQueue = unfilteredQueue; _resumeQueue = resumeQueue; SetTimeout(64); } public void SetTimeout(int milliseconds) { _timeout = milliseconds; } public WaitHandle[] Start(int threads) { int threadsAmount = 0; if (threads % 2 == 0) { threadsAmount = 256 / threads; } WaitHandle[] waitHandles = new WaitHandle[threads]; 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 }; waitHandles[i] = handle; Thread f = new (Scan!); f.Start(scanSettings); Console.WriteLine($"Scanner thread ({i}) started"); Thread.Sleep(1000); } 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) { scanSettings.Start = resumeNow.FirstByte; scanSettings.End = resumeNow.EndRange; secondByte = resumeNow.SecondByte; thirdByte = resumeNow.ThirdByte; fourthByte = resumeNow.FourthByte; } byte[] buf = []; using Ping ping = new(); 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(500); } for (int l = fourthByte; l < 256; l++) { 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; } } catch { // } if (responseCode != IPStatus.Success) { _discardedQueue.Enqueue(CreateDiscardedQueueItem(ip, (int)responseCode)); continue; } (int, int) ports = TcpClientHelper.CheckPort(ip.ToString(), 80, 443); if (ports is { Item1: 0, Item2: 0 }) { _discardedQueue.Enqueue(CreateDiscardedQueueItem(ip, (int)responseCode)); continue; } _unfilteredQueue.Enqueue(CreateUnfilteredQueueItem(ip, ports)); } 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})"); } _resumeQueue.Enqueue(resumeObject); scanSettings.Handle!.Set(); } private static Discarded CreateDiscardedQueueItem(Ip ip, int responseCode) { return new() { Ip = ip, ResponseCode = responseCode }; } private static UnfilteredQueueItem CreateUnfilteredQueueItem(Ip ip, (int, int) ports) { Unfiltered unfiltered = new() { Ip = ip, Port1 = ports.Item1, Port2 = ports.Item2, Filtered = false }; return new() { Unfiltered = unfiltered, Operations = Operations.Insert }; } public void Stop() { _stop = true; } }