Network Scan with ICMP Echo Requests

It is occasionally useful to check (or scan) an IP address range for active devices. One easy method sends ICMP Echo Request packets and expects answers in the form of ICMP Echo Reply packets, like the ping program does. Sending ICMP Echo Request packets to a range of IP addresses is sometimes called a ping sweep.

Usually programs like fping, nmap, or Angry IP Scanner are used for this kind of network scan. Sometimes none of these are available, but a basic UNIX-like system is. In these circumstances (e.g., with a basic Solaris 10 install) my ping_scan shell script below can be used. If available, BASH brace expansion, seq, or jot can be used to create a list of IP addresses. prips is a small tool to generate a list of IP addresses from a range or network description. I have written a shell script named net2ips that returns all host IP addresses of a given IP network. My net2ips.py is a similar script written in Python 3 that supports both IPv4 and IPv6. My Python 3 script ipenum.py extends this to also accept range descriptions using start and end addresses.

To stress one point: ping_scan is supposed to be usable without a compiler, without root permissions, and without installation. Thus it is a shell script relying on the widely available ping program for ICMP.


ping_scan

Download

Shell script ping_scan

Requirements

The ping_scan script needs the Bash shell, a ping program like that of Solaris (tested with Solaris 10's ping and my ping_wrapper script), and a POSIX compatible sort.

Usage

ping_scan [-h] [-L] [-V] [-t TIMEOUT] [-v] [-u] [IP...]

Options

-h           print this help and exit
-t TIMEOUT   specify the timeout value used for ping (default 1s)
-v           print additional runtime info
-u           print not reachable hosts instead
-L           print license and exit
-V           print version information and exit

Description

ping_scan sends ICMP echo requests to the hosts (IP addresses) specified and prints every host that answers with an ICMP echo reply.

Specify IP addresses as command line arguments. If no IP addresses are given as arguments, IP addresses are read from STDIN, one IP address per line.

With the -u option, only hosts / IP addresses from whom no answer was received inside the timeout are printed.

Environment

The environment variable PING_WRAPPER can be used to specify a different ping program, e.g. my ping_wrapper script (see below).

Examples

$ ping_scan 8.8.8.8 8.8.4.4
8.8.4.4 is alive
8.8.8.8 is alive
$ ping_scan -v 8.8.8.8 8.8.4.4
Sending ICMP echo requests and waiting for results... (timeout 1s)
8.8.4.4 is alive
8.8.8.8 is alive
$ env PING_WRAPPER=~/bin/ping_wrapper ping_scan -v -t5 8.8.8.8 8.8.4.4
Sending ICMP echo requests and waiting for results... (timeout 5s)
8.8.4.4 is alive
8.8.8.8 is alive
$ env PING_WRAPPER=./ping_wrapper ./ping_scan -t5 -u 9.9.9.9 8.8.8.8 7.7.7.7
no answer from 7.7.7.7
$ env PING_WRAPPER=./ping_wrapper ./ping_scan -t5 -uv 9.9.9.9 8.8.8.8 7.7.7.7
Sending ICMP echo requests and waiting for results... (timeout 5s)
Printing not reachable hosts.
no answer from 7.7.7.7
$ time ping_scan 131.246.124.{65..126}
131.246.124.65 is alive
131.246.124.67 is alive
131.246.124.69 is alive
131.246.124.70 is alive
131.246.124.71 is alive
131.246.124.72 is alive
131.246.124.73 is alive
131.246.124.74 is alive
131.246.124.75 is alive
131.246.124.76 is alive
131.246.124.77 is alive
131.246.124.78 is alive
131.246.124.79 is alive
131.246.124.80 is alive
131.246.124.81 is alive
131.246.124.82 is alive
131.246.124.83 is alive
131.246.124.84 is alive
131.246.124.85 is alive
131.246.124.87 is alive
131.246.124.89 is alive
131.246.124.90 is alive
131.246.124.91 is alive
131.246.124.93 is alive
131.246.124.96 is alive
131.246.124.97 is alive
131.246.124.98 is alive
131.246.124.99 is alive
131.246.124.102 is alive
131.246.124.103 is alive
131.246.124.104 is alive
131.246.124.106 is alive
131.246.124.107 is alive
131.246.124.124 is alive
131.246.124.125 is alive
131.246.124.126 is alive

real    0m1.636s
user    0m0.116s
sys     0m1.060s

More Complex Examples

Counting Replies

$ ping_scan 131.246.124.{65..126} | wc -l
36

Comparing Pre- and Post-Change Results

$ ping_scan 192.0.2.{1..254} > pre_change_replies
$ # implement some network changes...
$ ping_scan 192.0.2.{1..254} > post_change_replies
$ diff -U0 pre_change_replies post_change_replies | egrep -v -- '^(--|\+\+|@@)'

Lines staring with '+' are new after the change, those staring with '-' are missing after the change.


ping_wrapper

The shell script ping_wrapper is intended to make the ping program from iputils, which is the most commonly used ping program on GNU/Linux systems, usable with ping_scan (see above).

Download

Shell script ping_wrapper

Usage

ping_wrapper [-n] host [timeout]

Examples

$ ping_wrapper 127.0.0.1
127.0.0.1 is alive
$ ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_req=1 ttl=64 time=0.054 ms
64 bytes from 127.0.0.1: icmp_req=2 ttl=64 time=0.045 ms
64 bytes from 127.0.0.1: icmp_req=3 ttl=64 time=0.039 ms
^C
--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.039/0.046/0.054/0.006 ms

Cut&Paste Examples for GNU/Linux Instead of ping_scan

On a modern GNU/Linux system you can use the tools installed by default for a quick enough ping scan:

$ for i in 192.168.254.{1..254}; do ping -c1 -q -W1 "$i" 2>/dev/null& sleep .01; done | fgrep -B1 '1 received'
--- 192.168.254.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
--
--- 192.168.254.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
--
--- 192.168.254.120 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
--
--- 192.168.254.121 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
--
--- 192.168.254.125 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
--
--- 192.168.254.126 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
--
--- 192.168.254.129 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
--
--- 192.168.254.130 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
To create the same output as ping_scan you can use:
$ for i in 131.246.124.{65..70}; do ping -c1 -q -W1 "$i" 2>/dev/null& sleep .01; done | sed -n '/^---/{N;s/^--- \([^ ]*\) .*\n1 [^1]*1 rec.*$/\1 is alive/p}'
131.246.124.65 is alive
131.246.124.66 is alive
131.246.124.69 is alive
131.246.124.67 is alive
131.246.124.70 is alive
To show just the hosts that do not answer to ping you can use:
$ for i in 192.0.2.{1..254}; do ping -c1 -q -W1 "$i" 2>/dev/null& sleep .01; done | sed -n '/^---/{N;s/^--- \([^ ]*\) .*\n1 [^1]*0 rec.*$/no answer from\1/p}' 
To show both answering (alive) and non-answering hosts you can use:
$ for i in 192.0.2.{1..254}; do ping -c1 -q -W1 "$i" 2>/dev/null& sleep .01; done sed -n '/^---/{N;s/^--- \([^ ]*\) .*\n1 [^1]*1 rec.*$/\1 is alive/p;s/^--- \([^ ]*\) .*\n1 [^1]*0 rec.*$/\1 does not answer/p}' | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n


Using fping

To get a similar output as ping_scan with fping (without the words is alive) use:

$ fping -a -g 172.29.29.0/24 -q -r 0
172.29.29.1
172.29.29.2
172.29.29.29
172.29.29.233


back to my homepage.