Thornton 2 dot Com
1K37L

Shellscript: Find IP Addresses on a /24 Subnet Quickly with Ping

If you connect to a small private IPv4 network and just need to find out which IP addresses are up, here's how to scan the whole network in just two or three seconds with just ping.

Example use case:

Okay, serious example use case:

My day job is ISP tech support, and that sometimes means field support for radio modems. If I get to a site and discover that the modem isn't answering on the IP address it's supposed to on the LAN interface, and if the modem isn't associating, then I need to quickly find out what IP address it thinks it has, and whether or not it's the factory default address.

A simple for-loop iterating over every possible address in the subnet and pinging it once takes five minutes or longer to run, and even nmap takes at least 15 seconds. The quicker way is to ping all of them at once, and get a list of only the one or ones that respond, in about two seconds.


In one-liner form:

seq 0 255|while read o;do(ping -c 1 192.168.0.$o >/dev/null 2>&1 &&echo $_)&done

In nicer shellscript form, saved to ~/bin/findip (for example):

#!/bin/sh

sub24="$1"

if [ -z "${sub24}" ]
  then
    echo "Usage: `basename $0` 192.168.0" >&2
    echo "    where \"192.168.0\" is the first three octets of the" >&2
    echo "    range you want to scan." >&2
    exit 1
  fi

seq 0 255 | \
while read octet
  do
    (
    ping -c 1 ${sub24}.${octet} >/dev/null 2>&1 && \
    echo "${sub24}.${octet}"
    ) &
  done

Notes:

If you're on the same /24 subnet as the range you're pinging, then you'll always get your own IP address in the list of successful pings. If you're expecting only one device, you should get two addresses.

In bash, the quick way to get a sequence of numbers is a for loop with a range, but FreeBSD's Bourne shell doesn't have that feature. Instead of for index in {<start>..<end>}; do commands; done, the same effect is made by seq <start> <end> | while read index; do commands; done.

All the ping commands are spawned as background jobs, which is where the speed comes from, and they're put in parenthetical subshells so that the IP addresses of only successful pings are shown. (In any case, both stdout and stderr from ping are devnulled so there's no other noise.)

If your shell doesn't recognize $_ (which in this case expands to the last argument of the last foreground command), or only blank lines are printed, then replace the echo $_ command with echo "${sub24}.${octet}" with the quoted string just like it appears in the ping command.