Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Network Sniffer and Analyzer Program - Part 2

4.81/5 (6 votes)
28 Oct 2022CPOL3 min read 8.1K   737  
Network Sniffer and Analyzer Program written in C# .NET 6.0 Windows Form (Sharppcap, PacketDotNet)
The program can capture and analyze DNS packets. It can also spoof ARP so that you can sniff Other Users Packets in the network. The program firstly scans the network to find connected devices in the network and then you can choose one of the found devices and sniff the incoming and the outgoing packets for this device.

Introduction

You can read the first part of this article at the following link: Network Sniffer and Analyzer Program - Part 1.

Image 1

Scan the Network to Get All Available Devices

In this part, we will learn how to get all devices available on the network and their info like the mac address, the host name, the ipv4 and the ipv6.

Actually, there are two ways to get whether a device is connected in the network or not:

The first one is to ping the target IP and then wait for a response from it and that for specific timeout and in case we get a response from it, then it's available and if we don't get a response from it, then it's not available.

The disadvantage of this method is that incoming echo request must be allowed by the target device to be able to ping the Target Device.

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

The other way is to apply the Dns.GetHostEntryAsync(hostNameOrAddress).

On the target IP, this method will get all the info about the target IP or return an error or timeout error in case the IP is not in the network.

In the following code, I will show you how to do that in an elegant way:

C#
  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();
                }
            }
    }

In the PingDevice class, we have two asynchronous functions called "SendAsych". In the second one, we will call the Dns.GetHostEntryAsync (hostNameOrAddress) function and set the 'await' keyword to it. This word will organize the event's triggering so it will prevent the executing thread from doing anything else until the target function is executed,at the end Dns.GetHostEntryAsync will find the target device and return its information or it will throw an error and return Null with the status Invalid Host. The difference between both methods is that in the first method, we have to set the timeout manually and in the second, it will be set automatically now after we define our main method to get the Available devices in the Network, we will enhance our ,,PingDeviceCompletedEventArgs" class to get all info about the found device like the host name, the mac address and the ipv6 addresses:

C#
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

To ping a single device with specific timeout, we can use the following code:

C#
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);
}

and to ping a single device with Automatic timeout, we can use the following code:

C#
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);
       }

whereas I highly recommend using an automatic timeout because it will return all available devices in the network without excluding any device unlike using a manual timeout where if the time is inappropriate or less than necessary, it will not return all available devices to handle the Ping_Device function Result we will use the ,,PingDeviceCompletedEventArgs" Eventhandler and that as in the following code:

C#
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
           }
       }

Finally, we will ping all possible Ips based on the IP class and here, I will point out that class A and B are very resource exhausted and take a lot of time and at the end, they will trigger an out of memory exception and that because they have pinned a large number of objects in memory in a short time, so I don't recommend using this function with class A and B:

C#
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);
               }
           }
       }

History

  • 28th October, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)