In the previous column on hacking PingPlotter I discussed how you can use the tool’s Web interface and the curl utility to add targets to be tracked, for example, to add a single host you would enter the following on the command line:
curl ‘http://192.168.1.127:81/cmd.asp?ID=NEWTARGET &target=192.168.1.254'
This assumes 192.168.1.127 is the host that’s running PingPlotter Pro with the Web server enabled and 192.168.1.254 is the host you want to monitor. Better still, a whole range of hosts can be added using sequences; for example:
curl ‘http://192.168.1.127:81/cmd.asp ID=NEWTARGET &target=192.168.[1-254].[1-254]’
But, as I pondered at the end of the previous column, how could you add only the active hosts on your network? After a bit of tinkering this is the Bash script I came up with:
#!/bin/bash
# (the previous “hash bang” line isn’t necessary under OS X)
#
# Usage: pp-prog %1 %2 %3 %4 %5
#
# %1 - first IP address octet
# %2 - second IP address octet
# %3 - third IP address octet
# %4 - start value for fourth IP address octet
# %5 - end value for fourth IP address octet
#
# Example: > pp-prog.sh 192 168 1 1 254
#
COUNT=3 # number of pings to send to each host
DOT=“.” # separator for IP address
#
a=$1$DOT$2$DOT$3$DOT # build a string of the top
# three IP address octets
for (( i=$4; i/dev/null #note 6b
else
printf "Host : $a$i is down at $(date)r” # note 7
fi
done
printf "%0.s " {1..62} # note 8a
printf "rDone.n" # note 8b
If you’re on OS X and have curl installed (see the previous column) then you can just create a file called pp-prog.sh with the above text (modified for the address of your PingPlotter host then make it executable with the command:
chmod +x pp-prog.sh
Voila! You can now configure PingPlotter for only the active hosts on your network.
Note that if you run the script again PingPlotter will add a second entry for each host the script finds which is not what you want … so, if you have a better script or even one that can run repeatedly and add newly found hosts without duplicating those already added as targets to PingPlotter or even remove hosts that go missing let me know.
Notes:
First of all, if you’re on Windows and you don’t have the Bash shell see Is there a way to run Bash scripts on Windows?
Next, here are a few notes on what the script is doing:
Note 1: This is a C-style for-loop which is easier to use with variables, in this case, $4 and $5, the start and end of the Class C network defined by $1, $2, and $3
Note 2: For OS X’s ping tool in the command:
ping -t 1 -c $COUNT $a$i
… the switch -t 1 specifies a 1 second timeout before ping exits regardless of how many packets have been received. For other systems’ ping utility the correct switch is usually -W. The output from a successful ping as above will look something like:
PING xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx): 56 data bytes 64 bytes from xxx.xxx.xxx.xxx: icmp_seq=0 ttl=64 time=0.626 ms --- xxx.xxx.xxx.xxx ping statistics --- 2 packets transmitted, 1 packets received, 50.0% packet loss round-trip min/avg/max/stddev = 0.626/0.626/0.626/0.000 ms
A failed ping will look like:
PING xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx): 56 data bytes --- xxx.xxx.xxx.xxx ping statistics --- 1 packets transmitted, 0 packets received, 100.0% packet loss
Note 3: The output from ping is piped to grep and the argument ‘received’ tells grep to send any line containing that argument text to stdout. For the successful ping example in note 1 the output from grep would be just the line:
2 packets transmitted, 1 packets received, 50.0% packet loss
A failed ping will produce:
2 packets transmitted, 0 packets received, 100.0% packet loss
Note 4: The output from grep is piped to the awk utility. The -F switch specifies the separator that divides the data items, in this case it specifies commas and the { print $2 } argument specifies that awk should output the second field; thus, from grep’s output from a successful ping awk would, in turn, output:
1 packets received
This could also be 2 or 3 packets depending on how many were received during the time set by ping’s -t switch. Obviously a failed ping would result in awk outputting:
0 packets received
The awk output is sent to a second invocation of awk which defaults to a space as a separator and is instructed to print the first field, { print $1 } , which will be either 0 for ping failed or 1,2, or 3 for ping succeeded.
Note 5: The $ in front of the parentheses around the ping, grep, and awk commands converts the value produced by the ping-grep-awk-awk commands into a value that can be stored in the variable response.
Note 6a: If the variable response does not equal “0” (i.e. one or more packets received) then print, using printf, a success status update (note the carriage return, r). This will update look like:
Host : xxx.xxx.xxx.xxx is down at Wed Jul 23 16:50:09 PDT 2014
Note 6b: … then invoke curl and send the command to PingPlotter to add a target specified by combination of variables $a$i (the variables’ current values are substituted for the placeholders). After the curl command is:
&>/dev/null
… which sends both output from the command via standard output (stdout) as well as error output to the bit bucket. If you really care about errors then feel free to modify this but for successful invocations of curl you’ll still want to get rid of the stdout output; it will just be a block of XML like this:
Note 7: If the variable response equals “0” then print an failure update:
Host : xxx.xxx.xxx.xxx is down at Wed Jul 23 16:50:09 PDT 2014
Using printf with a r appends a carriage return so that further ping failure updates will overwrite the line. This overwriting will occur until a successful update overwrites the line and then moves printing to the next line down. Note the two spaces before the r in the success update covered in note 6a; those will overwrite the last two characters of the failure message which is due to “down” being longer than “up”. Why all of this faffing about with text output? ‘Cause the updates let you know something is happening even when there’s a whole run of ping failures and it might as well look pretty.
Notes 8a & 8b: Finally, when we’ve looped through all of the IP address space we print 62 spaces to overwrite the last status message The printf that outputs the spaces is a little tricky; “%0.s “ specifies to print a zero-length string with no extra characters if the string provided is longer than zero. Then after this zero-length string print a space and there are 62 arguments, so printf prints 62 zero-length strings following each with a space. The final printf prints a carriage return, the text “Done.”, and finally a newline before exiting the script. Again, pretty is as pretty does.




