Add support for aggressiv ip address scanning.
This commit is contained in:
parent
56fa20b86f
commit
cb5ec30b99
47
src/CidrHelper.cs
Normal file
47
src/CidrHelper.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace SddpViewer;
|
||||||
|
|
||||||
|
public class CidrHelper
|
||||||
|
{
|
||||||
|
public static (IPAddress Start, IPAddress End) GetIpRangeFromCidr(string cidr)
|
||||||
|
{
|
||||||
|
string[] parts = cidr.Split('/');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
throw new FormatException("Ungültiges CIDR-Format.");
|
||||||
|
|
||||||
|
IPAddress ip = IPAddress.Parse(parts[0]);
|
||||||
|
int prefixLength = int.Parse(parts[1]);
|
||||||
|
|
||||||
|
if (prefixLength < 0 || prefixLength > 32)
|
||||||
|
throw new ArgumentException("Ungültige Präfixlänge.");
|
||||||
|
|
||||||
|
byte[] ipBytes = ip.GetAddressBytes();
|
||||||
|
byte[] maskBytes = new byte[4];
|
||||||
|
int remainingBits = prefixLength;
|
||||||
|
|
||||||
|
for (int i = 0; i < maskBytes.Length; i++)
|
||||||
|
{
|
||||||
|
if (remainingBits >= 8)
|
||||||
|
{
|
||||||
|
maskBytes[i] = 0xFF;
|
||||||
|
remainingBits -= 8;
|
||||||
|
}
|
||||||
|
else if (remainingBits > 0)
|
||||||
|
{
|
||||||
|
maskBytes[i] = (byte)(0xFF << (8 - remainingBits));
|
||||||
|
remainingBits = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] startBytes = new byte[4];
|
||||||
|
byte[] endBytes = new byte[4];
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
startBytes[i] = (byte)(ipBytes[i] & maskBytes[i]);
|
||||||
|
endBytes[i] = (byte)(ipBytes[i] | ~maskBytes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (new IPAddress(startBytes), new IPAddress(endBytes));
|
||||||
|
}
|
||||||
|
}
|
@ -118,8 +118,12 @@ public partial class DiscoveredDeviceViewModel : ObservableObject, IDisposable
|
|||||||
|
|
||||||
private string EvaluateHostName() => Dns.GetHostEntry(IpAddress).HostName;
|
private string EvaluateHostName() => Dns.GetHostEntry(IpAddress).HostName;
|
||||||
|
|
||||||
private string GetResponseHeader() =>
|
private string GetResponseHeader()
|
||||||
string.Join("," + Environment.NewLine, _device.ResponseHeaders.Select(x => $"{{{x.Key} : {string.Join(";", x.Value)}}}"));
|
{
|
||||||
|
return _device.ResponseHeaders is null
|
||||||
|
? ""
|
||||||
|
: string.Join("," + Environment.NewLine, _device.ResponseHeaders.Select(x => $"{{{x.Key} : {string.Join(";", x.Value)}}}"));
|
||||||
|
}
|
||||||
|
|
||||||
private IPAddress EvaluateIpAddress(DiscoveredSsdpDevice device) =>
|
private IPAddress EvaluateIpAddress(DiscoveredSsdpDevice device) =>
|
||||||
IPAddress.TryParse(device.DescriptionLocation.Host, out var value) ? value : IPAddress.Any;
|
IPAddress.TryParse(device.DescriptionLocation.Host, out var value) ? value : IPAddress.Any;
|
||||||
|
40
src/IpRangeHelper.cs
Normal file
40
src/IpRangeHelper.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace SddpViewer;
|
||||||
|
|
||||||
|
public class IpRangeHelper
|
||||||
|
{
|
||||||
|
public static IEnumerable<IPAddress> GetIPRange(IPAddress startIp, IPAddress endIp)
|
||||||
|
{
|
||||||
|
uint start = IpToUint(startIp);
|
||||||
|
uint end = IpToUint(endIp);
|
||||||
|
|
||||||
|
if (start > end)
|
||||||
|
{
|
||||||
|
(start, end) = (end, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint current = start; current <= end; current++)
|
||||||
|
{
|
||||||
|
yield return UintToIp(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint IpToUint(IPAddress ip)
|
||||||
|
{
|
||||||
|
byte[] bytes = ip.GetAddressBytes();
|
||||||
|
if (bytes.Length != 4)
|
||||||
|
throw new ArgumentException("Nur IPv4 wird unterstützt.");
|
||||||
|
return (uint)((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IPAddress UintToIp(uint ip)
|
||||||
|
{
|
||||||
|
byte[] bytes = new byte[4];
|
||||||
|
bytes[0] = (byte)((ip >> 24) & 0xFF);
|
||||||
|
bytes[1] = (byte)((ip >> 16) & 0xFF);
|
||||||
|
bytes[2] = (byte)((ip >> 8) & 0xFF);
|
||||||
|
bytes[3] = (byte)(ip & 0xFF);
|
||||||
|
return new IPAddress(bytes);
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,7 @@
|
|||||||
<Button Command="{Binding StartListeningCommand}" Content="Listen for devices" />
|
<Button Command="{Binding StartListeningCommand}" Content="Listen for devices" />
|
||||||
<Button Command="{Binding SearchDevicesNowCommand}" Content="Search now" />
|
<Button Command="{Binding SearchDevicesNowCommand}" Content="Search now" />
|
||||||
<Button Command="{Binding ResearchCommand}" Content="Search more" />
|
<Button Command="{Binding ResearchCommand}" Content="Search more" />
|
||||||
|
<Button Command="{Binding IpScanCommand}" Content="Scan ip" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Grid Grid.Column="1" Grid.Row="0">
|
<Grid Grid.Column="1" Grid.Row="0">
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using System.Collections.Specialized;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
|
||||||
namespace SddpViewer;
|
namespace SddpViewer;
|
||||||
|
|
||||||
@ -132,6 +135,64 @@ public sealed partial class MainWindowViewModel : ObservableObject, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand(IncludeCancelCommand = true)]
|
||||||
|
private async Task IpScan(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (SelectedNetworkAdapter is not null)
|
||||||
|
{
|
||||||
|
var ip = SelectedNetworkAdapter.IpAddress.GetAddressBytes();
|
||||||
|
ip[^1] = 0;
|
||||||
|
var interNetwork = new IPAddress(ip);
|
||||||
|
var cidr = $"{interNetwork}/{SelectedNetworkAdapter.PrefixLength}";
|
||||||
|
var range = CidrHelper.GetIpRangeFromCidr(cidr);
|
||||||
|
var ipRange = IpRangeHelper.GetIPRange(range.Start, range.End).Where(IpAddressFilter);
|
||||||
|
var collection = new ConcurrentBag<DiscoveredDeviceViewModel>();
|
||||||
|
using var httpClient = new HttpClient();
|
||||||
|
httpClient.Timeout = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
|
await Parallel.ForEachAsync(
|
||||||
|
ipRange,
|
||||||
|
new ParallelOptions() { MaxDegreeOfParallelism = 16, CancellationToken = cancellationToken },
|
||||||
|
async (address, token) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
DiscoveredSsdpDevice device = new DiscoveredSsdpDevice()
|
||||||
|
{
|
||||||
|
CacheLifetime = TimeSpan.Zero,
|
||||||
|
DescriptionLocation = new Uri($"http://{address.ToString()}:8080/discovery/ssdp"),
|
||||||
|
};
|
||||||
|
var response = await httpClient.GetAsync(device.DescriptionLocation, token);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
device.ResponseHeaders = response.Headers;
|
||||||
|
var viewModel = new DiscoveredDeviceViewModel(device);
|
||||||
|
collection.Add(viewModel);
|
||||||
|
Console.WriteLine($"{address} ok");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{address} not ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach (DiscoveredDeviceViewModel viewModel in collection)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Invoke(() => SddpDevices.Add(viewModel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IpAddressFilter(IPAddress arg)
|
||||||
|
{
|
||||||
|
if (this.SddpDevices.Any(x => Equals(x.IpAddress, arg)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private async Task StartListening(Func<SsdpDeviceLocator, Task>? action = null)
|
private async Task StartListening(Func<SsdpDeviceLocator, Task>? action = null)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@ using System.Net.Sockets;
|
|||||||
|
|
||||||
namespace SddpViewer;
|
namespace SddpViewer;
|
||||||
|
|
||||||
public record NetworkAdapter(string Name, IPAddress IpAddress)
|
public record NetworkAdapter(string Name, IPAddress IpAddress, int PrefixLength)
|
||||||
{
|
{
|
||||||
public string DisplayName => $"{Name} - {IpAddress}";
|
public string DisplayName => $"{Name} - {IpAddress}";
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ public record NetworkAdapter(string Name, IPAddress IpAddress)
|
|||||||
.UnicastAddresses.FirstOrDefault(x => x.Address.AddressFamily == AddressFamily.InterNetwork);
|
.UnicastAddresses.FirstOrDefault(x => x.Address.AddressFamily == AddressFamily.InterNetwork);
|
||||||
if (physicalAddress is not null)
|
if (physicalAddress is not null)
|
||||||
{
|
{
|
||||||
yield return new NetworkAdapter(nic.Name, physicalAddress.Address);
|
yield return new NetworkAdapter(nic.Name, physicalAddress.Address, physicalAddress.PrefixLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user