65.9K
CodeProject 正在变化。 阅读更多。
Home

网络嗅探器和分析程序 - 第二部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (6投票s)

2022 年 10 月 28 日

CPOL

3分钟阅读

viewsIcon

8629

downloadIcon

795

使用 C# .NET 6.0 Windows Form (Sharppcap, PacketDotNet) 编写的网络嗅探器和分析程序

引言

您可以阅读本文的第一部分,请访问以下链接:网络嗅探器和分析程序 - 第一部分

扫描网络以获取所有可用设备

在本部分中,我们将学习如何获取网络上所有可用设备及其信息,例如 MAC 地址、主机名、IPv4 和 IPv6。

实际上,有两种方法可以确定设备是否连接到网络

第一种方法是 ping 目标 IP,然后等待其响应,并在特定超时时间内等待。如果收到响应,则表示可用;如果没有收到响应,则表示不可用。

这种方法的缺点是目标设备必须允许传入的回显请求,才能 ping 目标设备。

firewall > Advanced > Settings. check Allow incoming echo request.

另一种方法是应用 Dns.GetHostEntryAsync(hostNameOrAddress)

在目标 IP 上,此方法将获取有关目标 IP 的所有信息,或者在 IP 不在网络中时返回错误或超时错误。

在下面的代码中,我将向您展示如何以优雅的方式执行此操作

  public class PingDeviceCompletedEventArgs : EventArgs
    {
        public PingDeviceStatus Status;

        public string IP;
    }

public enum PingDeviceStatus
    {
        Pending,
        Completed,
        InvalidHost,
        Timeout
    }

    public delegate void PingDeviceCompletedEventHandler
           (Object sender, PingDeviceCompletedEventArgs e);

    public class PingDevice
    {
        public event PingDeviceCompletedEventHandler PingCompleted;
        public PingDevice()  { }

        public async void SendAsync
               (string hostNameOrAddress, int millisecond_time_out)
        {            
                new Thread(async delegate ()
                {
                    PingDeviceCompletedEventArgs args = 
                              new PingDeviceCompletedEventArgs();
                    PingDeviceCompletedEventHandler handler = this.PingCompleted;
                    try
                    {
                        args.Status = PingDeviceStatus.Pending;
                        var result = Task.Run(() => 
                        Dns.GetHostEntryAsync(hostNameOrAddress)).Wait
                            (millisecond_time_out);
                        if (!result)
                        {
                            args.Status = PingDeviceStatus.Timeout;
                            args.IP = null;
                            if (handler != null)
                                handler(this, args);
                        }
                        else
                        {
                            args.Status = PingDeviceStatus.Completed;
                            args.IP = hostNameOrAddress;
                            if (handler != null)
                                handler(this, args);
                        }
                    }
                    catch (Exception ex)
                    {
                        args.Status = PingDeviceStatus.InvalidHost;
                        args.IP = null;
                        if (handler != null)
                            handler(this, args);
                    }

                }).Start();
            }

            public async void SendAsync(string hostNameOrAddress)
            {
                {
                    new Thread(async delegate ()
                    {
                        PingDeviceCompletedEventArgs args = 
                                  new PingDeviceCompletedEventArgs();
                        PingDeviceCompletedEventHandler handler = this.PingCompleted;
                        try
                        {
                            args.Status = PingDeviceStatus.Pending;
                            var result = await Dns.GetHostEntryAsync(hostNameOrAddress);
                           
                            if (result == null)
                            {
                                args.Status = PingDeviceStatus.Timeout;
                                args.IP = null;
                                if (handler != null)
                                    handler(this, args);
                            }
                            else
                            {
                                args.Status = PingDeviceStatus.Completed;
                                args.IP = hostNameOrAddress;
                                if (handler != null)
                                    handler(this, args);
                            }
                        }
                        catch (Exception ex)
                        {
                            args.Status = PingDeviceStatus.InvalidHost;
                            args.IP = null;
                            if (handler != null)
                                handler(this, args);
                        }
                    }).Start();
                }
            }
    }

PingDevice 类中,我们有两个异步函数,名为“SendAsych”。在第二个函数中,我们将调用 Dns.GetHostEntryAsync (hostNameOrAddress) 函数,并为其设置“await”关键字。这个关键字将组织事件的触发,以防止执行线程在目标函数执行完毕之前执行任何其他操作。最终,Dns.GetHostEntryAsync 将找到目标设备并返回其信息,或者它将抛出错误并返回 Null,状态为 Invalid Host。两种方法之间的区别在于,在第一种方法中,我们必须手动设置超时时间,而在第二种方法中,超时时间将自动设置。现在,在定义获取网络中可用设备的主要方法之后,我们将增强我们的 ,,PingDeviceCompletedEventArgs" 类,以获取有关找到的设备的所有信息,例如主机名、MAC 地址和 IPv6 地址

 public class PingDeviceCompletedEventArgs : EventArgs
    {
        public PingDeviceStatus Status;

        public string IP;

        public string Host => (IP != null) ? GetHostName(IP) : null;

        public List<string> Ipv6 => (IP != null) ? getIPV6Addr(IP) : null;

        public string MAC => (IP != null) ? getMACAddresse(IP) : null;

        List<string> getIPV6Addr(string ipv4)
        {
            try
            {
                IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(ipv4);
                IPAddress[] addr = ipEntry.AddressList;
                List<string> foundIPs = new List<string>();
                foreach (IPAddress iPAddress in addr)
                {
                    if (iPAddress.AddressFamily == 
                        System.Net.Sockets.AddressFamily.InterNetworkV6)
                    {
                        foundIPs.Add(iPAddress.ToString());
                    }
                }
                return foundIPs;
            }
            catch (Exception ex) { return null; }

            return null;
        }

        string GetHostName(string ipAddress)
        {
            try
            {
                IPHostEntry entry = Dns.GetHostEntry(ipAddress);
                if (entry != null)
                {
                    return entry.HostName;
                }
            }
            catch (SocketException)
            {
                // MessageBox.Show(e.Message.ToString());
            }

            return null;
        }

        [DllImport("iphlpapi.dll", ExactSpelling = true)]
        public static extern int SendARP(int DestIP, int SrcIP, 
               [Out] byte[] MacAddr, ref int MacLen);

        public string getMACAddresse(string Ipaddress)
        {
            IPAddress address = IPAddress.Parse(Ipaddress);
            try
            {
                byte[] MACByte = new byte[6];
                int MACLength = MACByte.Length;
                SendARP((int)address.Address, 0, MACByte, ref MACLength);
                string MACSSTR = BitConverter.ToString(MACByte, 0, 6);
                if (MACSSTR != "00-00-00-00-00-00")
                    return PhysicalAddress.Parse(MACSSTR).ToString();
            }
            catch (Exception ex) { return "not detected"; }
            return "not detected";
        }

Using the Code

要使用特定超时时间 ping 单个设备,可以使用以下代码

        public void Ping_Device(string host, int time_out)
        {
            Thread thread = new Thread(() =>
              {
                  try
                  {
                      PingDevice ping = new PingDevice();
                      ping.PingCompleted += 
                      new PingDeviceCompletedEventHandler(Ping_Completed);
                      ping.SendAsync(host, time_out);
                  }
                  catch
                  {

                  }
              });

            thread.Start();

         //   Ping_Threads.Add(thread);
        }

要使用自动超时时间 ping 单个设备,可以使用以下代码

 void Ping_Device(string host)
        {
            Thread thread = new Thread(() =>
            {
                try
                {
                    PingDevice ping = new PingDevice();
                    ping.PingCompleted += 
                    new PingDeviceCompletedEventHandler(Ping_Completed);
                    ping.SendAsync(host);
                }
                catch
                {

                }
            });

            thread.Start();

            //   Ping_Threads.Add(thread);
        }

我强烈建议使用自动超时时间,因为它将返回网络中的所有可用设备,而不会排除任何设备。与使用手动超时时间不同,如果时间不合适或小于必要时间,它将不会返回所有可用设备。为了处理 Ping_Device 函数的结果,我们将使用 ,,PingDeviceCompletedEventArgs" Eventhandler,如以下代码所示

 void Ping_Completed(object sender, PingDeviceCompletedEventArgs e)
        {
            if (e.IP != null)
            {
                string ip = (string)e.IP;
                if (e.Status == PingDeviceStatus.Completed)
                {                 
                 // to do 
                }
            }
            else
            {
                // to do 
            }
        }

最后,我们将基于 IP 类 ping 所有可能的 IP。在这里,我要指出 A 类和 B 类非常耗费资源,需要花费大量时间,并且最终会触发内存不足异常。这是因为它们在短时间内将大量对象固定在内存中,因此我不建议使用 A 类和 B 类执行此函数

 void Ping_ALL_Devices(string Gateway)
        {
            string[] array = Gateway.Split('.');

            IPClass iPClass = getIPClass(Gateway);

            if (iPClass == IPClass.D)
                MessageBox.Show("Cannot Ping Multicast Address");

            if (iPClass == IPClass.E)
                MessageBox.Show("Cannot Ping Address From Class E");

            if (iPClass == IPClass.A)
            {
                for (int a = 1; a < 255; a++)
                {
                    for (int b = 1; b < 255; b++)
                    {
                        for (int c = 1; c < 255; c++)
                        {
                            string ping_var = array[0] + "." + a + "." + b + "." + c;
                            Ping_Device(ping_var);
                        }
                    }
                }
            }

            if (iPClass == IPClass.B)
            {
                for (int a = 1; a < 255; a++)
                {
                    for (int b = 1; b < 255; b++)
                    {
                        string ping_var = array[0] + "." + 
                               array[1] + "." + a + "." + b;
                        Ping_Device(ping_var);
                    }
                }
            }

            if (iPClass == IPClass.C)
            {
                for (int a = 1; a < 255; a++)
                {
                    string ping_var = array[0] + "." + 
                           array[1] + "." + array[2] + "." + a;
                    Ping_Device(ping_var);
                }
            }
        }

历史

  • 2022 年 10 月 28 日:初始版本
© . All rights reserved.