Proper way to scan a range of IP addresses

2019-06-28 08:24发布

问题:

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?

回答1:

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;
   }


回答2:

Don't forget the headache of the people who will deny pinging in their firewall rules.

My only suggestion is perhaps a question: Do you have to do #1?

Can't you simply try to connect to that known socket? Successful connection to that socket kills two birds with one stone: yes the host is there/alive, and yes, the known-socket is open.

This type of situation does lend itself well to multithreading, fire it off on another thread, and wait for it to come back with an answer...



回答3:

As many people mentioned Ping is not the best ways to detect if the machine is alive, if it is an absolute must to detect all available machine on the subnet, you could use some of the trick nmap scanner uses, to detect available machines.

You couuld use nmap -sP 192.168.2.1-200 to scan 192.168.2.0 to 192.168.2.255



回答4:

Sounds suspiciously like someone trying to write a botnet and scanning subnets for infected PCs.

There's hardly ever a reason to "detect computers on the network", let them talk to you instead when and if they want to.