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 GetResponseHeader() =>
|
||||
string.Join("," + Environment.NewLine, _device.ResponseHeaders.Select(x => $"{{{x.Key} : {string.Join(";", x.Value)}}}"));
|
||||
private string GetResponseHeader()
|
||||
{
|
||||
return _device.ResponseHeaders is null
|
||||
? ""
|
||||
: string.Join("," + Environment.NewLine, _device.ResponseHeaders.Select(x => $"{{{x.Key} : {string.Join(";", x.Value)}}}"));
|
||||
}
|
||||
|
||||
private IPAddress EvaluateIpAddress(DiscoveredSsdpDevice device) =>
|
||||
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 SearchDevicesNowCommand}" Content="Search now" />
|
||||
<Button Command="{Binding ResearchCommand}" Content="Search more" />
|
||||
<Button Command="{Binding IpScanCommand}" Content="Scan ip" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<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;
|
||||
|
||||
@ -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]
|
||||
private async Task StartListening(Func<SsdpDeviceLocator, Task>? action = null)
|
||||
{
|
||||
|
@ -4,7 +4,7 @@ using System.Net.Sockets;
|
||||
|
||||
namespace SddpViewer;
|
||||
|
||||
public record NetworkAdapter(string Name, IPAddress IpAddress)
|
||||
public record NetworkAdapter(string Name, IPAddress IpAddress, int PrefixLength)
|
||||
{
|
||||
public string DisplayName => $"{Name} - {IpAddress}";
|
||||
|
||||
@ -20,7 +20,7 @@ public record NetworkAdapter(string Name, IPAddress IpAddress)
|
||||
.UnicastAddresses.FirstOrDefault(x => x.Address.AddressFamily == AddressFamily.InterNetwork);
|
||||
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