sometimes you just need to measure network latency to specific services between sites. a common thing to do is to do an icmp (ping) test between systems. however, oftentimes your ping tests are dropped. this is what firewalls do from time to time.
a better thing to do is to initiate a half-open scan - just like what
nmap does to map services.
tcptraceroute or
hping3 are terrific tools in this regard.
however (there's always a
however) graphs and warnings and the like would be good things™ to have.
smokeping with
tcpping offers both the latter and former, respectively.
getting them to work together is another kettle of fish, entirely.
tcpping is nothing more than a wrapper script written to have tcptraceroute feed its data to smokeping. the wrapper script is below - don't forget to chmod +x it. if you're on an ubuntu or debian system, you'll need both tcptraceroute and bc. apt-get them. i like to put tccping in /usr/local/bin (because that's where i put all me-made things).
however, smokeping (if it is a really old version) doesn't always have TCPPing.pm (as you may find) thus enabling you to use this coolio probe. you can check this out by going here:
/usr/share/perl5/smokeping/Smokeping/probes/
ls the directory. if TCPPing.pm isn't there, drop in the below TCPPing.pm . Then issue:
smokeping -makepod Smokeping::probes::TCPPing
just remember that you'll need all the modules in the pm prior to doing the make pod and running smokeping and averting a myriad of errors. you can grab each of them (if you haven't them already) by issuing:
perl -MCPAN -e "install IPC::Open3" <- for instance.
now, configure smokeping appropriately. under Probes, add:
+TCPPing
binary = /usr/bin/local/tcpping
forks = 5
offset = 50%
step = 300
timeout = 15
and, as an example here's a stanza for checking both icmp and samba
++ fileservers
menu = fileservers
title = fileservers connectivity
+++ fileservold
menu = fileservers - fileserver10 (icmp)
title = fileservers - fileserver10 (icmp) - 10.0.0.10
host = 10.0.0.10
+++ fileservoldsmb
menu = fileservers - fileservold10 (smb)
title = fileservers - fileserver10 (smb) - 10.0.0.10
probe = TCPPing
host = 10.0.0.10
port = 139
tcpping
#!/bin/sh
#
# tcpping: test response times using TCP SYN packets
# URL: http://www.vdberg.org/~richard/tcpping.html
#
# uses tcptraceroute from http://michael.toren.net/code/tcptraceroute/
#
# (c) 2002-2005 Richard van den Berg under the GPL
# http://www.gnu.org/copyleft/gpl.html
#
# 2002/12/20 v1.0 initial version
# 2003/01/25 v1.1 added -c and -r options
# now accepting all other tcptraceroute options
# 2003/01/30 v1.2 removed double quotes around backquotes
# 2003/03/25 v1.3 added -x option, courtesy of Alvin Austin
# 2005/03/31 v1.4 added -C option, courtesy of Norman Rasmussen
# 2007/01/11 v1.5 catch bad destination addresses
# 2007/01/19 v1.6 catch non-root tcptraceroute
ver="v1.6"
format="%Y%m%d%H%M%S"
d="no"
c="no"
C="no"
ttl=255
seq=0
q=1
r=1
w=3
topts=""
usage () {
name=`basename $0`
echo "tcpping $ver Richard van den Berg "
echo
echo "Usage: $name [-d] [-c] [-C] [-w sec] [-q num] [-x count] ipaddress [port]"
echo
echo " -d print timestamp before every result"
echo " -c print a columned result line"
echo " -C print in the same format as fping's -C option"
echo " -w wait time in seconds (defaults to 3)"
echo " -r repeat every n seconds (defaults to 1)"
echo " -x repeat n times (defaults to unlimited)"
echo
echo "See also: man tcptraceroute"
echo
}
_checksite() {
ttr=`tcptraceroute -f ${ttl} -m ${ttl} -q ${q} -w ${w} $* 2>&1`
if echo "${ttr}" | egrep -i "(bad destination|got roo)" >/dev/null 2>&1; then
echo "${ttr}"
exit
fi
}
_testsite() {
myseq="${1}"
shift
[ "${c}" = "yes" ] && nows=`date +${format}`
[ "${d}" = "yes" ] && nowd=`date`
ttr=`tcptraceroute -f ${ttl} -m ${ttl} -q ${q} -w ${w} $* 2>/dev/null`
host=`echo "${ttr}" | awk '{print $2 " " $3}'`
if echo "${ttr}" | egrep "\[(open|closed)\]" >/dev/null 2>&1; then
rtt=`echo "${ttr}" | awk '{print $5}'`
else
rtt=`echo "${ttr}" | awk '{print $4}'`
fi
not=`echo "${rtt}" | tr -d ".0123456789"`
[ "${d}" = "yes" ] && echo "$nowd"
if [ "${c}" = "yes" ]; then
if [ "x${rtt}" != "x" -a "x${not}" = "x" ]; then
echo "$myseq $nows $rtt $host"
else
echo "$myseq $nows $max $host"
fi
elif [ "${C}" = "yes" ]; then
if [ "$myseq" = "0" ]; then
echo -n "$1 :"
fi
if [ "x${rtt}" != "x" -a "x${not}" = "x" ]; then
echo -n " $rtt"
else
echo -n " -"
fi
if [ "$x" = "1" ]; then
echo
fi
else
echo "${ttr}" | sed -e "s/^.*\*.*$/seq $myseq: no response (timeout)/" -e "s/^$ttl /seq $myseq: tcp response from/"
fi
# echo "${ttr}"
}
while getopts dhq:w:cr:nNFSAEi:f:l:m:p:s:x:C opt ; do
case "$opt" in
d|c|C) eval $opt="yes" ;;
q|w|r|x) eval $opt="$OPTARG" ;;
n|N|F|S|A|E) topt="$topt -$opt" ;;
i|l|p|s) topt="$topt -$opt $OPTARG" ;;
f|m) ttl="$OPTARG" ;;
?) usage; exit ;;
esac
done
shift `expr $OPTIND - 1`
if [ "x$1" = "x" ]; then
usage
exit
fi
max=`echo "${w} * 1000" | bc`
if [ `date +%s` != "%s" ]; then
format="%s"
fi
_checksite ${topt} $*
if [ "$x" = "" ]; then
while [ 1 ] ; do
_testsite ${seq} ${topt} $* &
pid=$!
if [ "${C}" = "yes" ]; then
wait $pid
fi
seq=`expr $seq + 1`
sleep ${r}
done
else
while [ "$x" -gt 0 ] ; do
_testsite ${seq} ${topt} $* &
pid=$!
if [ "${C}" = "yes" ]; then
wait $pid
fi
seq=`expr $seq + 1`
x=`expr $x - 1`
if [ "$x" -gt 0 ]; then
sleep ${r}
fi
done
fi
exit
TCPPing.pm
package Smokeping::probes::TCPPing;
=head1 301 Moved Permanently
This is a Smokeping probe module. Please use the command
C
to view the documentation or the command
C
to generate the POD document.
=cut
use strict;
use base qw(Smokeping::probes::basefork);
use IPC::Open3;
use Symbol;
use Carp;
sub pod_hash {
return {
name => <<'DOC',
Smokeping::probes::TCPPing - TCPPing Probe for SmokePing
DOC
description => <<'DOC',
Integrates TCPPing as a probe into smokeping. The variable B must
point to your copy of the TCPPing program. If it is not installed on
your system yet, you can get it from http://www.vdberg.org/~richard/tcpping.
You can also get it from http://www.darkskies.za.net/~norman/scripts/tcpping.
The (optional) port option lets you configure the port for the pings sent.
The TCPPing manpage has the following to say on this topic:
The problem is that with the widespread use of firewalls on the modern Internet,
many of the packets that traceroute(8) sends out end up being filtered,
making it impossible to completely trace the path to the destination.
However, in many cases, these firewalls will permit inbound TCP packets to specific
ports that hosts sitting behind the firewall are listening for connections on.
By sending out TCP SYN packets instead of UDP or ICMP ECHO packets,
tcptraceroute is able to bypass the most common firewall filters.
It is worth noting that tcptraceroute never completely establishes a TCP connection
with the destination host. If the host is not listening for incoming connections,
it will respond with an RST indicating that the port is closed. If the host instead
responds with a SYN|ACK, the port is known to be open, and an RST is sent by
the kernel tcptraceroute is running on to tear down the connection without completing
three-way handshake. This is the same half-open scanning technique that nmap(1) uses
when passed the -sS flag.
DOC
authors => <<'DOC',
Norman Rasmussen
Patched for Smokeping 2.x compatibility by Anton Chernev
DOC
}
}
sub new($$$)
{
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = $class->SUPER::new(@_);
# no need for this if we run as a cgi
unless ( $ENV{SERVER_SOFTWARE} ) {
my $return = `$self->{properties}{binary} -C -x 1 localhost 2>&1`;
if ($return =~ m/bytes, ([0-9.]+)\sms\s+.*\n.*\n.*:\s+([0-9.]+)/ and $1 > 0){
$self->{pingfactor} = 1000 * $2/$1;
print "### tcpping seems to report in ", $1/$2, " milliseconds\n";
} else {
$self->{pingfactor} = 1000; # Gives us a good-guess default
print "### assuming you are using an tcpping copy reporting in milliseconds\n";
}
};
return $self;
}
sub ProbeDesc($){
my $self = shift;
return "TCP Pings";
}
sub probevars {
my $class = shift;
return $class->_makevars($class->SUPER::probevars, {
_mandatory => [ 'binary' ],
binary => {
_doc => "The location of your TCPPing script.",
_example => '/usr/bin/tcpping',
_sub => sub {
my $val = shift;
return "ERROR: TCPPing 'binary' does not point to an executable"
unless -f $val and -x _;
my $return = `$val -C -x 1 localhost 2>&1`;
return "ERROR: TCPPing must be installed setuid root or it will not work\n"
if $return =~ m/only.+root/;
return undef;
},
},
});
}
sub targetvars {
my $class = shift;
return $class->_makevars($class->SUPER::targetvars, {
port => {
_doc => "The TCP port the probe should measure.",
_example => '80',
_sub => sub {
my $val = shift;
return "ERROR: TCPPing port must be between 0 and 65535"
if $val and ( $val < 0 or $val > 65535 );
return undef;
},
},
});
}
sub pingone ($){
my $self = shift;
my $target = shift;
# do NOT call superclass ... the ping method MUST be overwriten
my $inh = gensym;
my $outh = gensym;
my $errh = gensym;
my @times; # Result times
my @port = () ;
push @port, $target->{vars}{port} if $target->{vars}{port};
my @cmd = (
$self->{properties}{binary},
'-C', '-x', $self->pings($target),
$target->{addr}, @port);
$self->do_debug("Executing @cmd");
my $pid = open3($inh,$outh,$errh, @cmd);
while (<$outh>){
chomp;
next unless /^\S+\s+:\s+[\d\.]/; #filter out error messages from tcpping
@times = split /\s+/;
my $ip = shift @times;
next unless ':' eq shift @times; #drop the colon
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep /^\d/, @times;
}
waitpid $pid,0;
close $inh;
close $outh;
close $errh;
return @times;
}
1;