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.