Search code examples
c#.netip-addresssubnetscanning

Proper way to scan a range of IP addresses


Given a range of IP addresses entered by a user (through various means), I want to identify which of these machines have software running that I can talk to.

Here's the basic process:

  1. Ping these addresses to find available machines

  2. Connect to a known socket on the available machines

  3. Send a message to the successfully established sockets

  4. Compare the response to the expected response

Steps 2-4 are straight forward for me. What is the best way to implement the first step in .NET?

I'm looking at the System.Net.NetworkInformation.Ping class. Should I ping multiple addresses simultaneously to speed up the process? If I ping one address at a time with a long timeout it could take forever. But with a small timeout, I may miss some machines that are available.

Sometimes pings appear to be failing even when I know that the address points to an active machine. Do I need to ping twice in the event of the request getting discarded?

To top it all off, when I scan large collections of addresses with the network cable unplugged, Ping throws a NullReferenceException in FreeUnmanagedResources(). !?

Any pointers on the best approach to scanning a range of IPs like this?


Solution

  • Since not all machines respond to pings (depending on firewall settings) I suggest skipping step 1 if possible.

    If you know the machines you will be connecting to respond to pings the ping class works well enough. It only sends 1 packet so ping more than once in case it gets dropped. Also, in my experience the ping class will often throw an exception instead of returning a PingReply object if the host is unreachable.

    This is my suggested implementation:

    public bool
       Ping (string host, int attempts, int timeout)
       {
          System.Net.NetworkInformation.Ping  ping = 
                                           new System.Net.NetworkInformation.Ping ();
    
          System.Net.NetworkInformation.PingReply  pingReply;
    
          for (int i = 0; i < attempts; i++)
          {
             try
             {
                pingReply = ping.Send (host, timeout); 
    
                // If there is a successful ping then return true.
                if (pingReply != null &&
                    pingReply.Status == System.Net.NetworkInformation.IPStatus.Success)
                   return true;
             }
             catch
             {
                // Do nothing and let it try again until the attempts are exausted.
                // Exceptions are thrown for normal ping failurs like address lookup
                // failed.  For this reason we are supressing errors.
             }
          }
    
          // Return false if we can't successfully ping the server after several attempts.
          return false;
       }