Skip to content

Commit

Permalink
IP descovery
Browse files Browse the repository at this point in the history
  • Loading branch information
veniware committed Aug 30, 2024
1 parent b31bec9 commit f6c850b
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 18 deletions.
42 changes: 41 additions & 1 deletion Protest/Front/ipdiscovery.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,42 @@ class IpDiscovery extends List {

const entry = this.link.data[key];
if (entry) {
//
let changed = false;

if (json.name && entry.name.v.length === 0) {
entry.name.v = json.name;
changed = true;
}

if (json.ipv6 && entry.ipv6.v.length === 0) {
entry.ipv6.v = json.ipv6;
changed = true;
}

if (json.mac && entry.mac.v.length === 0) {
entry.mac.v = json.mac;
changed = true;
}

if (json.manufacturer && entry.manufacturer.v.length === 0) {
entry.manufacturer.v = json.manufacturer;
changed = true;
}

if (json.services) {
const array = json.services.split(",");
for (let i=0; i<array.length; i++) {
if (entry.services.v.includes(array[i])) continue;
entry.services.v.push(array[i]);
changed = true;
}
}

if (changed
&& (entry.element.offsetTop - this.list.scrollTop >= -32 || entry.element.offsetTop - this.list.scrollTop <= this.list.clientHeight)) { //in viewport
this.InflateElement(entry.element, entry);
}

}
else {
let services = Array.from(new Set(json.services.split(",")));
Expand All @@ -185,6 +220,7 @@ class IpDiscovery extends List {
this.list.appendChild(element);

const newHost = {
element : element,
key : {v:key},
name : {v:json.name},
ip : {v:json.ip},
Expand All @@ -197,6 +233,10 @@ class IpDiscovery extends List {
this.link.data[key] = newHost;
this.link.length++;

this.counter.textContent = this.list.childNodes.length === this.link.length
? this.link.length
: `${this.list.childNodes.length} / ${this.link.length}`;

this.InflateElement(element, this.link.data[key]);
}
};
Expand Down
150 changes: 133 additions & 17 deletions Protest/Tools/IpDiscovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Protest.Http;
using Protest.Protocols;

Expand Down Expand Up @@ -44,6 +46,7 @@ internal struct HostEntry {
internal string mac;
internal string manufacturer;
internal string services;
internal string source;
}

private static readonly JsonSerializerOptions hostSerializerOptions;
Expand Down Expand Up @@ -142,7 +145,19 @@ public static async void WebSocketHandler(HttpListenerContext ctx) {

ConcurrentDictionary<string, HostEntry> dic = new ConcurrentDictionary<string, HostEntry>();

Thread[] threads = new Thread[] {
new Thread(()=> DiscoverAdapter(dic, nic, ws, mutex)),
new Thread(()=> DiscoverMdns(dic, nic, ws, mutex, tokenSource.Token)),
new Thread(()=> DiscoverIcmp(dic, nic, ws, mutex, tokenSource.Token)),
};

byte phase = 1;

try {
for (int i = 0; i < threads.Length; i++) {
threads[i].Start();
}

await Task.Delay(50);

while (ws.State == WebSocketState.Open) {
Expand All @@ -151,15 +166,34 @@ public static async void WebSocketHandler(HttpListenerContext ctx) {
break;
}

DiscoverAdapter(dic, nic, ws, mutex, tokenSource.Token);
DiscoverMdns(dic, nic, ws, mutex, tokenSource.Token);
DiscoverIcmp(dic, nic, ws, mutex, tokenSource.Token);
if (threads.All(o => o.ThreadState != ThreadState.Running)) {

if (phase == 1) {
threads = new Thread[] {
new Thread(()=> DiscoverHostname(dic, nic, ws, mutex, tokenSource.Token)),
new Thread(()=> DiscoverServices(dic, nic, ws, mutex, tokenSource.Token)),
};

for (int i = 0; i < threads.Length; i++) {
threads[i].Start();
}

phase = 2;
}
else if (phase == 2) {
break;
}

await Task.Delay(30000);
}

await Task.Delay(3_000);
}
}
catch { }
finally {
tokenSource.Cancel();
dic.Clear();

if (ws?.State == WebSocketState.Open) {
try {
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
Expand All @@ -169,7 +203,7 @@ public static async void WebSocketHandler(HttpListenerContext ctx) {
}
}

private static void DiscoverAdapter(ConcurrentDictionary<string, HostEntry> dic, NetworkInterface nic, WebSocket ws, object mutex, CancellationToken token) {
private static void DiscoverAdapter(ConcurrentDictionary<string, HostEntry> dic, NetworkInterface nic, WebSocket ws, object mutex) {
UnicastIPAddressInformationCollection unicast = nic.GetIPProperties().UnicastAddresses;
GatewayIPAddressInformationCollection gateway = nic.GetIPProperties().GatewayAddresses;

Expand Down Expand Up @@ -199,11 +233,12 @@ private static void DiscoverAdapter(ConcurrentDictionary<string, HostEntry> dic,
mac = mac,
manufacturer = MacLookup.LookupToString(mac),
services = String.Empty,
source = "nic"
};

dic.AddOrUpdate(ipv4String, host, (key, value) => value);

WsWriteText(ws, JsonSerializer.Serialize<HostEntry>(host, hostSerializerOptions), mutex);
WsWriteText(ws, JsonSerializer.SerializeToUtf8Bytes<HostEntry>(host, hostSerializerOptions), mutex);
}

IPAddress gwIpV4 = null, gwIpV6 = null;
Expand All @@ -230,11 +265,12 @@ private static void DiscoverAdapter(ConcurrentDictionary<string, HostEntry> dic,
mac = mac,
manufacturer = MacLookup.LookupToString(mac),
services = String.Empty,
source = "nic"
};

dic.AddOrUpdate(ipv4String, gwHost, (key, value) => value);

WsWriteText(ws, JsonSerializer.Serialize<HostEntry>(gwHost, hostSerializerOptions), mutex);
WsWriteText(ws, JsonSerializer.SerializeToUtf8Bytes<HostEntry>(gwHost, hostSerializerOptions), mutex);
}
}

Expand Down Expand Up @@ -275,6 +311,11 @@ private static void DiscoverIcmp(ConcurrentDictionary<string, HostEntry> dic, Ne

for (int i = 0; i < task.Result.Length; i++) {
if (!task.Result[i]) continue;

if (token.IsCancellationRequested) {
return;
}

string ipString = hosts[i].ToString();
string mac = Arp.ArpRequest(ipString);

Expand All @@ -286,14 +327,85 @@ private static void DiscoverIcmp(ConcurrentDictionary<string, HostEntry> dic, Ne
mac = mac,
manufacturer = MacLookup.LookupToString(mac),
services = String.Empty,
source = "icmp"
};

dic.AddOrUpdate(ipString, gwHost, (key, value) => value);

WsWriteText(ws, JsonSerializer.Serialize<HostEntry>(gwHost, hostSerializerOptions), mutex);
WsWriteText(ws, JsonSerializer.SerializeToUtf8Bytes<HostEntry>(gwHost, hostSerializerOptions), mutex);
}
}

private static void DiscoverMdns(ConcurrentDictionary<string, HostEntry> dic, NetworkInterface nic, WebSocket ws, object mutex, CancellationToken token) {
MdnsMulticast(dic, nic, ws, mutex, token, ANY_QUERY, Protocols.Dns.RecordType.ANY, 1000);
//MdnsMulticast(dic, nic, ws, mutex, token, HTTP_QUERY, Protocols.Dns.RecordType.ANY, 1000);
}

private static void DiscoverHostname(ConcurrentDictionary<string, HostEntry> dic, NetworkInterface nic, WebSocket ws, object mutex, CancellationToken token) {
foreach (KeyValuePair<string, HostEntry> pair in dic) {
if (token.IsCancellationRequested) {
return;
}

HostEntry host = pair.Value;
string name = NetBios.GetBiosName(pair.Key, 200);
if (name is not null) {
WsWriteText(ws, JsonSerializer.SerializeToUtf8Bytes(new {
ip = pair.Key,
name = name,
}), mutex);
}
else {
try {
IPHostEntry hostEntry = System.Net.Dns.GetHostEntry(host.ip);
if (!string.IsNullOrEmpty(hostEntry.HostName)) {
WsWriteText(ws, JsonSerializer.SerializeToUtf8Bytes(new {
ip = pair.Key,
name = name,
}), mutex);
}
}
catch { }
}
}
}

private static void DiscoverServices(ConcurrentDictionary<string, HostEntry> dic, NetworkInterface nic, WebSocket ws, object mutex, CancellationToken token) {
short[] ports = { 22, 23, 53, 80, 443, 445, 3389, 9100 };

foreach (KeyValuePair<string, HostEntry> pair in dic) {
if (token.IsCancellationRequested) {
return;
}

HostEntry host = pair.Value;

Task<bool[]> tasks = PortScan.PortsScanAsync(host.ip, ports, 400, false);
tasks.Wait();

if (tasks.Result.Any(o=>o)) {
StringBuilder services = new StringBuilder();
for (int i = 0; i < tasks.Result.Length; i++) {
if (!tasks.Result[i]) continue;

if (services.Length > 0) services.Append(',');

if (PORTS_TO_PROTOCOL.TryGetValue((ushort)ports[i], out string proto)) {
services.Append(proto);
}
else {
services.Append(ports[i]);
}
}

WsWriteText(ws, JsonSerializer.SerializeToUtf8Bytes(new {
ip = pair.Key,
services = services.ToString()
}), mutex);
}
}
}

private static async Task<bool[]> PingArrayAsync(List<IPAddress> host, int timeout) {
List<Task<bool>> tasks = new List<Task<bool>>();
for (int i = 0; i < host.Count; i++) tasks.Add(PingAsync(host[i], timeout));
Expand All @@ -305,13 +417,15 @@ private static async Task<bool> PingAsync(IPAddress host, int timeout) {

try {
PingReply reply = await p.SendPingAsync(host, timeout, Icmp.ICMP_PAYLOAD);
if (reply.Status == IPStatus.Success) {
return reply.Status == IPStatus.Success;

/*if (reply.Status == IPStatus.Success) {
return true;
}
//retry:
retry:
reply = await p.SendPingAsync(host, timeout*2, Icmp.ICMP_PAYLOAD);
return reply.Status == IPStatus.Success;
return reply.Status == IPStatus.Success;*/
}
catch (ArgumentException) {
return false;
Expand All @@ -324,18 +438,17 @@ private static async Task<bool> PingAsync(IPAddress host, int timeout) {
}
}

private static void DiscoverMdns(ConcurrentDictionary<string, HostEntry> dic, NetworkInterface nic, WebSocket ws, object mutex, CancellationToken token) {
MdnsMulticast(dic, nic, ws, mutex, token, ANY_QUERY, Protocols.Dns.RecordType.ANY, 1000);
MdnsMulticast(dic, nic, ws, mutex, token, HTTP_QUERY, Protocols.Dns.RecordType.ANY, 1000);
}

private static void MdnsMulticast(ConcurrentDictionary<string, HostEntry> dic, NetworkInterface nic, WebSocket ws, object mutex, CancellationToken token, string queryString, RecordType type, int timeout) {
UnicastIPAddressInformationCollection addresses = nic.GetIPProperties().UnicastAddresses;
if (addresses.Count == 0) return;

byte[] request = ConstructQuery(queryString, type);

foreach (UnicastIPAddressInformation address in addresses) {
if (token.IsCancellationRequested) {
return;
}

if (IPAddress.IsLoopback(address.Address)) continue;

using Socket socket = CreateAndBindSocket(address.Address, timeout, out IPEndPoint remoteEndPoint);
Expand Down Expand Up @@ -447,16 +560,18 @@ private static void MdnsResponse(ConcurrentDictionary<string, HostEntry> dic, We
mac = mac,
manufacturer = MacLookup.LookupToString(mac),
services = services.ToString(),
source = "mdns"
};

dic.AddOrUpdate(ipString, host, (key, value) => value);

WsWriteText(ws, JsonSerializer.Serialize<HostEntry>(host, hostSerializerOptions), mutex);
WsWriteText(ws, JsonSerializer.SerializeToUtf8Bytes<HostEntry>(host, hostSerializerOptions), mutex);

}).Start();
}
catch { }
}

}

file sealed class HostJsonConverter : JsonConverter<IpDiscovery.HostEntry> {
Expand All @@ -473,6 +588,7 @@ public override void Write(Utf8JsonWriter writer, IpDiscovery.HostEntry value, J
ReadOnlySpan<byte> _services = "services"u8;

writer.WriteStartObject();
writer.WriteString("source", value.source);
writer.WriteString(_name, value.name);
writer.WriteString(_ip, value.ip);
writer.WriteString(_ipv6, value.ipv6);
Expand Down

0 comments on commit f6c850b

Please sign in to comment.