使用 CIDR 表示法解析子网

问题描述 投票:0回答:1

我的 ARP 扫描仪有问题。

我有函数将输入的子网解析为 IP 范围,我可以迭代它,这样我就可以向网络发送 ARP 请求并返回网络上活动的主机。

我可以通过 Wireshark 应用程序看到正在生成 ARP 数据包,但子网错误。

例如,当我在wireshark中输入子网192.168.1.1/24时,我看到1.1.168.X而不是192.168.1.X wireshark_scan

此外,由于某种原因,它不适用于 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));
    }
}
c# network-programming subnet arp
1个回答
0
投票

您的

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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.