RSE/Backend/Handler/IpScanner.cs

238 lines
7.5 KiB
C#

using System.Collections.Concurrent;
using System.Globalization;
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<QueueItem> _queue;
private readonly ConcurrentQueue<Discarded> _discardedQueue;
private readonly DbHandler _dbHandler;
private bool _stop;
private int _timeout;
public IpScanner(ConcurrentQueue<QueueItem> queue, DbHandler dbHandler, ConcurrentQueue<Discarded> discardedQueue)
{
_queue = queue;
_dbHandler = dbHandler;
_discardedQueue = discardedQueue;
SetTimeout(128);
}
public void SetTimeout(int milliseconds)
{
Console.WriteLine($"Setting timeout to {milliseconds}ms");
_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)
{
Console.WriteLine("loooooooooooooooooooooooooooool");
Thread.Sleep(500);
}
for (int l = fourthByte; l < 256; l++)
{
if (_stop)
{
resumeObject.FourthByte = l;
break;
}
string ip = $"{i}.{j}.{k}.{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, out IPAddress? address);
if (address is not null)
{
responseCode = ping.Send(address, _timeout, buf, null).Status;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (responseCode != IPStatus.Success)
{
_discardedQueue.Enqueue(CreateDiscardedQueueItem(ip, (int)responseCode));
continue;
}
(int, int) ports = TcpClientHelper.CheckPort(ip, 80, 443);
if (ports is { Item1: 0, Item2: 0 })
{
_discardedQueue.Enqueue(CreateDiscardedQueueItem(ip, (int)responseCode));
continue;
}
_queue.Enqueue(CreateUnfilteredQueueItem(ip, (int)responseCode, 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})");
}
QueueItem resume = new()
{
ResumeObject = resumeObject,
Operations = Operations.Insert
};
_queue.Enqueue(resume);
scanSettings.Handle!.Set();
}
private static Discarded CreateDiscardedQueueItem(string ip, int responseCode)
{
Discarded discarded = new()
{
Ip = ip,
ResponseCode = responseCode
};
return discarded;
}
private static QueueItem CreateUnfilteredQueueItem(string ip, int responseCode, (int, int) ports)
{
Unfiltered unfiltered = new()
{
Ip = ip,
ResponseCode = responseCode,
Port1 = ports.Item1,
Port2 = ports.Item2,
Filtered = 0
};
QueueItem superUnfilteredObject = new()
{
Unfiltered = unfiltered,
Operations = Operations.Insert
};
return superUnfilteredObject;
}
public void Stop()
{
_stop = true;
}
}