It’s been a while since I’ve gotten a blog post up, but with my CCIE recertification out of the way I’m hoping to ramp some volume back up. We’re talking about some sexy stuff today… Ping sweeps! First off, let’s cover why you’d need to sweep up your pings. Some people use the ping sweep as a means to “find” hosts on the network. The problem with this is, devices with host-based firewalls active may not respond to an ICMP ping. If you’re pinging from off the local subnet, there are other reasons you might not get a response back as well, like a host having a mis-programmed default gateway or subnet mask, or an interface ACL on the routing device. That said, ping sweeps are still incredibly useful for helping to find vacant IP addresses on a LAN. Or, at least, IP addresses that are not currently active. Always consult your properly maintained IP documentation to find IPs you can safely use for new deployments (yes, I’m laughing at that one too…).
Anyway, how do ping sweeps help identify active IPs if we can’t trust the ping responses? Well, just because a device may not respond to the ICMP echo request from the ping, the device will respond to an ARP request for its IP address on the subnet. It doesn’t have a choice, it’s a requirement for an IP(v4) stack to operate and can’t be blocked by any host firewall. (At this point I’m sure some reader will identify a situation where ARP replies can also be restricted by some means, but I’ll point out that in working on hundreds of enterprise and data center networks, I’ve never found a host that did not reply to every single ARP request it received.) So my goal of a ping sweep isn’t to get ping responses, it’s to “wake up” the ARP cache of a host or network device on the subnet so that the ARP cache can be inspected to determine what IPs are really alive. This information can then be used to identify candidate IP addresses to assign to something. In my role as a consultant often working remotely on things, the ability to propose IPs for assignment to be confirmed by the customer is usually faster than asking the customer to identify the IPs in the first place.
Some time ago, Greg Ferro posted a simple Bash script for doing a ping sweep which, if executed from on the same broadcast domain as the subnet you’re sweeping, would work just fine to populate the ARP cache of the host. The nmap tool is another great way to scan a connected subnet for live hosts. But what if you’re working remotely on a segment where you only have access to a Cisco networking device? Well, typing “ping 10.1.1.1,” then waiting for the timeouts, and then typing “ping 10.1.1.2” will get old by about the time you get to 10.1.1.4. You’d want the ability to cycle through addresses quickly.
When pinging from a Cisco router or switch, we have another trick we can use to speed things up: if the ping timeout is specified as zero, the router/switch will send an ARP request (if the MAC to IP binding has not already been resolved) followed by the pings, but not wait for any timeout of the ping itself before continuing on. I typically send two such requests to ensure I get a reply.
There is another situation that I’ve had occasion to ping a large range of addresses from the attached layer 3 switch is to refresh client ARP caches when migrating layer 3 gateway services from one device to another. In a perfect world, everything would be configured for a FHRP and/or pick up gratuitous ARP announcements when the gateway services move. In practice, it doesn’t always go down that way, so a trick to force a refresh on client ARP cache entries for the default gateway can really ease the pain of a gateway migration.
So, how do we do this CLI magic? The IOS Tcl Shell can easily be used for variable-based scripts and with some experimentation, control loops can make pinging large IP ranges fairly painless (if a bit time-consuming).
Our first example is the “classic” ping script that every CCIE candidate has memorized:
foreach ip { 4.2.2.2 8.8.8.8 8.8.4.4} { ping $ip repeat 2 timeout 1 }
This works to confirm reachability to a set of individual, known targets, but to perform a full-subnet ping sweep this way would require a lot of typing or text-editor-fu. Here it is in action. It works, just not very efficiently for our scenario where you need to hit every possible host IP.
Here is the topology I am testing with:
R1#show arp Protocol Address Age (min) Hardware Addr Type Interface Internet 192.168.14.1 - ca01.cc3c.0000 ARPA FastEthernet0/0 Internet 192.168.33.1 - ca01.cc3c.001d ARPA FastEthernet1/1 Internet 192.168.174.1 - ca01.cc3c.001c ARPA FastEthernet1/0 R1#tclsh R1(tcl)#foreach ip { +>(tcl)#192.168.14.2 +>(tcl)#192.168.14.3 +>(tcl)#192.168.14.4 +>(tcl)#192.168.14.5 +>(tcl)#192.168.14.53} { +>(tcl)#ping $ip repeat 2 timeout 1 } Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.2, timeout is 1 seconds: .. Success rate is 0 percent (0/2) Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.3, timeout is 1 seconds: .. Success rate is 0 percent (0/2) Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.4, timeout is 1 seconds: .. Success rate is 0 percent (0/2) Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.5, timeout is 1 seconds: .. Success rate is 0 percent (0/2) Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.53, timeout is 1 seconds: .! Success rate is 50 percent (1/2), round-trip min/avg/max = 32/32/32 ms R1(tcl)#exit Protocol Address Age (min) Hardware Addr Type Interface Internet 192.168.14.1 - ca01.cc3c.0000 ARPA FastEthernet0/0 Internet 192.168.14.2 0 Incomplete ARPA Internet 192.168.14.3 0 Incomplete ARPA Internet 192.168.14.4 0 Incomplete ARPA Internet 192.168.14.5 0 Incomplete ARPA Internet 192.168.14.53 0 0050.7966.6801 ARPA FastEthernet0/0 Internet 192.168.33.1 - ca01.cc3c.001d ARPA FastEthernet1/1 Internet 192.168.174.1 - ca01.cc3c.001c ARPA FastEthernet1/0
The “Incomplete” entries can be considered, with high confidence, not to be present on the network right now. The answered entries are basically guaranteed to be active on the network. Notice one of the host targets did actually sneak a response in within the “zero” timeout. That happens occasionally. Doesn’t matter.
But! Tcl can use incremented control loops, of course, like a for loop. So with just a couple lines of syntax, we can loop through an entire /24 prefix:
Loop for a whole subnet
for {set i 1} {$i < 255} {incr i} { ping 10.100.$subnet.$i re 2 ti 0
As ‘i’ is incremented, the ping command is run with the zero timeout. Then ‘i’ is incremented and the process repeats. The result looks like this:
R1#show arp Protocol Address Age (min) Hardware Addr Type Interface Internet 192.168.14.1 - ca01.cc3c.0000 ARPA FastEthernet0/0 Internet 192.168.33.1 - ca01.cc3c.001d ARPA FastEthernet1/1 Internet 192.168.174.1 - ca01.cc3c.001c ARPA FastEthernet1/0 R1#tclsh R1(tcl)#for {set i 1} {$i < 255} {incr i} { >(tcl)#ping 192.168.14.$i re 2 ti 0 >(tcl)#} Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.1, timeout is 0 seconds: !! Success rate is 100 percent (2/2), round-trip min/avg/max = 4/6/8 ms Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.2, timeout is 0 seconds: .. Success rate is 0 percent (0/2) Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.3, timeout is 0 seconds: .. Success rate is 0 percent (0/2) Type escape sequence to abort. Sending 2, 100-byte ICMP Echos to 192.168.14.4, timeout is 0 seconds: .. (THIS GOES ON FOR A WHILE) Sending 2, 100-byte ICMP Echos to 192.168.14.254, timeout is 0 seconds: .. Success rate is 0 percent (0/2) R1(tcl)#exit R1#show arp Protocol Address Age (min) Hardware Addr Type Interface Internet 192.168.14.1 - ca01.cc3c.0000 ARPA FastEthernet0/0 Internet 192.168.14.2 0 Incomplete ARPA Internet 192.168.14.3 0 Incomplete ARPA Internet 192.168.14.4 0 Incomplete ARPA Internet 192.168.14.5 0 Incomplete ARPA Internet 192.168.14.6 0 Incomplete ARPA (AGAIN, A BIG LIST OF INCOMPLETES) R1#show arp | exclude Incomplete Protocol Address Age (min) Hardware Addr Type Interface Internet 192.168.14.1 - ca01.cc3c.0000 ARPA FastEthernet0/0 Internet 192.168.14.53 0 0050.7966.6801 ARPA FastEthernet0/0 Internet 192.168.14.69 0 0050.7966.6802 ARPA FastEthernet0/0 Internet 192.168.33.1 - ca01.cc3c.001d ARPA FastEthernet1/1 Internet 192.168.174.1 - ca01.cc3c.001c ARPA FastEthernet1/0
This is much faster and more useful. Since it tries every IP in the subnet, it can also be used to “force” an ARP update of the pinging device’s MAC address in the other devices on the network.
Even this can be slow if you have a number of attached subnets, though. But the looping idea can be expanded further with nesting to produce a list of subnets which should be fully scanned. The one assumption we’re making here is that the first two octets are the same and they are all at least /24 prefixes (or, the ranges need to be specified in terms of a complete /24 at a time).
Nested loops for multiple subnets
foreach subnet { 10 11 } { for {set i 1} {$i < 255} {incr i} { ping 10.100.$subnet.$i re 2 ti 0 } }
In action:
foreach subnet { 14 33 174 } { for {set i 1} {$i < 255} {incr i} { ping 192.168.$subnet.$i re 2 ti 0 } }
It took about 5-6 seconds to scan those 3 /24s and we found every active host.
Protocol Address Age (min) Hardware Addr Type Interface Internet 192.168.14.1 - ca01.cc3c.0000 ARPA FastEthernet0/0 Internet 192.168.14.53 0 0050.7966.6801 ARPA FastEthernet0/0 Internet 192.168.14.69 0 0050.7966.6802 ARPA FastEthernet0/0 Internet 192.168.33.1 - ca01.cc3c.001d ARPA FastEthernet1/1 Internet 192.168.33.9 0 0050.7966.6805 ARPA FastEthernet1/1 Internet 192.168.33.101 0 0050.7966.6803 ARPA FastEthernet1/1 Internet 192.168.33.217 0 0050.7966.6804 ARPA FastEthernet1/1 Internet 192.168.174.1 - ca01.cc3c.001c ARPA FastEthernet1/0 Internet 192.168.174.91 0 0050.7966.6806 ARPA FastEthernet1/0 Internet 192.168.174.220 0 0050.7966.6807 ARPA FastEthernet1/0
Now, obviously there are still practical limits here. Trying to scan an attached /16 would probably take a while. Actually, I got curious after writing that last sentence and tried this:
for {set j 1} {$j < 255} {incr j} { for {set i 1} {$i < 255} {incr i} { ping 192.168.$j.$i re 2 ti 0 } }
Scanning 192.168.0.0/16 from the router took about 6 minutes. That’s actually not *so* bad. That still doesn’t make assigning connected interfaces a /16 mask a good idea!
A Real World Example
I was recently trying to identify available IPs for a single-to-dual-core conversion where we had to come up with new host IPs for each subnet for the “real” IPs of the two new core switches which would then use the existing gateway IP for the VIP. Since there were a handful of subnets to check for available IPs, and I was hoping to use the same pair of IPs in each subnet for consistency, it was easy to loop through a set of subnets, checking the .253 and .254 hosts:
foreach subnet { 170 180 190 192 200 201 204 } { for {set i 253} {$i < 255} {incr i} { ping 192.168.$subnet.$i re 2 ti 0 } } SW01#sh arp | i 253|254 Internet 192.168.180.253 0 Incomplete ARPA Internet 192.168.180.254 0 Incomplete ARPA Internet 192.168.190.254 0 Incomplete ARPA Internet 192.168.190.253 0 Incomplete ARPA Internet 192.168.170.254 0 Incomplete ARPA Internet 192.168.170.253 0 Incomplete ARPA Internet 192.168.192.253 0 Incomplete ARPA Internet 192.168.192.254 0 Incomplete ARPA Internet 192.168.204.253 0 Incomplete ARPA Internet 192.168.204.254 0 Incomplete ARPA Internet 192.168.201.253 0 Incomplete ARPA Internet 192.168.200.253 0 Incomplete ARPA Internet 192.168.200.254 0 Incomplete ARPA Internet 192.168.201.254 0 Incomplete ARPA
So, does this replace good IPAM and documentation? No, but sometimes you don’t have documentation or can’t trust the doc. Using the Tcl Shell for IP scanning can be a quick and easy way to scan a subnet or force an ARP refresh.
thanks for the great writeup! I was curious what kind of load this might put on the device you are running it on? Is this something that should really be done during off hours/maintenance window?
When I’ve used this for small scans I’ve never had it generate a problematic CPU load, but I think it’s certainly prudent to test cautiously before using in a heavily loaded environment that could be easily upset by a small CPU spike. Thanks for reading!
Very nice poste ! I like it 🙂