我的 ARP 扫描仪有问题。
我有函数将输入的子网解析为 IP 范围,我可以迭代它,这样我就可以向网络发送 ARP 请求并返回网络上活动的主机。
我可以通过 Wireshark 应用程序看到正在生成 ARP 数据包,但子网错误。
例如,当我在wireshark中输入子网192.168.1.1/24时,我看到1.1.168.X而不是192.168.1.X
此外,由于某种原因,它不适用于 192.168.1.0/24,仅适用于末尾为零的 192.168.1.1/24,它什么也不做。
这是扫描仪的代码:
[DllImport("iphlpapi.dll", ExactSpelling = true)]
private static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);
private static uint macAddrLen = (uint)new byte[6].Length;
private async Task PerformArpScan()
{
ScanResults.Clear();
foreach (var subnet in Subnets)
{
var (networkAddress, cidr) = ParseSubnet(subnet);
var hosts = GenerateIPRange(networkAddress, cidr).ToList();
var results = new ConcurrentBag<ScanResult>();
await Task.Run(() =>
{
Parallel.ForEach(hosts, new ParallelOptions { MaxDegreeOfParallelism = 20 }, ip =>
{
var result = SendArpRequest(ip);
if (result != null)
{
results.Add(result);
}
});
});
await Dispatcher.InvokeAsync(() =>
{
foreach (var result in results)
{
ScanResults.Add(result);
}
});
}
}
private ScanResult SendArpRequest(IPAddress ipAddress)
{
byte[] macAddr = new byte[6];
uint macAddrLen = (uint)macAddr.Length;
try
{
int result = SendARP(BitConverter.ToInt32(ipAddress.GetAddressBytes().Reverse().ToArray(), 0), 0, macAddr, ref macAddrLen);
if (result == 0)
{
string macAddressString = string.Join(":", macAddr.Take((int)macAddrLen).Select(b => b.ToString("X2")));
return new ScanResult
{
IpAddress = ipAddress.ToString(),
MacAddress = macAddressString,
Status = "Online",
OpenPorts = "N/A"
};
}
}
catch (Exception ex)
{
Console.WriteLine($"Error sending ARP request to {ipAddress}: {ex.Message}");
}
return null;
}
private (IPAddress, int) ParseSubnet(string subnet)
{
var parts = subnet.Split('/');
var ip = IPAddress.Parse(parts[0]);
var cidr = int.Parse(parts[1]);
// Ensure we're using the network address
var ipBytes = ip.GetAddressBytes();
var mask = uint.MaxValue << (32 - cidr);
var networkBytes = BitConverter.GetBytes(BitConverter.ToUInt32(ipBytes, 0) & mask);
return (new IPAddress(networkBytes), cidr);
}
private IEnumerable<IPAddress> GenerateIPRange(IPAddress networkAddress, int cidr)
{
byte[] ipBytes = networkAddress.GetAddressBytes();
uint startIP = BitConverter.ToUInt32(ipBytes, 0) & (uint.MaxValue << (32 - cidr));
uint endIP = startIP | (uint.MaxValue >> cidr);
for (uint i = startIP + 1; i < endIP; i++)
{
yield return new IPAddress(BitConverter.GetBytes(i));
}
}
您的
GenerateIPRange
实施中可能存在问题。 IPAddress.GetAddressBytes()
方法将按网络顺序返回字节(大端/最高有效字节在前),而 BitConverter
方法将按主机顺序读取(在 x86/64 架构上小端/最低有效字节在前)。 您需要反转字节顺序,例如:
private IEnumerable<IPAddress> GenerateIPRange(IPAddress networkAddress, int cidr)
{
Action<byte[]> ReverseIfLittleEndian = b => {
if (BitConverter.IsLittleEndian)
Array.Reverse(b);
};
byte[] ipBytes = networkAddress.GetAddressBytes();
ReverseIfLittleEndian(ipBytes);
uint startIP = BitConverter.ToUInt32(ipBytes, 0) & (uint.MaxValue << (32 - cidr));
uint endIP = startIP | (uint.MaxValue >> cidr);
for (uint i = startIP + 1; i < endIP; i++)
{
byte[] ipa = BitConverter.GetBytes(i);
ReverseIfLittleEndian(ipa);
yield return new IPAddress(ipa);
}
}
在 .NET Core 中,BinaryPrimitives 类提供了合并字节序的方法:
using System.Buffers.Binary;
private IEnumerable<IPAddress> GenerateIPRange(IPAddress networkAddress, int cidr)
{
byte[] ipBytes = networkAddress.GetAddressBytes();
uint startIP = BinaryPrimitives.ReadUInt32BigEndian(ipBytes) & (uint.MaxValue << (32 - cidr));
uint endIP = startIP | (uint.MaxValue >> cidr);
for (uint i = startIP + 1; i < endIP; i++)
{
byte[] addr = new byte[sizeof(uint)];
BinaryPrimitives.WriteUInt32BigEndian(addr, i);
yield return new IPAddress(addr);
}
}