commit
This commit is contained in:
357
debian/smokeping/usr/share/perl5/Smokeping/probes/AnotherCurl.pm
vendored
Normal file
357
debian/smokeping/usr/share/perl5/Smokeping/probes/AnotherCurl.pm
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
package Smokeping::probes::AnotherCurl;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::AnotherCurl>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::AnotherCurl>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Carp;
|
||||
|
||||
my $DEFAULTBIN = "/usr/bin/curl";
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => "Smokeping::probes::AnotherCurl - a curl(1) probe for SmokePing",
|
||||
overview => "Fetches an HTTP or HTTPS URL using curl(1).",
|
||||
description => "(see curl(1) for details of the options below)",
|
||||
authors => <<'DOC',
|
||||
Gerald Combs <gerald [AT] ethereal.com>
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
Jean Baptiste Favre <smokeping@jbfavre.org>
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
You should consider setting a lower value for the C<pings> variable than the
|
||||
default 20, as repetitive URL fetching may be quite heavy on the server.
|
||||
|
||||
The URL to be tested used to be specified by the variable 'url' in earlier
|
||||
versions of Smokeping, and the 'host' setting did not influence it in any
|
||||
way. The variable name has now been changed to 'urlformat', and it can
|
||||
(and in most cases should) contain a placeholder for the 'host' variable.
|
||||
|
||||
Legacy Curl probe only returns page load time. With AnotherCurl, you can
|
||||
specify which 'write-out' value you want to get (please refer to curl(1) for
|
||||
more details about write_out option.
|
||||
DOC
|
||||
see_also => "curl(1), L<http://curl.haxx.se/>",
|
||||
}
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout};
|
||||
return $class->_makevars($h, {
|
||||
binary => {
|
||||
_doc => "The location of your curl binary.",
|
||||
_default => $DEFAULTBIN,
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: Curl 'binary' $val does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'urlformat' ],
|
||||
agent => {
|
||||
_doc => <<DOC,
|
||||
The "-A" curl(1) option. This is a full HTTP User-Agent header including
|
||||
the words "User-Agent:". Note that it does not need any quotes around it.
|
||||
DOC
|
||||
_example => 'User-Agent: Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6c',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "The Curl 'agent' string does not need any quotes around it anymore."
|
||||
if $val =~ /^["']/ or $val =~ /["']$/;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
timeout => {
|
||||
_doc => qq{The "-m" curl(1) option. Maximum timeout in seconds.},
|
||||
_re => '\d+',
|
||||
_example => 20,
|
||||
_default => 10,
|
||||
},
|
||||
interface => {
|
||||
_doc => <<DOC,
|
||||
The "--interface" curl(1) option. Bind to a specific interface, IP address or
|
||||
host name.
|
||||
DOC
|
||||
_example => 'eth0',
|
||||
},
|
||||
ssl2 => {
|
||||
_doc => qq{The "-2" curl(1) option. Force SSL2.},
|
||||
_example => 1,
|
||||
},
|
||||
urlformat => {
|
||||
_doc => <<DOC,
|
||||
The template of the URL to fetch. Can be any one that curl supports.
|
||||
Any occurrence of the string '%host%' will be replaced with the
|
||||
host to be probed.
|
||||
DOC
|
||||
_example => "http://%host%/",
|
||||
},
|
||||
insecure_ssl => {
|
||||
_doc => <<DOC,
|
||||
The "-k" curl(1) option. Accept SSL connections that don't have a secure
|
||||
certificate chain to a trusted CA. Note that if you are going to monitor
|
||||
https targets, you'll probably have to either enable this option or specify
|
||||
the CA path to curl through extraargs below. For more info, see the
|
||||
curl(1) manual page.
|
||||
DOC
|
||||
_example => 1,
|
||||
},
|
||||
extrare=> {
|
||||
_doc => <<DOC,
|
||||
The regexp used to split the extraargs string into an argument list,
|
||||
in the "/regexp/" notation. This contains just the space character
|
||||
(" ") by default, but if you need to specify any arguments containing spaces,
|
||||
you can set this variable to a different value.
|
||||
DOC
|
||||
_default => "/ /",
|
||||
_example => "/ /",
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "extrare should be specified in the /regexp/ notation"
|
||||
unless $val =~ m,^/.*/$,;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
follow_redirects => {
|
||||
_doc => <<DOC,
|
||||
If this variable is set to 'yes', curl will follow any HTTP redirection steps (the '-L' option).
|
||||
If set to 'no', HTTP Location: headers will not be followed. See also 'include_redirects'.
|
||||
DOC
|
||||
_default => "no",
|
||||
_re => "(yes|no)",
|
||||
_example => "yes",
|
||||
},
|
||||
|
||||
include_redirects => {
|
||||
_doc => <<DOC,
|
||||
If this variable is set to 'yes', the measurement result will include the time
|
||||
spent on following any HTTP redirection steps. If set to 'no', only the last
|
||||
step is measured. See also 'follow_redirects'.
|
||||
DOC
|
||||
_default => "no",
|
||||
_re => "(yes|no)",
|
||||
_example => "yes",
|
||||
},
|
||||
extraargs => {
|
||||
_doc => <<DOC,
|
||||
Any extra arguments you might want to hand to curl(1). The arguments
|
||||
should be separated by the regexp specified in "extrare", which
|
||||
contains just the space character (" ") by default.
|
||||
|
||||
Note that curl will be called with the resulting list of arguments
|
||||
without any shell expansion. If you need to specify any arguments
|
||||
containing spaces, you should set "extrare" to something else.
|
||||
|
||||
As a complicated example, to explicitly set the "Host:" header in Curl
|
||||
requests, you need to set "extrare" to something else, eg. "/;/",
|
||||
and then specify C<extraargs = --header;Host: www.example.com>.
|
||||
DOC
|
||||
_example => "-6 --head --user user:password",
|
||||
},
|
||||
write_out => {
|
||||
_doc => <<DOC,
|
||||
Choose which write-out value you want to send to Smokeping. Value can
|
||||
be one of: 'time_appconnect', 'time_connect', 'time_namelookup',
|
||||
'time_pretransfer', 'time_redirect', 'time_starttransfer', 'time_total'.
|
||||
|
||||
Default behaviour is the same as legacy Curl probe one.
|
||||
DOC
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
# derived class will mess with this through the 'features' method below
|
||||
my $featurehash = {
|
||||
agent => "-A",
|
||||
timeout => "-m",
|
||||
interface => "--interface",
|
||||
};
|
||||
|
||||
sub features {
|
||||
my $self = shift;
|
||||
my $newval = shift;
|
||||
$featurehash = $newval if defined $newval;
|
||||
return $featurehash;
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
|
||||
$self->_init if $self->can('_init');
|
||||
|
||||
# no need for this if running as a CGI
|
||||
$self->test_usage unless $ENV{SERVER_SOFTWARE};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
# warn about unsupported features
|
||||
sub test_usage {
|
||||
my $self = shift;
|
||||
my $bin = $self->{properties}{binary};
|
||||
my @unsupported;
|
||||
|
||||
my $arghashref = $self->features;
|
||||
my %arghash = %$arghashref;
|
||||
my $curl_man = `$bin --help`;
|
||||
|
||||
for my $feature (keys %arghash) {
|
||||
next if $curl_man =~ /\Q$arghash{$feature}/;
|
||||
push @unsupported, $feature;
|
||||
$self->do_log("Note: your curl doesn't support the $feature feature (option $arghash{$feature}), disabling it");
|
||||
}
|
||||
map { delete $arghashref->{$_} } @unsupported;
|
||||
# if ($curl_man !~ /\stime_redirect\s/) {
|
||||
# $self->do_log("Note: your curl doesn't support the 'time_redirect' output variable; 'include_redirects' will not function.");
|
||||
# }
|
||||
return;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "URLs using curl(1)";
|
||||
}
|
||||
|
||||
# other than host, count and protocol-specific args come from here
|
||||
sub make_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args;
|
||||
my %arghash = %{$self->features};
|
||||
|
||||
for (keys %arghash) {
|
||||
my $val = $target->{vars}{$_};
|
||||
push @args, ($arghash{$_}, $val) if defined $val;
|
||||
}
|
||||
return @args;
|
||||
}
|
||||
|
||||
# This is what derived classes will override
|
||||
sub proto_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
# XXX - It would be neat if curl had a "time_transfer". For now,
|
||||
# we take the total time minus the DNS lookup time.
|
||||
my @args = ("-w", "Total: %{time_total} DNS: %{time_namelookup} Redirect: %{time_redirect} Connect: %{time_connect} Appconnect: %{time_appconnect} Pretransfert: %{time_pretransfer} Starttransfert: %{time_starttransfer}\\n");
|
||||
my $ssl2 = $target->{vars}{ssl2};
|
||||
push (@args, "-2") if $ssl2;
|
||||
my $insecure_ssl = $target->{vars}{insecure_ssl};
|
||||
push (@args, '-k') if $insecure_ssl;
|
||||
my $follow = $target->{vars}{follow_redirects};
|
||||
push (@args, '-L') if $follow eq "yes";
|
||||
|
||||
return(@args);
|
||||
}
|
||||
|
||||
sub extra_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $args = $target->{vars}{extraargs};
|
||||
return () unless defined $args;
|
||||
my $re = $target->{vars}{extrare};
|
||||
($re =~ m,^/(.*)/$,) and $re = qr{$1};
|
||||
return split($re, $args);
|
||||
}
|
||||
|
||||
sub make_commandline {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $count = shift;
|
||||
|
||||
my @args = $self->make_args($target);
|
||||
my $url = $target->{vars}{urlformat};
|
||||
my $host = $target->{addr};
|
||||
$url =~ s/%host%/$host/g;
|
||||
my @urls = split(/\s+/, $url);
|
||||
push @args, ("-o", "/dev/null") for (@urls);
|
||||
push @args, $self->proto_args($target);
|
||||
push @args, $self->extra_args($target);
|
||||
|
||||
return ($self->{properties}{binary}, @args, @urls);
|
||||
}
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $t = shift;
|
||||
|
||||
my @cmd = $self->make_commandline($t);
|
||||
|
||||
$self->do_debug("executing command list " . join(",", map { qq('$_') } @cmd));
|
||||
|
||||
my @times;
|
||||
my $count = $self->pings($t);
|
||||
|
||||
for (my $i = 0 ; $i < $count; $i++) {
|
||||
open(P, "-|") or exec @cmd;
|
||||
|
||||
my $val;
|
||||
|
||||
while (<P>) {
|
||||
chomp;
|
||||
/^Total: (\d+\.\d+) DNS: (\d+\.\d+) Redirect: (\d+\.\d+) Connect: (\d+\.\d+) Appconnect: (\d+\.\d+) Pretransfert: (\d+\.\d+) Starttransfert: (\d+\.\d+)?/ and do {
|
||||
# Total: time_total
|
||||
# DNS: time_namelookup
|
||||
# Redirect: time_redirect
|
||||
# Connect: time_connect
|
||||
# Appconnect: time_appconnect
|
||||
# Pretransfert: time_pretransfer
|
||||
# Starttransfert: time_starttransfer
|
||||
# Default is current behaviour where we take total minus DNS resolution.
|
||||
if ($t->{vars}{write_out} eq 'time_total') {$val += $1}
|
||||
elsif ($t->{vars}{write_out} eq 'time_namelookup') {$val += $2}
|
||||
elsif ($t->{vars}{write_out} eq 'time_redirect') {$val += $3}
|
||||
elsif ($t->{vars}{write_out} eq 'time_connect') {$val += $4}
|
||||
elsif ($t->{vars}{write_out} eq 'time_appconnect') {$val += $5}
|
||||
elsif ($t->{vars}{write_out} eq 'time_pretransfer') {$val += $6}
|
||||
elsif ($t->{vars}{write_out} eq 'time_starttransfer') {$val += $7}
|
||||
else {$val += $1 - $2;}
|
||||
|
||||
if ($t->{vars}{include_redirects} eq "yes" and defined $3) {
|
||||
$val += $3;
|
||||
}
|
||||
$self->do_debug("curl output: '$_', result: $val");
|
||||
};
|
||||
}
|
||||
close P;
|
||||
if ($?) {
|
||||
my $status = $? >> 8;
|
||||
my $signal = $? & 127;
|
||||
my $why = "with status $status";
|
||||
$why .= " [signal $signal]" if $signal;
|
||||
|
||||
# only log warnings on the first ping of the first ping round
|
||||
my $function = ($self->rounds_count == 1 and $i == 0) ?
|
||||
"do_log" : "do_debug";
|
||||
|
||||
$self->$function(qq(WARNING: curl exited $why on $t->{addr}));
|
||||
}
|
||||
push @times, $val if defined $val;
|
||||
}
|
||||
|
||||
# carp("Got @times") if $self->debug;
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
1;
|
||||
247
debian/smokeping/usr/share/perl5/Smokeping/probes/AnotherDNS.pm
vendored
Normal file
247
debian/smokeping/usr/share/perl5/Smokeping/probes/AnotherDNS.pm
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
package Smokeping::probes::AnotherDNS;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::AnotherDNS>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::AnotherDNS>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use IPC::Open3;
|
||||
use Symbol;
|
||||
use Carp;
|
||||
use Time::HiRes qw(sleep ualarm gettimeofday tv_interval);
|
||||
use IO::Socket;
|
||||
use IO::Select;
|
||||
use Net::DNS;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::AnotherDNS - Alternate DNS Probe
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Like DNS, but uses Net::DNS and Time::HiRes instead of dig. This probe does
|
||||
*not* retry the request three times before it is considered "lost", like dig and
|
||||
other resolver do by default. If operating as caching Nameserver, BIND (and
|
||||
maybe others) expect clients to retry the request if the answer is not in the
|
||||
cache. So, ask the nameserver for something that he is authoritative for if you
|
||||
want measure the network packet loss correctly.
|
||||
|
||||
If you have a really fast network and nameserver, you will notice that this
|
||||
probe reports the query time in microsecond resolution. :-)
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Christoph Heine <Christoph.Heine@HaDiKo.DE>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub new($$$) {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
my $self = shift;
|
||||
return "DNS requests";
|
||||
}
|
||||
|
||||
sub pingone ($) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my $host = $target->{addr};
|
||||
my $lookuphost = $target->{vars}{lookup};
|
||||
my $mininterval = $target->{vars}{mininterval};
|
||||
my $recordtype = $target->{vars}{recordtype};
|
||||
my $authoritative = $target->{vars}{authoritative};
|
||||
my $timeout = $target->{vars}{timeout};
|
||||
my $port = $target->{vars}{port};
|
||||
my $ipversion = $target->{vars}{ipversion};
|
||||
my $protocol = $target->{vars}{protocol};
|
||||
my $require_noerror = $target->{vars}{require_noerror};
|
||||
my $require_nxdomain = $target->{vars}{require_nxdomain};
|
||||
my $expect_text = $target->{vars}{expect_text};
|
||||
$lookuphost = $target->{addr} unless defined $lookuphost;
|
||||
|
||||
if ($require_nxdomain eq 1 && $require_noerror eq 1) {
|
||||
$self->do_log("ERROR: require_nxdomain and require_noerror can't both be enabled for the same target");
|
||||
return;
|
||||
}
|
||||
|
||||
my $sock = 0;
|
||||
|
||||
if ($ipversion == 6) {
|
||||
require IO::Socket::INET6;
|
||||
$sock = IO::Socket::INET6->new(
|
||||
"PeerAddr" => $host,
|
||||
"PeerPort" => $port,
|
||||
"Proto" => $protocol,
|
||||
);
|
||||
} else {
|
||||
require IO::Socket::INET;
|
||||
$sock = IO::Socket::INET->new(
|
||||
"PeerAddr" => $host,
|
||||
"PeerPort" => $port,
|
||||
"Proto" => $protocol,
|
||||
);
|
||||
}
|
||||
|
||||
my $sel = IO::Select->new($sock);
|
||||
|
||||
my @times;
|
||||
|
||||
my $elapsed;
|
||||
for ( my $run = 0 ; $run < $self->pings($target) ; $run++ ) {
|
||||
my $expectMatched = 0;
|
||||
if (defined $elapsed) {
|
||||
my $timeleft = $mininterval - $elapsed;
|
||||
sleep $timeleft if $timeleft > 0;
|
||||
}
|
||||
my $query = Net::DNS::Packet->new( $lookuphost, $recordtype );
|
||||
$query->header->rd(!$authoritative);
|
||||
my $packet = $query->data;
|
||||
my $t0 = [gettimeofday()];
|
||||
$sock->send($packet);
|
||||
my ($ready) = $sel->can_read($timeout);
|
||||
my $t1 = [gettimeofday()];
|
||||
$elapsed = tv_interval( $t0, $t1 );
|
||||
if ( defined $ready ) {
|
||||
my $buf = '';
|
||||
$ready->recv( $buf, 512 );
|
||||
my ($recvPacket, $err) = Net::DNS::Packet->new(\$buf);
|
||||
if (defined $recvPacket) {
|
||||
my $recvHeader = $recvPacket->header();
|
||||
next if $require_nxdomain && $recvHeader->rcode ne "NXDOMAIN";
|
||||
if ($expect_text ne "" && $recvHeader->ancount > 0) {
|
||||
#Test the answer RR(s) for the expected response string
|
||||
foreach ($recvPacket->answer()) {
|
||||
#$self->do_debug("Checking for $expect_text in " . $_->string);
|
||||
if (index($_->string, $expect_text) != -1) {
|
||||
$expectMatched = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
next if $expect_text ne "" && $expectMatched eq 0;
|
||||
next if $recvHeader->id != $query->header->id;
|
||||
next if $authoritative && !$recvHeader->aa;
|
||||
next if $recvHeader->ancount() < $target->{vars}{require_answers};
|
||||
if (not $require_noerror) {
|
||||
push @times, $elapsed;
|
||||
} else {
|
||||
# Check the Response Code for the NOERROR.
|
||||
if ($recvHeader->rcode() eq "NOERROR") {
|
||||
push @times, $elapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@times =
|
||||
map { sprintf "%.10e", $_ } sort { $a <=> $b } grep { $_ ne "-" } @times;
|
||||
|
||||
return @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout};
|
||||
return $h;
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
lookup => {
|
||||
_doc => <<DOC,
|
||||
Name of the host to look up in the dns.
|
||||
DOC
|
||||
_example => 'www.example.org',
|
||||
},
|
||||
mininterval => {
|
||||
_doc => <<DOC,
|
||||
Minimum time between sending two lookup queries in (possibly fractional) seconds.
|
||||
DOC
|
||||
_default => .5,
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
authoritative => {
|
||||
_doc => 'Send non-recursive queries and require authoritative answers.',
|
||||
_default => 0,
|
||||
},
|
||||
require_noerror => {
|
||||
_doc => 'Only Count Answers with Response Status NOERROR.',
|
||||
_default => 0,
|
||||
},
|
||||
require_answers => {
|
||||
_doc => 'Only Count Answers with answer count >= this value.',
|
||||
_default => 0,
|
||||
},
|
||||
recordtype => {
|
||||
_doc => 'Record type to look up.',
|
||||
_default => 'A',
|
||||
},
|
||||
timeout => {
|
||||
_doc => 'Timeout for a single request in seconds.',
|
||||
_default => 5,
|
||||
_re => '\d+',
|
||||
},
|
||||
expect_text => {
|
||||
_doc => <<DOC,
|
||||
A string that should be present in the DNS answer. This can be used
|
||||
to verify that an A record contains the expected IP address, a PTR
|
||||
record reflects the expected hostname, etc. If the query returns
|
||||
multiple records, any single match will pass the test.
|
||||
DOC
|
||||
_example => '192.168.50.60',
|
||||
},
|
||||
require_nxdomain => {
|
||||
_doc => <<DOC,
|
||||
Set to 1 if NXDOMAIN should be interpreted as success instead of
|
||||
failure. This reverses the normal behavior of the probe. Example uses
|
||||
include testing a DNS firewall, verifying that a mail server IP is
|
||||
not listed on a DNSBL, or other scenarios where NXDOMAIN is desired.
|
||||
DOC
|
||||
_default => 0,
|
||||
_example => 0,
|
||||
_re => '[01]',
|
||||
},
|
||||
port => {
|
||||
_doc => 'The UDP Port to use.',
|
||||
_default => 53,
|
||||
_re => '\d+',
|
||||
},
|
||||
protocol => {
|
||||
_doc => 'The Network Protocol to use.',
|
||||
_default => 'udp',
|
||||
_re => '(udp|UDP|tcp|TCP)',
|
||||
},
|
||||
ipversion => {
|
||||
_doc => <<DOC,
|
||||
The IP protocol used. Possible values are "4" and "6".
|
||||
Passed to echoping(1) as the "-4" or "-6" options.
|
||||
DOC
|
||||
_example => 4,
|
||||
_default => 4,
|
||||
_re => '[46]',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
238
debian/smokeping/usr/share/perl5/Smokeping/probes/AnotherSSH.pm
vendored
Normal file
238
debian/smokeping/usr/share/perl5/Smokeping/probes/AnotherSSH.pm
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
package Smokeping::probes::AnotherSSH;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::AnotherSSH>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::AnotherSSH>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Carp;
|
||||
use Time::HiRes qw(sleep ualarm gettimeofday tv_interval);
|
||||
use IO::Select;
|
||||
use Socket;
|
||||
use Fcntl;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::AnotherSSH - Another SSH probe
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Latency measurement using SSH. This generates Logfile messages on the other
|
||||
Host, so get permission from the owner first!
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Christoph Heine <Christoph.Heine@HaDiKo.DE>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub new($$$) {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
my $self = shift;
|
||||
return "SSH connections";
|
||||
}
|
||||
|
||||
sub pingone ($) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my $host = $target->{addr};
|
||||
|
||||
# Time
|
||||
my $mininterval = $target->{vars}{mininterval};
|
||||
|
||||
# Our greeting string.
|
||||
my $greeting = $target->{vars}{greeting};
|
||||
|
||||
# Interval to measure
|
||||
my $interval = $target->{vars}{interval};
|
||||
|
||||
# Connect to this port.
|
||||
my $port = $target->{vars}{port};
|
||||
|
||||
#Timeout for the select() calls.
|
||||
my $timeout = $target->{vars}{timeout};
|
||||
|
||||
my @times; # Result times
|
||||
|
||||
my $t0;
|
||||
for ( my $run = 0 ; $run < $self->pings($target) ; $run++ ) {
|
||||
if (defined $t0) {
|
||||
my $elapsed = tv_interval($t0, [gettimeofday()]);
|
||||
my $timeleft = $mininterval - $elapsed;
|
||||
sleep $timeleft if $timeleft > 0;
|
||||
}
|
||||
my ($t1,$t2,$t3); # Timestamps.
|
||||
|
||||
#Temporary variables to play with.
|
||||
my $ready;
|
||||
my $buf;
|
||||
my $nbytes;
|
||||
|
||||
my $proto = getprotobyname('tcp');
|
||||
my $iaddr = gethostbyname($host);
|
||||
my $sin = sockaddr_in( $port, $iaddr );
|
||||
socket( Socket_Handle, PF_INET, SOCK_STREAM, $proto );
|
||||
|
||||
# Make the Socket non-blocking
|
||||
my $flags = fcntl( Socket_Handle, F_GETFL, 0 ) or do {
|
||||
$self->do_debug("Can't get flags for socket: $!");
|
||||
close(Socket_Handle);
|
||||
next;
|
||||
};
|
||||
|
||||
fcntl( Socket_Handle, F_SETFL, $flags | O_NONBLOCK ) or do {
|
||||
$self->do_debug("Can't make socket nonblocking: $!");
|
||||
close(Socket_Handle); next;
|
||||
};
|
||||
|
||||
my $sel = IO::Select->new( \*Socket_Handle );
|
||||
|
||||
# connect () and measure the Time.
|
||||
$t0 = [gettimeofday()];
|
||||
connect( Socket_Handle, $sin );
|
||||
($ready) = $sel->can_read($timeout);
|
||||
$t1 = [gettimeofday()];
|
||||
|
||||
if(not defined $ready) {
|
||||
$self->do_debug("Timeout!");
|
||||
close(Socket_Handle); next;
|
||||
}
|
||||
$nbytes = sysread( Socket_Handle, $buf, 1500 );
|
||||
if (not defined $nbytes or $nbytes <= 0) {
|
||||
$self->do_debug("Read nothing and Connection closed!");
|
||||
close(Socket_Handle); next;
|
||||
}
|
||||
# $self->do_debug("Got '$buf' from remote Server");
|
||||
if (not $buf =~ m/^SSH/) {
|
||||
$self->do_debug("Not an SSH Server");
|
||||
close(Socket_Handle); next;
|
||||
}
|
||||
|
||||
($ready) = $sel->can_write($timeout);
|
||||
if (not defined($ready)) {
|
||||
$self->do_debug("Huh? Can't write.");
|
||||
close(Socket_Handle); next;
|
||||
}
|
||||
$t2 = [gettimeofday()];
|
||||
syswrite( Socket_Handle, $greeting . "\n" );
|
||||
($ready) = $sel->can_read($timeout);
|
||||
$t3 = [gettimeofday()];
|
||||
if(not defined $ready) {
|
||||
$self->do_debug("Timeout!");
|
||||
close(Socket_Handle); next;
|
||||
}
|
||||
close(Socket_Handle);
|
||||
|
||||
# We made it! Yeah!
|
||||
|
||||
if( $interval eq "connect") {
|
||||
push @times, tv_interval( $t0, $t1 );
|
||||
} elsif ( $interval eq "established") {
|
||||
push @times, tv_interval($t2,$t3);
|
||||
} elsif ($interval eq "complete") {
|
||||
push @times, tv_interval($t0,$t3);
|
||||
} else {
|
||||
$self->do_debug("You should never see this message.\n The universe will now collapse. Goodbye!\n");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@times =
|
||||
map { sprintf "%.10e", $_ } sort { $a <=> $b } grep { $_ ne "-" } @times;
|
||||
|
||||
return @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout};
|
||||
return $h;
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $e = "=";
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
greeting => {
|
||||
_doc => <<DOC,
|
||||
Greeting string to send to the SSH Server. This will appear in the Logfile.
|
||||
Use this to make clear, who you are and what you are doing to avoid confusion.
|
||||
|
||||
Also, don't use something that is a valid version string. This probe assumes
|
||||
that the connection gets terminated because of protocol mismatch.
|
||||
DOC
|
||||
_default => "SSH-Latency-Measurement-Sorry-for-this-logmessage" ,
|
||||
},
|
||||
mininterval => {
|
||||
_doc => "Minimum interval between the start of two connection attempts in (possibly fractional) seconds.",
|
||||
_default => 0.5,
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
interval => {
|
||||
_doc => <<DOC,
|
||||
The interval to be measured. One of:
|
||||
|
||||
${e}over
|
||||
|
||||
${e}item connect
|
||||
|
||||
Interval between connect() and the greeting string from the host.
|
||||
|
||||
${e}item established
|
||||
|
||||
Interval between our greeting message and the end of the connection
|
||||
because of Protocol mismatch. This is the default.
|
||||
|
||||
${e}item complete
|
||||
|
||||
From connect() to the end of the connection.
|
||||
|
||||
${e}back
|
||||
|
||||
DOC
|
||||
|
||||
_sub => sub {
|
||||
my $interval = shift;
|
||||
if(not ( $interval eq "connect"
|
||||
or $interval eq "established"
|
||||
or $interval eq "complete")) {
|
||||
return "ERROR: Invalid interval parameter";
|
||||
}
|
||||
return undef;
|
||||
},
|
||||
_default => 'established',
|
||||
},
|
||||
timeout => {
|
||||
_doc => 'Timeout for the connection.',
|
||||
_re => '\d+',
|
||||
_default => 5,
|
||||
},
|
||||
port => {
|
||||
_doc => 'Connect to this port.',
|
||||
_re => '\d+',
|
||||
_default => 22,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
300
debian/smokeping/usr/share/perl5/Smokeping/probes/CiscoRTTMonDNS.pm
vendored
Normal file
300
debian/smokeping/usr/share/perl5/Smokeping/probes/CiscoRTTMonDNS.pm
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
package Smokeping::probes::CiscoRTTMonDNS;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::CiscoRTTMonDNS>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::CiscoRTTMonDNS>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Symbol;
|
||||
use Carp;
|
||||
use BER;
|
||||
use SNMP_Session;
|
||||
use SNMP_util "0.97";
|
||||
use Smokeping::ciscoRttMonMIB "0.2";
|
||||
|
||||
my $e = "=";
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::CiscoRTTMonDNS.pm - Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
A probe for smokeping, which uses the ciscoRttMon MIB functionality ("Service Assurance Agent", "SAA") of Cisco IOS to time ( recursive, type A) DNS queries to a DNS server.
|
||||
|
||||
DOC
|
||||
|
||||
notes => <<DOC,
|
||||
${e}head2 host parameter
|
||||
|
||||
The host parameter specifies the DNS server, which the router will use.
|
||||
|
||||
${e}head2 IOS VERSIONS
|
||||
|
||||
This probe only works with IOS 12.0(3)T or higher. It is recommended to test it on less critical routers first.
|
||||
|
||||
${e}head2 INSTALLATION
|
||||
|
||||
To install this probe copy ciscoRttMonMIB.pm to (\$SMOKEPINGINSTALLDIR)/lib/Smokeping and CiscoRTTMonDNS.pm to (\$SMOKEPINGINSTALLDIR)/lib/Smokeping/probes.
|
||||
|
||||
The router(s) must be configured to allow read/write SNMP access. Sufficient is:
|
||||
|
||||
snmp-server community RTTCommunity RW
|
||||
|
||||
If you want to be a bit more restrictive with SNMP write access to the router, then consider configuring something like this
|
||||
|
||||
access-list 2 permit 10.37.3.5
|
||||
snmp-server view RttMon ciscoRttMonMIB included
|
||||
snmp-server community RTTCommunity view RttMon RW 2
|
||||
|
||||
The above configuration grants SNMP read-write only to 10.37.3.5 (the smokeping host) and only to the ciscoRttMon MIB tree. The probe does not need access to SNMP variables outside the RttMon tree.
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
The probe does unnecessary DNS queries, i.e. more than configured in the "pings" variable, because the RTTMon MIB only allows to set a total time for all queries in one measurement run (one "life"). Currently the probe sets the life duration to "pings"*5+3 seconds (5 secs is the timeout value hardcoded into this probe).
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<http://oss.oetiker.ch/smokeping/>
|
||||
|
||||
L<http://www.switch.ch/misc/leinen/snmp/perl/>
|
||||
|
||||
The best source for background info on SAA is Cisco's documentation on L<http://www.cisco.com> and the CISCO-RTTMON-MIB documentation, which is available at:
|
||||
|
||||
L<ftp://ftp.cisco.com/pub/mibs/v2/CISCO-RTTMON-MIB.my>
|
||||
DOC
|
||||
authors => <<DOC,
|
||||
Joerg.Kummer at Roche.com
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
my $pingtimeout = 5;
|
||||
|
||||
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} ) {
|
||||
$self->{pingfactor} = 1000;
|
||||
};
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
return "CiscoRTTMonDNS.pm";
|
||||
}
|
||||
|
||||
sub pingone ($$) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my $name = $target->{vars}{name};
|
||||
|
||||
my $pings = $self->pings($target) || 20;
|
||||
|
||||
# use the process ID as as row number to make this poll distinct on the router;
|
||||
my $row=$$;
|
||||
|
||||
if (defined
|
||||
StartRttMibEcho($target->{vars}{ioshost}.":::::2", $target->{addr}, $name,
|
||||
$pings, $target->{vars}{iosint}, $row))
|
||||
{
|
||||
# wait for the series to finish
|
||||
sleep ($pings*$pingtimeout+5);
|
||||
if (my @times=FillTimesFromHistoryTable($target->{vars}{ioshost}.":::::2", $pings, $row)){
|
||||
DestroyData ($target->{vars}{ioshost}.":::::2", $row);
|
||||
return @times;
|
||||
}
|
||||
else {
|
||||
return();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
sub StartRttMibEcho ($$$$$$){
|
||||
my ($host, $target, $dnsName, $pings, $sourceip, $row) = @_;
|
||||
|
||||
# resolve the target name and encode its IP address
|
||||
$_=$target;
|
||||
if (!/^([0-9]|\.)+/) {
|
||||
(my $name, my $aliases, my $addrtype, my $length, my @addrs) = gethostbyname ($target);
|
||||
$target=join('.',(unpack("C4",$addrs[0])));
|
||||
}
|
||||
my @octets=split(/\./,$target);
|
||||
my $encoded_target= pack ("CCCC", @octets);
|
||||
|
||||
# resolve the source name and encode its IP address
|
||||
my $encoded_source = undef;
|
||||
if (defined $sourceip) {
|
||||
$_=$sourceip;
|
||||
if (!/^([0-9]|\.)+/) {
|
||||
(my $name, my $aliases, my $addrtype, my $length, my @addrs) = gethostbyname ($sourceip);
|
||||
$sourceip=join('.',(unpack("C4",$addrs[0])));
|
||||
}
|
||||
my @octets=split(/\./,$sourceip);
|
||||
$encoded_source= pack ("CCCC", @octets);
|
||||
}
|
||||
|
||||
#############################################################
|
||||
# rttMonCtrlAdminStatus - 1:active 2:notInService 3:notReady 4:createAndGo 5:createAndWait 6:destroy
|
||||
#delete data from former measurements
|
||||
#return undef unless defined
|
||||
# &snmpset($host, "rttMonCtrlAdminStatus.$row",'integer', 6);
|
||||
|
||||
#############################################################
|
||||
# Check RTTMon version and supported protocols
|
||||
$SNMP_Session::suppress_warnings = 10; # be silent
|
||||
(my $version)=&snmpget ($host, "rttMonApplVersion");
|
||||
if (! defined $version ) {
|
||||
Smokeping::do_log ("$host doesn't support or allow RTTMon !\n");
|
||||
return undef;
|
||||
}
|
||||
Smokeping::do_log ("$host supports $version\n");
|
||||
$SNMP_Session::suppress_warnings = 0; # report errors
|
||||
|
||||
# echo(1), pathEcho(2), fileIO(3), script(4), udpEcho(5), tcpConnect(6), http(7),
|
||||
# dns(8), jitter(9), dlsw(10), dhcp(11), ftp(12)
|
||||
|
||||
my $DnsSupported=0==1;
|
||||
snmpmaptable ($host,
|
||||
sub () {
|
||||
my ($proto, $supported) = @_;
|
||||
# 1 is true , 2 is false
|
||||
$DnsSupported=0==0 if ($proto==8 && $supported==1);
|
||||
},
|
||||
"rttMonApplSupportedRttTypesValid");
|
||||
|
||||
if (! $DnsSupported) {
|
||||
Smokeping::do_log ("$host doesn't support DNS resolution time measurements !\n");
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
#############################################################
|
||||
#setup the new data row
|
||||
|
||||
my @params=();
|
||||
push @params,
|
||||
"rttMonCtrlAdminStatus.$row", 'integer', 5,
|
||||
"rttMonCtrlAdminRttType.$row", 'integer', 8,
|
||||
"rttMonEchoAdminProtocol.$row", 'integer', 26,
|
||||
"rttMonEchoAdminNameServer.$row", 'octetstring', $encoded_target,
|
||||
"rttMonEchoAdminTargetAddressString.$row",'octetstring', $dnsName,
|
||||
"rttMonCtrlAdminTimeout.$row", 'integer', $pingtimeout*1000,
|
||||
"rttMonCtrlAdminFrequency.$row", 'integer', $pingtimeout,
|
||||
"rttMonCtrlAdminNvgen.$row", 'integer', 2,
|
||||
"rttMonHistoryAdminNumBuckets.$row", 'integer', $pings,
|
||||
"rttMonHistoryAdminNumLives.$row", 'integer', 1,
|
||||
"rttMonHistoryAdminFilter.$row", 'integer', 2,
|
||||
"rttMonScheduleAdminRttStartTime.$row", 'timeticks', 1,
|
||||
"rttMonScheduleAdminRttLife.$row", 'integer', $pings*$pingtimeout+3,
|
||||
"rttMonScheduleAdminConceptRowAgeout.$row",'integer', 60;
|
||||
|
||||
# the router (or this script) doesn't check whether the IP address is one of
|
||||
# the router's IP address, i.e. the router might send packets, but never
|
||||
# gets replies..
|
||||
if (defined $sourceip) {
|
||||
push @params, "rttMonEchoAdminSourceAddress.$row", 'octetstring', $encoded_source;
|
||||
}
|
||||
|
||||
return undef unless defined
|
||||
&snmpset($host, @params);
|
||||
|
||||
#############################################################
|
||||
# and go !
|
||||
return undef unless defined
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row",'integer',1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# RttResponseSense values
|
||||
# 1:ok 2:disconnected 3:overThreshold 4:timeout 5:busy 6:notConnected 7:dropped 8:sequenceError
|
||||
# 9:verifyError 10:applicationSpecific 11:dnsServerTimeout 12:tcpConnectTimeout 13:httpTransactionTimeout
|
||||
#14:dnsQueryError 15:httpError 16:error
|
||||
|
||||
sub FillTimesFromHistoryTable($$$$) {
|
||||
my ($host, $pings, $row) = @_;
|
||||
my @times;
|
||||
|
||||
# snmpmaptable walks two tables (of equal size)
|
||||
# - "rttMonHistoryCollectionCompletionTime.$row",
|
||||
# - "rttMonHistoryCollectionSense.$row"
|
||||
# The code in the sub() argument is executed for each index value snmptable walks
|
||||
|
||||
snmpmaptable ($host,
|
||||
sub () {
|
||||
my ($index, $rtt, $status) = @_;
|
||||
push @times, (sprintf ("%.10e", $rtt/1000))
|
||||
if ($status==1);
|
||||
},
|
||||
"rttMonHistoryCollectionCompletionTime.$row",
|
||||
"rttMonHistoryCollectionSense.$row");
|
||||
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub DestroyData ($$) {
|
||||
my ($host, $row) = @_;
|
||||
|
||||
&snmpset($host, "rttMonCtrlOperState.$row", 'integer', 3);
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 2);
|
||||
#delete any old config
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 6);
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'ioshost', 'name' ],
|
||||
ioshost => {
|
||||
_doc => <<DOC,
|
||||
The (mandatory) ioshost parameter specifies the Cisco router, which will send the DNS requests,
|
||||
as well as the SNMP community string on the router.
|
||||
DOC
|
||||
_example => 'RTTcommunity@Myrouter.foobar.com.au',
|
||||
},
|
||||
name => {
|
||||
_doc => "The (mandatory) name parameter is the DNS name to resolve.",
|
||||
_example => 'www.foobar.com.au',
|
||||
},
|
||||
timeout => {
|
||||
_re => '\d+',
|
||||
_example => 15,
|
||||
_default => $pingtimeout+10,
|
||||
_doc => "How long a single RTTMonDNS 'ping' take at maximum plus 10 seconds to spare. Since we control our own timeout the only purpose of this is to not have us killed by the ping method from basefork.",
|
||||
},
|
||||
iosint => {
|
||||
_doc => <<DOC,
|
||||
The (optional) iosint parameter is the source address for the DNS packets.
|
||||
This should be one of the active (!) IP addresses of the router to get
|
||||
results. IOS looks up the target host address in the forwarding table
|
||||
and then uses the interface(s) listed there to send the DNS packets. By
|
||||
default IOS uses the (primary) IP address on the sending interface as
|
||||
source address for packets originated by the router.
|
||||
DOC
|
||||
_example => '10.33.22.11',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
=head1
|
||||
1;
|
||||
|
||||
334
debian/smokeping/usr/share/perl5/Smokeping/probes/CiscoRTTMonEchoICMP.pm
vendored
Normal file
334
debian/smokeping/usr/share/perl5/Smokeping/probes/CiscoRTTMonEchoICMP.pm
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
package Smokeping::probes::CiscoRTTMonEchoICMP;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::CiscoRTTMonEchoICMP>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::CiscoRTTMonEchoICMP>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Symbol;
|
||||
use Carp;
|
||||
use BER;
|
||||
use SNMP_Session;
|
||||
use SNMP_util "0.97";
|
||||
use Smokeping::ciscoRttMonMIB "0.2";
|
||||
|
||||
sub pod_hash {
|
||||
my $e = "=";
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::CiscoRTTMonEchoICMP - Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
A probe for smokeping, which uses the ciscoRttMon MIB functionality ("Service Assurance Agent", "SAA") of Cisco IOS to measure ICMP echo ("ping") roundtrip times between a Cisco router and any IP address.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
${e}head2 IOS VERSIONS
|
||||
|
||||
It is highly recommended to use this probe with routers running IOS 12.0(3)T or higher and to test it on less critical routers first. I managed to crash a router with 12.0(9) quite consistently ( in IOS lingo 12.0(9) is older code than 12.0(3)T ). I did not observe crashes on higher IOS releases, but messages on the router like the one below, when multiple processes concurrently accessed the same router (this case was IOS 12.1(12b) ):
|
||||
|
||||
Aug 20 07:30:14: %RTT-3-SemaphoreBadUnlock: %RTR: Attempt to unlock semaphore by wrong RTR process 70, locked by 78
|
||||
|
||||
Aug 20 07:35:15: %RTT-3-SemaphoreInUse: %RTR: Could not obtain a lock for RTR. Process 80
|
||||
|
||||
|
||||
${e}head2 INSTALLATION
|
||||
|
||||
To install this probe copy ciscoRttMonMIB.pm files to (\$SMOKEPINGINSTALLDIR)/lib/Smokeping and CiscoRTTMonEchoICMP.pm to (\$SMOKEPINGINSTALLDIR)/lib/Smokeping/probes. V0.97 or higher of Simon Leinen's SNMP_Session.pm is required.
|
||||
|
||||
The router(s) must be configured to allow read/write SNMP access. Sufficient is:
|
||||
|
||||
snmp-server community RTTCommunity RW
|
||||
|
||||
If you want to be a bit more restrictive with SNMP write access to the router, then consider configuring something like this
|
||||
|
||||
access-list 2 permit 10.37.3.5
|
||||
snmp-server view RttMon ciscoRttMonMIB included
|
||||
snmp-server community RTTCommunity view RttMon RW 2
|
||||
|
||||
The above configuration grants SNMP read-write only to 10.37.3.5 (the smokeping host) and only to the ciscoRttMon MIB tree. The probe does not need access to SNMP variables outside the RttMon tree.
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
The probe sends unnecessary pings, i.e. more than configured in the "pings" variable, because the RTTMon MIB only allows to set a total time for all pings in one measurement run (one "life"). Currently the probe sets the life duration to "pings"*5+3 seconds (5 secs is the ping timeout value hardcoded into this probe).
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<http://oss.oetiker.ch/smokeping/>
|
||||
|
||||
L<http://www.switch.ch/misc/leinen/snmp/perl/>
|
||||
|
||||
The best source for background info on SAA is Cisco's documentation on L<http://www.cisco.com> and the CISCO-RTTMON-MIB documentation, which is available at:
|
||||
L<ftp://ftp.cisco.com/pub/mibs/v2/CISCO-RTTMON-MIB.my>
|
||||
DOC
|
||||
authors => <<DOC,
|
||||
Joerg.Kummer at Roche.com
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
my $pingtimeout = 5;
|
||||
|
||||
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} ) {
|
||||
$self->{pingfactor} = 1000;
|
||||
};
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
return "CiscoRTTMonEchoICMP";
|
||||
}
|
||||
|
||||
sub pingone ($$) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my $pings = $self->pings($target) || 20;
|
||||
my $tos = $target->{vars}{tos};
|
||||
my $bytes = $target->{vars}{packetsize};
|
||||
|
||||
# use the process ID as as row number to make this poll distinct on the router;
|
||||
my $row=$$;
|
||||
|
||||
if (defined
|
||||
StartRttMibEcho($target->{vars}{ioshost}.":::::2", $target->{addr},
|
||||
$bytes, $pings, $target->{vars}{iosint}, $tos, $row, $target->{vars}{vrf}))
|
||||
{
|
||||
# wait for the series to finish
|
||||
sleep ($pings*$pingtimeout+5);
|
||||
if (my @times=FillTimesFromHistoryTable($target->{vars}{ioshost}.":::::2", $pings, $row)){
|
||||
DestroyData ($target->{vars}{ioshost}.":::::2", $row);
|
||||
return @times;
|
||||
}
|
||||
else {
|
||||
return();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
sub StartRttMibEcho ($$$$$$){
|
||||
my ($host, $target, $size, $pings, $sourceip, $tos, $row,$vrf) = @_;
|
||||
|
||||
# resolve the target name and encode its IP address
|
||||
$_=$target;
|
||||
if (!/^([0-9]|\.)+/) {
|
||||
(my $name, my $aliases, my $addrtype, my $length, my @addrs) = gethostbyname ($target);
|
||||
$target=join('.',(unpack("C4",$addrs[0])));
|
||||
}
|
||||
my @octets=split(/\./,$target);
|
||||
my $encoded_target= pack ("CCCC", @octets);
|
||||
|
||||
# resolve the source name and encode its IP address
|
||||
my $encoded_source = undef;
|
||||
if (defined $sourceip) {
|
||||
$_=$sourceip;
|
||||
if (!/^([0-9]|\.)+/) {
|
||||
(my $name, my $aliases, my $addrtype, my $length, my @addrs) = gethostbyname ($sourceip);
|
||||
$sourceip=join('.',(unpack("C4",$addrs[0])));
|
||||
}
|
||||
my @octets=split(/\./,$sourceip);
|
||||
$encoded_source= pack ("CCCC", @octets);
|
||||
}
|
||||
|
||||
#############################################################
|
||||
# rttMonCtrlAdminStatus - 1:active 2:notInService 3:notReady 4:createAndGo 5:createAndWait 6:destroy
|
||||
#delete data from former measurements
|
||||
#return undef unless defined
|
||||
# &snmpset($host, "rttMonCtrlAdminStatus.$row",'integer', 6);
|
||||
|
||||
#############################################################
|
||||
# Check RTTMon version and supported protocols
|
||||
$SNMP_Session::suppress_warnings = 10; # be silent
|
||||
(my $version)=&snmpget ($host, "rttMonApplVersion");
|
||||
if (! defined $version ) {
|
||||
Smokeping::do_log ("$host doesn't support or allow RTTMon !\n");
|
||||
return undef;
|
||||
}
|
||||
Smokeping::do_log ("$host supports $version\n");
|
||||
$SNMP_Session::suppress_warnings = 0; # report errors
|
||||
|
||||
# echo(1), pathEcho(2), fileIO(3), script(4), udpEcho(5), tcpConnect(6), http(7),
|
||||
# dns(8), jitter(9), dlsw(10), dhcp(11), ftp(12)
|
||||
my $udpEchoSupported=0==1;
|
||||
snmpmaptable ($host,
|
||||
sub () {
|
||||
my ($proto, $supported) = @_;
|
||||
# 1 is true , 2 is false
|
||||
$udpEchoSupported=0==0 if ($proto==5 && $supported==1);
|
||||
},
|
||||
"rttMonApplSupportedRttTypesValid");
|
||||
|
||||
#############################################################
|
||||
#setup the new data row
|
||||
|
||||
my @params=();
|
||||
push @params,
|
||||
"rttMonCtrlAdminStatus.$row", 'integer', 5,
|
||||
"rttMonCtrlAdminRttType.$row", 'integer', 1,
|
||||
"rttMonEchoAdminProtocol.$row", 'integer', 2,
|
||||
"rttMonEchoAdminTargetAddress.$row", 'octetstring', $encoded_target,
|
||||
"rttMonCtrlAdminTimeout.$row", 'integer', $pingtimeout*1000,
|
||||
"rttMonCtrlAdminFrequency.$row", 'integer', $pingtimeout,
|
||||
"rttMonHistoryAdminNumBuckets.$row", 'integer', $pings,
|
||||
"rttMonHistoryAdminNumLives.$row", 'integer', 1,
|
||||
"rttMonHistoryAdminFilter.$row", 'integer', 2,
|
||||
"rttMonEchoAdminPktDataRequestSize.$row",'integer', $size-8,
|
||||
"rttMonScheduleAdminRttStartTime.$row", 'timeticks', 1,
|
||||
"rttMonScheduleAdminRttLife.$row", 'integer', $pings*$pingtimeout+3,
|
||||
"rttMonScheduleAdminConceptRowAgeout.$row",'integer', 60;
|
||||
|
||||
if(defined($vrf)){
|
||||
push @params,"rttMonEchoAdminVrfName.$row",'octetstring',$vrf;
|
||||
}
|
||||
|
||||
# with udpEcho support (>= 12.0(3)T ) the ICMP ping support was enhanced in the RTTMon SW - we are
|
||||
# NOT using udpEcho, but echo (ICMP echo, ping)
|
||||
if ($udpEchoSupported) {
|
||||
push @params, "rttMonEchoAdminTOS.$row", 'integer', $tos;
|
||||
push @params, "rttMonCtrlAdminNvgen.$row", 'integer', 2;
|
||||
|
||||
# the router (or this script) doesn't check whether the IP address is one of
|
||||
# the router's IP address, i.e. the router might send packets, but never
|
||||
# gets ping replies..
|
||||
if (defined $sourceip) {
|
||||
push @params, "rttMonEchoAdminSourceAddress.$row", 'octetstring', $encoded_source;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Smokeping::do_log ("Warning this host does not support ToS or iosint\n");
|
||||
}
|
||||
|
||||
return undef unless defined
|
||||
&snmpset($host, @params);
|
||||
|
||||
#############################################################
|
||||
# and go !
|
||||
return undef unless defined
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row",'integer',1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# RttResponseSense values
|
||||
# 1:ok 2:disconnected 3:overThreshold 4:timeout 5:busy 6:notConnected 7:dropped 8:sequenceError
|
||||
# 9:verifyError 10:applicationSpecific 11:dnsServerTimeout 12:tcpConnectTimeout 13:httpTransactionTimeout
|
||||
#14:dnsQueryError 15:httpError 16:error
|
||||
|
||||
sub FillTimesFromHistoryTable($$$$) {
|
||||
my ($host, $pings, $row) = @_;
|
||||
my @times;
|
||||
|
||||
# snmpmaptable walks two tables (of equal size)
|
||||
# - "rttMonHistoryCollectionCompletionTime.$row",
|
||||
# - "rttMonHistoryCollectionSense.$row"
|
||||
# The code in the sub() argument is executed for each index value snmptable walks
|
||||
snmpmaptable ($host,
|
||||
sub () {
|
||||
my ($index, $rtt, $status) = @_;
|
||||
push @times, (sprintf ("%.10e", $rtt/1000))
|
||||
if ($status==1);
|
||||
},
|
||||
"rttMonHistoryCollectionCompletionTime.$row",
|
||||
"rttMonHistoryCollectionSense.$row");
|
||||
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub DestroyData ($$) {
|
||||
my ($host, $row) = @_;
|
||||
|
||||
&snmpset($host, "rttMonCtrlOperState.$row", 'integer', 3);
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 2);
|
||||
#delete any old config
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 6);
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'ioshost' ],
|
||||
ioshost => {
|
||||
_example => 'RTTcommunity@Myrouter.foobar.com.au',
|
||||
_doc => <<DOC,
|
||||
The (mandatory) ioshost parameter specifies the Cisco router, which will
|
||||
execute the pings, as well as the SNMP community string on the router.
|
||||
DOC
|
||||
},
|
||||
timeout => {
|
||||
_re => '\d+',
|
||||
_example => 15,
|
||||
_default => $pingtimeout+10,
|
||||
_doc => "How long a single RTTMonEcho ICMP 'ping' take at maximum plus 10 seconds to spare. Since we control our own timeout the only purpose of this is to not have us killed by the ping method from basefork.",
|
||||
},
|
||||
iosint => {
|
||||
_example => '10.33.22.11',
|
||||
_doc => <<DOC,
|
||||
The (optional) iosint parameter is the source address for the pings
|
||||
sent. This should be one of the active (!) IP addresses of the router to
|
||||
get results. IOS looks up the target host address in the forwarding table
|
||||
and then uses the interface(s) listed there to send the ping packets. By
|
||||
default IOS uses the (primary) IP address on the sending interface as
|
||||
source address for a ping. The RTTMon MIB versions before IOS 12.0(3)T
|
||||
didn't support this parameter.
|
||||
DOC
|
||||
},
|
||||
tos => {
|
||||
_example => 160,
|
||||
_default => 0,
|
||||
_doc => <<DOC,
|
||||
The (optional) tos parameter specifies the value of the ToS byte in
|
||||
the IP header of the pings. Multiply DSCP values times 4 and Precedence
|
||||
values times 32 to calculate the ToS values to configure, e.g. ToS 160
|
||||
corresponds to a DSCP value 40 and a Precedence value of 5. The RTTMon
|
||||
MIB versions before IOS 12.0(3)T didn't support this parameter.
|
||||
DOC
|
||||
},
|
||||
vrf => {
|
||||
_example => "INTERNET",
|
||||
_doc => <<DOC,
|
||||
The the VPN name in which the RTT operation will be used. For regular RTT
|
||||
operation this field should not be configured. The agent
|
||||
will use this field to identify the VPN routing Table for
|
||||
this operation.
|
||||
DOC
|
||||
},
|
||||
packetsize => {
|
||||
_doc => <<DOC,
|
||||
The packetsize parameter lets you configure the packetsize for the pings
|
||||
sent. The minimum is 8, the maximum 16392. Use the same number as with
|
||||
fping, if you want the same packet sizes being used on the network.
|
||||
DOC
|
||||
_default => 56,
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: packetsize must be between 8 and 16392"
|
||||
unless $val >= 8 and $val <= 16392;
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
311
debian/smokeping/usr/share/perl5/Smokeping/probes/CiscoRTTMonTcpConnect.pm
vendored
Normal file
311
debian/smokeping/usr/share/perl5/Smokeping/probes/CiscoRTTMonTcpConnect.pm
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
package Smokeping::probes::CiscoRTTMonTcpConnect;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::CiscoRTTMonTcpConnect>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::CiscoRTTMonTcpConnect>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Symbol;
|
||||
use Carp;
|
||||
use BER;
|
||||
use SNMP_Session;
|
||||
use SNMP_util "0.97";
|
||||
use Smokeping::ciscoRttMonMIB "0.2";
|
||||
|
||||
sub pod_hash {
|
||||
my $e = "=";
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::CiscoRTTMonTcpConnect - Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
A probe for smokeping, which uses the ciscoRttMon MIB functionality ("Service Assurance Agent", "SAA") of Cisco IOS to measure TCP connect times between a Cisco router and a TCP server. The measured value is the time is the time to establish a TCP session, i.e. the time between the initial "SYN" TCP packet of the router and the "SYN ACK" packet of the host. The router terminates the TCP session immediately after the reception of "SYN ACK" with a "FIN" packet.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
${e}head2 IOS VERSIONS
|
||||
|
||||
This probe only works with Cisco IOS 12.0(3)T or higher. It is recommended to test it on less critical routers first.
|
||||
|
||||
${e}head2 INSTALLATION
|
||||
|
||||
To install this probe copy ciscoRttMonMIB.pm to (\$SMOKEPINGINSTALLDIR)/Smokeping/lib and CiscoRTTMonTcpConnect.pm to (\$SMOKEPINGINSTALLDIR)/lib/Smokeping/probes. V0.97 or higher of Simon Leinen's SNMP_Session.pm is required.
|
||||
|
||||
The router(s) must be configured to allow read/write SNMP access. Sufficient is:
|
||||
|
||||
snmp-server community RTTCommunity RW
|
||||
|
||||
If you want to be a bit more restrictive with SNMP write access to the router, then consider configuring something like this
|
||||
|
||||
access-list 2 permit 10.37.3.5
|
||||
snmp-server view RttMon ciscoRttMonMIB included
|
||||
snmp-server community RTTCommunity view RttMon RW 2
|
||||
|
||||
The above configuration grants SNMP read-write only to 10.37.3.5 (the smokeping host) and only to the ciscoRttMon MIB tree. The probe does not need access to SNMP variables outside the RttMon tree.
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
The probe establishes unnecessary connections, i.e. more than configured in the "pings" variable, because the RTTMon MIB only allows to set a total time for all connections in one measurement run (one "life"). Currently the probe sets the life duration to "pings"*5+3 seconds (5 secs is the timeout value hardcoded into this probe).
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<http://oss.oetiker.ch/smokeping/>
|
||||
|
||||
L<http://www.switch.ch/misc/leinen/snmp/perl/>
|
||||
|
||||
The best source for background info on SAA is Cisco's documentation on L<http://www.cisco.com> and the CISCO-RTTMON-MIB documentation, which is available at:
|
||||
L<ftp://ftp.cisco.com/pub/mibs/v2/CISCO-RTTMON-MIB.my>
|
||||
DOC
|
||||
authors => <<DOC,
|
||||
Joerg.Kummer at Roche.com
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
my $pingtimeout = 5;
|
||||
|
||||
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} ) {
|
||||
$self->{pingfactor} = 1000;
|
||||
};
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
return "CiscoRTTMonTcpConnect";
|
||||
}
|
||||
|
||||
sub pingone ($$) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my $pings = $self->pings($target) || 20;
|
||||
my $tos = $target->{vars}{tos};
|
||||
my $port = $target->{vars}{port};
|
||||
|
||||
# use the process ID as as row number to make this poll distinct on the router;
|
||||
my $row=$$;
|
||||
|
||||
if (defined
|
||||
StartRttMibEcho($target->{vars}{ioshost}.":::::2", $target->{addr}, $port,
|
||||
$pings, $target->{vars}{iosint}, $tos, $row))
|
||||
{
|
||||
# wait for the series to finish
|
||||
sleep ($pings*$pingtimeout+5);
|
||||
if (my @times=FillTimesFromHistoryTable($target->{vars}{ioshost}.":::::2", $pings, $row)){
|
||||
DestroyData ($target->{vars}{ioshost}.":::::2", $row);
|
||||
return @times;
|
||||
}
|
||||
else {
|
||||
return();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
sub StartRttMibEcho ($$$$$$){
|
||||
my ($host, $target, $port, $pings, $sourceip, $tos, $row) = @_;
|
||||
|
||||
# resolve the target name and encode its IP address
|
||||
$_=$target;
|
||||
if (!/^([0-9]|\.)+/) {
|
||||
(my $name, my $aliases, my $addrtype, my $length, my @addrs) = gethostbyname ($target);
|
||||
$target=join('.',(unpack("C4",$addrs[0])));
|
||||
}
|
||||
my @octets=split(/\./,$target);
|
||||
my $encoded_target= pack ("CCCC", @octets);
|
||||
|
||||
# resolve the source name and encode its IP address
|
||||
my $encoded_source = undef;
|
||||
if (defined $sourceip) {
|
||||
$_=$sourceip;
|
||||
if (!/^([0-9]|\.)+/) {
|
||||
(my $name, my $aliases, my $addrtype, my $length, my @addrs) = gethostbyname ($sourceip);
|
||||
$sourceip=join('.',(unpack("C4",$addrs[0])));
|
||||
}
|
||||
my @octets=split(/\./,$sourceip);
|
||||
$encoded_source= pack ("CCCC", @octets);
|
||||
}
|
||||
|
||||
#############################################################
|
||||
# rttMonCtrlAdminStatus - 1:active 2:notInService 3:notReady 4:createAndGo 5:createAndWait 6:destroy
|
||||
#delete data from former measurements
|
||||
#return undef unless defined
|
||||
# &snmpset($host, "rttMonCtrlAdminStatus.$row",'integer', 6);
|
||||
|
||||
#############################################################
|
||||
# Check RTTMon version and supported protocols
|
||||
$SNMP_Session::suppress_warnings = 10; # be silent
|
||||
(my $version)=&snmpget ($host, "rttMonApplVersion");
|
||||
if (! defined $version ) {
|
||||
Smokeping::do_log ("$host doesn't support or allow RTTMon !\n");
|
||||
return undef;
|
||||
}
|
||||
Smokeping::do_log ("$host supports $version\n");
|
||||
$SNMP_Session::suppress_warnings = 0; # report errors
|
||||
|
||||
# echo(1), pathEcho(2), fileIO(3), script(4), udpEcho(5), tcpConnect(6), http(7),
|
||||
# dns(8), jitter(9), dlsw(10), dhcp(11), ftp(12)
|
||||
|
||||
my $tcpConnSupported=0==1;
|
||||
snmpmaptable ($host,
|
||||
sub () {
|
||||
my ($proto, $supported) = @_;
|
||||
# 1 is true , 2 is false
|
||||
$tcpConnSupported=0==0 if ($proto==6 && $supported==1);
|
||||
},
|
||||
"rttMonApplSupportedRttTypesValid");
|
||||
|
||||
if (! $tcpConnSupported) {
|
||||
Smokeping::do_log ("$host doesn't support TCP connection time measurements !\n");
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
#############################################################
|
||||
#setup the new data row
|
||||
|
||||
my @params=();
|
||||
push @params,
|
||||
"rttMonCtrlAdminStatus.$row", 'integer', 5,
|
||||
"rttMonCtrlAdminRttType.$row", 'integer', 6,
|
||||
"rttMonEchoAdminProtocol.$row", 'integer', 24,
|
||||
"rttMonEchoAdminTargetAddress.$row", 'octetstring', $encoded_target,
|
||||
"rttMonEchoAdminTargetPort.$row", 'integer', $port,
|
||||
"rttMonCtrlAdminTimeout.$row", 'integer', $pingtimeout*1000,
|
||||
"rttMonCtrlAdminFrequency.$row", 'integer', $pingtimeout,
|
||||
"rttMonEchoAdminControlEnable.$row", 'integer', 2,
|
||||
"rttMonEchoAdminTOS.$row", 'integer', $tos,
|
||||
"rttMonCtrlAdminNvgen.$row", 'integer', 2,
|
||||
"rttMonHistoryAdminNumBuckets.$row", 'integer', $pings,
|
||||
"rttMonHistoryAdminNumLives.$row", 'integer', 1,
|
||||
"rttMonHistoryAdminFilter.$row", 'integer', 2,
|
||||
"rttMonScheduleAdminRttStartTime.$row", 'timeticks', 1,
|
||||
"rttMonScheduleAdminRttLife.$row", 'integer', $pings*$pingtimeout+3,
|
||||
"rttMonScheduleAdminConceptRowAgeout.$row",'integer', 60;
|
||||
|
||||
# the router (or this script) doesn't check whether the IP address is one of
|
||||
# the router's IP address, i.e. the router might send packets, but never
|
||||
# gets replies..
|
||||
if (defined $sourceip) {
|
||||
push @params, "rttMonEchoAdminSourceAddress.$row", 'octetstring', $encoded_source;
|
||||
}
|
||||
|
||||
return undef unless defined
|
||||
&snmpset($host, @params);
|
||||
|
||||
#############################################################
|
||||
# and go !
|
||||
return undef unless defined
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row",'integer',1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# RttResponseSense values
|
||||
# 1:ok 2:disconnected 3:overThreshold 4:timeout 5:busy 6:notConnected 7:dropped 8:sequenceError
|
||||
# 9:verifyError 10:applicationSpecific 11:dnsServerTimeout 12:tcpConnectTimeout 13:httpTransactionTimeout
|
||||
#14:dnsQueryError 15:httpError 16:error
|
||||
|
||||
sub FillTimesFromHistoryTable($$$$) {
|
||||
my ($host, $pings, $row) = @_;
|
||||
my @times;
|
||||
|
||||
# snmpmaptable walks two columns of rttMonHistoryCollectionTable
|
||||
# - "rttMonHistoryCollectionCompletionTime.$row",
|
||||
# - "rttMonHistoryCollectionSense.$row"
|
||||
# The code in the sub() argument is executed for each index value snmptable walks
|
||||
snmpmaptable ($host,
|
||||
sub () {
|
||||
my ($index, $rtt, $status) = @_;
|
||||
push @times, (sprintf ("%.10e", $rtt/1000))
|
||||
if ($status==1);
|
||||
},
|
||||
"rttMonHistoryCollectionCompletionTime.$row",
|
||||
"rttMonHistoryCollectionSense.$row");
|
||||
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub DestroyData ($$) {
|
||||
my ($host, $row) = @_;
|
||||
|
||||
&snmpset($host, "rttMonCtrlOperState.$row", 'integer', 3);
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 2);
|
||||
#delete any old config
|
||||
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 6);
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'ioshost' ],
|
||||
ioshost => {
|
||||
_example => 'RTTcommunity@Myrouter.foobar.com.au',
|
||||
_doc => <<DOC,
|
||||
The (mandatory) ioshost parameter specifies the Cisco router, which will
|
||||
establish the TCP connections as well as the SNMP community string on
|
||||
the router.
|
||||
DOC
|
||||
},
|
||||
port => {
|
||||
_default => 80,
|
||||
_re => '\d+',
|
||||
_doc => <<DOC,
|
||||
The (optional) port parameter lets you configure the destination TCP
|
||||
port on the host. The default is the http port 80.
|
||||
DOC
|
||||
},
|
||||
timeout => {
|
||||
_re => '\d+',
|
||||
_example => 15,
|
||||
_default => $pingtimeout+10,
|
||||
_doc => "How long a single RTTMon TcpConnect 'ping' take at maximum plus 10 seconds to spare. Since we control our own timeout the only purpose of this is to not have us killed by the ping method from basefork.",
|
||||
},
|
||||
iosint => {
|
||||
_example => '10.33.22.11',
|
||||
_doc => <<DOC,
|
||||
The (optional) iosint parameter is the source address for the TCP
|
||||
connections. This should be one of the active (!) IP addresses of the
|
||||
router to get results. IOS looks up the target host address in the
|
||||
forwarding table and then uses the interface(s) listed there to send
|
||||
the TCP packets. By default IOS uses the (primary) IP address on the
|
||||
sending interface as source address for a connection.
|
||||
DOC
|
||||
},
|
||||
tos => {
|
||||
_default => 0,
|
||||
_example => 160,
|
||||
_re => '\d+',
|
||||
_doc => <<DOC,
|
||||
The (optional) tos parameter specifies the value of the ToS byte in the
|
||||
IP header of the packets from the router. Multiply DSCP values times 4
|
||||
and Precedence values times 32 to calculate the ToS values to configure,
|
||||
e.g. ToS 160 corresponds to a DSCP value 40 and a Precedence value of
|
||||
5. Please note that this will not influence the ToS value in the packets
|
||||
sent by the the host.
|
||||
DOC
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
352
debian/smokeping/usr/share/perl5/Smokeping/probes/Curl.pm
vendored
Normal file
352
debian/smokeping/usr/share/perl5/Smokeping/probes/Curl.pm
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
package Smokeping::probes::Curl;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::Curl>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::Curl>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Carp;
|
||||
|
||||
my $DEFAULTBIN = "/usr/bin/curl";
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => "Smokeping::probes::Curl - a curl(1) probe for SmokePing",
|
||||
overview => "Fetches an HTTP or HTTPS URL using curl(1).",
|
||||
description => "(see curl(1) for details of the options below)",
|
||||
authors => <<'DOC',
|
||||
Gerald Combs <gerald [AT] ethereal.com>
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
You should consider setting a lower value for the C<pings> variable than the
|
||||
default 20, as repetitive URL fetching may be quite heavy on the server.
|
||||
|
||||
The URL to be tested used to be specified by the variable 'url' in earlier
|
||||
versions of Smokeping, and the 'host' setting did not influence it in any
|
||||
way. The variable name has now been changed to 'urlformat', and it can
|
||||
(and in most cases should) contain a placeholder for the 'host' variable.
|
||||
DOC
|
||||
see_also => "curl(1), L<http://curl.haxx.se/>",
|
||||
}
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout};
|
||||
return $class->_makevars($h, {
|
||||
binary => {
|
||||
_doc => "The location of your curl binary.",
|
||||
_default => $DEFAULTBIN,
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: Curl 'binary' $val does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'urlformat' ],
|
||||
agent => {
|
||||
_doc => <<DOC,
|
||||
The "-A" curl(1) option. This is a full HTTP User-Agent header including
|
||||
the words "User-Agent:". Note that it does not need any quotes around it.
|
||||
DOC
|
||||
_example => 'User-Agent: Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6c',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "The Curl 'agent' string does not need any quotes around it anymore."
|
||||
if $val =~ /^["']/ or $val =~ /["']$/;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
timeout => {
|
||||
_doc => qq{The "-m" curl(1) option. Maximum timeout in seconds.},
|
||||
_re => '\d+',
|
||||
_example => 20,
|
||||
_default => 10,
|
||||
},
|
||||
interface => {
|
||||
_doc => <<DOC,
|
||||
The "--interface" curl(1) option. Bind to a specific interface, IP address or
|
||||
host name.
|
||||
DOC
|
||||
_example => 'eth0',
|
||||
},
|
||||
ssl2 => {
|
||||
_doc => qq{The "-2" curl(1) option. Force SSL2.},
|
||||
_example => 1,
|
||||
},
|
||||
urlformat => {
|
||||
_doc => <<DOC,
|
||||
The template of the URL to fetch. Can be any one that curl supports.
|
||||
Any occurrence of the string '%host%' will be replaced with the
|
||||
host to be probed.
|
||||
DOC
|
||||
_example => "http://%host%/",
|
||||
},
|
||||
insecure_ssl => {
|
||||
_doc => <<DOC,
|
||||
The "-k" curl(1) option. Accept SSL connections that don't have a secure
|
||||
certificate chain to a trusted CA. Note that if you are going to monitor
|
||||
https targets, you'll probably have to either enable this option or specify
|
||||
the CA path to curl through extraargs below. For more info, see the
|
||||
curl(1) manual page.
|
||||
DOC
|
||||
_example => 1,
|
||||
},
|
||||
extrare=> {
|
||||
_doc => <<DOC,
|
||||
The regexp used to split the extraargs string into an argument list,
|
||||
in the "/regexp/" notation. This contains just the space character
|
||||
(" ") by default, but if you need to specify any arguments containing spaces,
|
||||
you can set this variable to a different value.
|
||||
DOC
|
||||
_default => "/ /",
|
||||
_example => "/ /",
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "extrare should be specified in the /regexp/ notation"
|
||||
unless $val =~ m,^/.*/$,;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
follow_redirects => {
|
||||
_doc => <<DOC,
|
||||
If this variable is set to 'yes', curl will follow any HTTP redirection steps (the '-L' option).
|
||||
If set to 'no', HTTP Location: headers will not be followed. See also 'include_redirects'.
|
||||
DOC
|
||||
_default => "no",
|
||||
_re => "(yes|no)",
|
||||
_example => "yes",
|
||||
},
|
||||
|
||||
include_redirects => {
|
||||
_doc => <<DOC,
|
||||
If this variable is set to 'yes', the measurement result will include the time
|
||||
spent on following any HTTP redirection steps. If set to 'no', only the last
|
||||
step is measured. See also 'follow_redirects'.
|
||||
DOC
|
||||
_default => "no",
|
||||
_re => "(yes|no)",
|
||||
_example => "yes",
|
||||
},
|
||||
extraargs => {
|
||||
_doc => <<DOC,
|
||||
Any extra arguments you might want to hand to curl(1). The arguments
|
||||
should be separated by the regexp specified in "extrare", which
|
||||
contains just the space character (" ") by default.
|
||||
|
||||
Note that curl will be called with the resulting list of arguments
|
||||
without any shell expansion. If you need to specify any arguments
|
||||
containing spaces, you should set "extrare" to something else.
|
||||
|
||||
As a complicated example, to explicitly set the "Host:" header in Curl
|
||||
requests, you need to set "extrare" to something else, eg. "/;/",
|
||||
and then specify C<extraargs = --header;Host: www.example.com>.
|
||||
DOC
|
||||
_example => "-6 --head --user user:password",
|
||||
},
|
||||
expect => {
|
||||
_doc => <<DOC,
|
||||
Require the given text to appear somewhere in the response, otherwise
|
||||
probe is treated as a failure
|
||||
DOC
|
||||
_default => "",
|
||||
_example => "Status: green",
|
||||
},
|
||||
require_zero_status => {
|
||||
_doc => <<DOC,
|
||||
If this variable is set to 'yes', responses will only be counted if
|
||||
Curl's exit status is '0'. This is useful for reporting timeouts as
|
||||
losses rather than delayed responses.
|
||||
DOC
|
||||
_default => "no",
|
||||
_re => "(yes|no)",
|
||||
_example => "yes",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
# derived class will mess with this through the 'features' method below
|
||||
my $featurehash = {
|
||||
agent => "-A",
|
||||
timeout => "-m",
|
||||
interface => "--interface",
|
||||
};
|
||||
|
||||
sub features {
|
||||
my $self = shift;
|
||||
my $newval = shift;
|
||||
$featurehash = $newval if defined $newval;
|
||||
return $featurehash;
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
|
||||
$self->_init if $self->can('_init');
|
||||
|
||||
# no need for this if running as a CGI
|
||||
$self->test_usage unless $ENV{SERVER_SOFTWARE};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
# warn about unsupported features
|
||||
sub test_usage {
|
||||
my $self = shift;
|
||||
my $bin = $self->{properties}{binary};
|
||||
my @unsupported;
|
||||
|
||||
my $arghashref = $self->features;
|
||||
my %arghash = %$arghashref;
|
||||
my $curl_man = `$bin --help all`;
|
||||
|
||||
for my $feature (keys %arghash) {
|
||||
next if $curl_man =~ /\Q$arghash{$feature}/;
|
||||
push @unsupported, $feature;
|
||||
$self->do_log("Note: your curl doesn't support the $feature feature (option $arghash{$feature}), disabling it");
|
||||
}
|
||||
map { delete $arghashref->{$_} } @unsupported;
|
||||
# if ($curl_man !~ /\stime_redirect\s/) {
|
||||
# $self->do_log("Note: your curl doesn't support the 'time_redirect' output variable; 'include_redirects' will not function.");
|
||||
# }
|
||||
return;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "URLs using curl(1)";
|
||||
}
|
||||
|
||||
# other than host, count and protocol-specific args come from here
|
||||
sub make_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args;
|
||||
my %arghash = %{$self->features};
|
||||
|
||||
for (keys %arghash) {
|
||||
my $val = $target->{vars}{$_};
|
||||
push @args, ($arghash{$_}, $val) if defined $val;
|
||||
}
|
||||
return @args;
|
||||
}
|
||||
|
||||
# This is what derived classes will override
|
||||
sub proto_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
# XXX - It would be neat if curl had a "time_transfer". For now,
|
||||
# we take the total time minus the DNS lookup time.
|
||||
my @args = ("-w", "Time: %{time_total} DNS time: %{time_namelookup} Redirect time: %{time_redirect}\\n");
|
||||
my $ssl2 = $target->{vars}{ssl2};
|
||||
push (@args, "-2") if $ssl2;
|
||||
my $insecure_ssl = $target->{vars}{insecure_ssl};
|
||||
push (@args, '-k') if $insecure_ssl;
|
||||
my $follow = $target->{vars}{follow_redirects};
|
||||
push (@args, '-L') if $follow eq "yes";
|
||||
|
||||
return(@args);
|
||||
}
|
||||
|
||||
sub extra_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $args = $target->{vars}{extraargs};
|
||||
return () unless defined $args;
|
||||
my $re = $target->{vars}{extrare};
|
||||
($re =~ m,^/(.*)/$,) and $re = qr{$1};
|
||||
return split($re, $args);
|
||||
}
|
||||
|
||||
sub make_commandline {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $count = shift;
|
||||
|
||||
my @args = $self->make_args($target);
|
||||
my $url = $target->{vars}{urlformat};
|
||||
my $host = $target->{addr};
|
||||
$url =~ s/%host%/$host/g;
|
||||
my @urls = split(/\s+/, $url);
|
||||
# push @args, ("-o", "/dev/null") for (@urls);
|
||||
push @args, $self->proto_args($target);
|
||||
push @args, $self->extra_args($target);
|
||||
|
||||
return ($self->{properties}{binary}, @args, @urls);
|
||||
}
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $t = shift;
|
||||
|
||||
my @cmd = $self->make_commandline($t);
|
||||
|
||||
$self->do_debug("executing command list " . join(",", map { qq('$_') } @cmd));
|
||||
|
||||
my @times;
|
||||
my $count = $self->pings($t);
|
||||
|
||||
for (my $i = 0 ; $i < $count; $i++) {
|
||||
open(P, "-|") or exec @cmd;
|
||||
|
||||
my $val;
|
||||
my $expectOK = 1;
|
||||
$expectOK = 0 if ($t->{vars}{expect} ne "");
|
||||
|
||||
while (<P>) {
|
||||
chomp;
|
||||
if (!$expectOK and index($_, $t->{vars}{expect}) != -1) {
|
||||
$expectOK = 1;
|
||||
}
|
||||
/Time: (\d+\.\d+) DNS time: (\d+\.\d+) Redirect time: (\d+\.\d+)?/ and do {
|
||||
$val += $1 - $2;
|
||||
if ($t->{vars}{include_redirects} eq "yes" and defined $3) {
|
||||
$val += $3;
|
||||
}
|
||||
$self->do_debug("curl output: '$_', result: $val");
|
||||
};
|
||||
}
|
||||
close P;
|
||||
if ($?) {
|
||||
my $status = $? >> 8;
|
||||
my $signal = $? & 127;
|
||||
my $why = "with status $status";
|
||||
$why .= " [signal $signal]" if $signal;
|
||||
|
||||
# only log warnings on the first ping of the first ping round
|
||||
my $function = ($self->rounds_count == 1 and $i == 0) ?
|
||||
"do_log" : "do_debug";
|
||||
|
||||
$self->$function(qq(WARNING: curl exited $why on $t->{addr}));
|
||||
}
|
||||
if ($? == 0 or $t->{vars}{require_zero_status} eq "no") {
|
||||
push @times, $val if (defined $val and $expectOK);
|
||||
}
|
||||
}
|
||||
|
||||
# carp("Got @times") if $self->debug;
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
1;
|
||||
142
debian/smokeping/usr/share/perl5/Smokeping/probes/DNS.pm
vendored
Normal file
142
debian/smokeping/usr/share/perl5/Smokeping/probes/DNS.pm
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
package Smokeping::probes::DNS;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::DNS>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::DNS>
|
||||
|
||||
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::DNS - Name Service Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates dig as a probe into smokeping. The variable B<binary> must
|
||||
point to your copy of the dig program. If it is not installed on
|
||||
your system yet, you should install bind-utils >= 9.0.0.
|
||||
|
||||
The Probe asks the given host n-times for it's name. Where n is
|
||||
the amount specified in the config File.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Igor Petrovski <pigor@myrealbox.com>,
|
||||
Carl Elkins <carl@celkins.org.uk>,
|
||||
Andre Stolze <stolze@uni-muenster.de>,
|
||||
Niko Tyni <ntyni@iki.fi>,
|
||||
Chris Poetzel<cpoetzel@anl.gov>
|
||||
DOC
|
||||
};
|
||||
}
|
||||
|
||||
my $dig_re=qr/query time:\s+([0-9.]+)\smsec.*/i;
|
||||
|
||||
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 $call = "$self->{properties}{binary} localhost";
|
||||
my $return = `$call 2>&1`;
|
||||
if ($return =~ m/$dig_re/s){
|
||||
$self->{pingfactor} = 1000;
|
||||
print "### parsing dig output...OK\n";
|
||||
} else {
|
||||
croak "ERROR: output of '$call' does not match $dig_re\n";
|
||||
}
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'binary' ],
|
||||
binary => {
|
||||
_doc => "The location of your dig binary.",
|
||||
_example => '/usr/bin/dig',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: DNS 'binary' does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
lookup => { _doc => "Name of the host to look up in the dns.",
|
||||
_example => "www.example.org",
|
||||
},
|
||||
server => { _doc => "Name of the dns server to use.",
|
||||
_example => "ns1.someisp.net",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
return "DNS requests";
|
||||
}
|
||||
|
||||
sub pingone ($){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my $inh = gensym;
|
||||
my $outh = gensym;
|
||||
my $errh = gensym;
|
||||
|
||||
my $host = $target->{addr};
|
||||
my $lookuphost = $target->{vars}{lookup};
|
||||
$lookuphost = $target->{addr} unless defined $lookuphost;
|
||||
my $dnsserver = $target->{vars}{server} || $host;
|
||||
my $query = "$self->{properties}{binary} \@$dnsserver $lookuphost";
|
||||
|
||||
my @times;
|
||||
|
||||
$self->do_debug("query=$query\n");
|
||||
for (my $run = 0; $run < $self->pings($target); $run++) {
|
||||
my $pid = open3($inh,$outh,$errh, $query);
|
||||
while (<$outh>) {
|
||||
if (/$dig_re/i) {
|
||||
push @times, $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
waitpid $pid,0;
|
||||
my $rc = $?;
|
||||
carp "$query returned with exit code $rc. run with debug enabled to get more information" unless $rc == 0;
|
||||
close $errh;
|
||||
close $inh;
|
||||
close $outh;
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep {$_ ne "-"} @times;
|
||||
|
||||
# $self->do_debug("time=@times\n");
|
||||
return @times;
|
||||
}
|
||||
|
||||
1;
|
||||
451
debian/smokeping/usr/share/perl5/Smokeping/probes/DismanPing.pm
vendored
Normal file
451
debian/smokeping/usr/share/perl5/Smokeping/probes/DismanPing.pm
vendored
Normal file
@@ -0,0 +1,451 @@
|
||||
package Smokeping::probes::DismanPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::DismanPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::DismanPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basevars);
|
||||
use SNMP_Session "1.13";
|
||||
use SNMP_util "1.13";
|
||||
use Smokeping::pingMIB "0.1";
|
||||
use Socket;
|
||||
use Net::Domain qw(hostname);
|
||||
|
||||
sub pod_hash {
|
||||
my $e = "=";
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::DismanPing - DISMAN-PING-MIB Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Uses the DISMAN-PING-MIB to cause a remote system to send probes.
|
||||
DOC
|
||||
authors => <<DOC,
|
||||
Bill Fenner <fenner\@research.att.com>,
|
||||
Tobi Oetiker <tobi\@oetiker.ch>
|
||||
DOC
|
||||
credits => <<DOC,
|
||||
This structure of this probe module is heavily based on
|
||||
L<Smokeping::probes::CiscoRTTMonEchoICMP|Smokeping::probes::CiscoRTTMonEchoICMP>
|
||||
by Joerg.Kummer at Roche.com.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
${e}head2 MENU NAMES
|
||||
|
||||
This probe uses the menu name of a test as part of the unique
|
||||
index. If the menu name is longer than 32 characters, the last
|
||||
32 characters are used for the index. Collisions are *B<not>*
|
||||
detected and simply cause one test's results to be used for
|
||||
all colliding names.
|
||||
|
||||
${e}head2 CONFIGURATION
|
||||
|
||||
This probe requires read/write access to the pingCtlTable.
|
||||
It also requires read-only access to the pingResultsTable and the
|
||||
pingHistoryTable. The DISMAN-PING-MIB is structured such that
|
||||
it is possible to restrict by pingCtlOwnerIndex. This probe
|
||||
uses a pingCtlOwnerIndex of "SP on hostname"
|
||||
as ownerindex by default; use B<ownerindex> to configure this if needed.
|
||||
|
||||
${e}head2 SAMPLE JUNOS CONFIGURATION
|
||||
|
||||
This configuration permits the community "pinger" read-write
|
||||
access to the full DISMAN-PING-MIB, but only when sourced
|
||||
from the manager at B<192.0.2.134>.
|
||||
|
||||
snmp {
|
||||
view pingMIB {
|
||||
oid .1.3.6.1.2.1.80 include;
|
||||
}
|
||||
community pinger {
|
||||
view pingMIB;
|
||||
authorization read-write;
|
||||
clients {
|
||||
192.0.2.134/32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${e}head2 SAMPLE CONFIGURATIONS NOTE
|
||||
|
||||
This configuration allows the "pinger" community full access to the
|
||||
DISMAN-PING-MIB. There is information in the description of
|
||||
B<pingCtlOwnerIndex> in RFC 4560 (L<http://tools.ietf.org/html/rfc4560>)
|
||||
about using the vacmViewTreeFamilyTable to further restrict access.
|
||||
The author has not tried this method.
|
||||
DOC
|
||||
|
||||
#${e}head2 SAMPLE IOS CONFIGURATION
|
||||
#
|
||||
#Note: I have no clue if IOS supports DISMAN-PING-MIB.
|
||||
#
|
||||
# access-list 2 permit 192.0.2.134
|
||||
# snmp-server view pingMIB .1.3.6.1.2.1.80 included
|
||||
# snmp-server community pinger view pingMIB RW 2
|
||||
#
|
||||
};
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
|
||||
# This is structured a little differently than the
|
||||
# average probe. _makevars prefers values from the
|
||||
# first argument, but we have to override the superclass's
|
||||
# pings value. So, we put our values in the first argument.
|
||||
# However, _makevars modifies its second argument, and we
|
||||
# don't want to modify the superclass's value, so we
|
||||
# make a copy in $tmp.
|
||||
my $tmp = { %{ $class->SUPER::probevars } };
|
||||
return $class->_makevars(
|
||||
{
|
||||
pings => {
|
||||
_re => '\d+',
|
||||
_default => 15,
|
||||
_example => 15,
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return
|
||||
"ERROR: for DismanPing, pings must be between 1 and 15."
|
||||
unless $val >= 1 and $val <= 15;
|
||||
return undef;
|
||||
},
|
||||
_doc => <<DOC,
|
||||
How many pings should be sent to each target. Note that the maximum value
|
||||
for DismanPing MIP is 15, which is less than the SmokePing default, so this
|
||||
class has its own default value. If your Database section specifies a
|
||||
value less than 15, you must also set it for this probe.
|
||||
Note that the number of pings in
|
||||
the RRD files is fixed when they are originally generated, and if you
|
||||
change this parameter afterwards, you'll have to delete the old RRD
|
||||
files or somehow convert them.
|
||||
DOC
|
||||
},
|
||||
},
|
||||
$tmp
|
||||
);
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars(
|
||||
$class->SUPER::targetvars,
|
||||
{
|
||||
_mandatory => ['pinghost'],
|
||||
ownerindex => {
|
||||
_doc => <<DOC,
|
||||
The SNMP OwnerIndex to use when setting up the test.
|
||||
When using VACM, can map to a Security Name or Group Name
|
||||
of the entity running the test.
|
||||
|
||||
By default this will be set to
|
||||
|
||||
DOC
|
||||
_example => "smokeping"
|
||||
},
|
||||
pinghost => {
|
||||
_example => 'pinger@router.example.com',
|
||||
_doc => <<DOC,
|
||||
The (mandatory) pinghost parameter specifies the remote system which will
|
||||
execute the pings, as well as the SNMP community string on the device.
|
||||
DOC
|
||||
},
|
||||
pingsrc => {
|
||||
_example => '192.0.2.9',
|
||||
_doc => <<DOC,
|
||||
The (optional) pingsrc parameter specifies the source address to be used
|
||||
for pings. If specified, this parameter must identify an IP address
|
||||
assigned to pinghost.
|
||||
DOC
|
||||
},
|
||||
|
||||
# tos => {
|
||||
# _example => 160,
|
||||
# _default => 0,
|
||||
# _doc => <<DOC,
|
||||
#The (optional) tos parameter specifies the value of the ToS byte in
|
||||
#the IP header of the pings. Multiply DSCP values times 4 and Precedence
|
||||
#values times 32 to calculate the ToS values to configure, e.g. ToS 160
|
||||
#corresponds to a DSCP value 40 and a Precedence value of 5.
|
||||
#DOC
|
||||
# },
|
||||
packetsize => {
|
||||
_doc => <<DOC,
|
||||
The packetsize parameter lets you configure the packet size for the pings
|
||||
sent. The minimum is 8, the maximum 65507. Use the same number as with
|
||||
fping if you want the same packet sizes being used on the network.
|
||||
DOC
|
||||
_default => 56,
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: packetsize must be between 8 and 65507"
|
||||
unless $val >= 8 and $val <= 65507;
|
||||
return undef;
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
# XXX
|
||||
# This is copied from basefork.pm; it actually belongs
|
||||
# in basevars.pm.
|
||||
sub pod_variables {
|
||||
my $class = shift;
|
||||
my $pod = $class->SUPER::pod_variables;
|
||||
my $targetvars = $class->targetvars;
|
||||
$pod .= "Supported target-specific variables:\n\n";
|
||||
$pod .= $class->_pod_variables($targetvars);
|
||||
return $pod;
|
||||
}
|
||||
|
||||
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} ) {
|
||||
|
||||
# Initialization stuff that might take time
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize} || 56;
|
||||
return "DISMAN ICMP Echo Pings ($bytes Bytes)";
|
||||
}
|
||||
|
||||
# RFC 4560:
|
||||
# A single SNMP PDU can be used to create and start a remote
|
||||
# ping test. Within the PDU, pingCtlTargetAddress should be set to the
|
||||
# target host's address (pingCtlTargetAddressType will default to
|
||||
# ipv4(1)), pingCtlAdminStatus to enabled(1), and pingCtlRowStatus to
|
||||
# createAndGo(4).
|
||||
#
|
||||
# At least one implementation doesn't implement a default for
|
||||
# pingCtlTargetAddressType (and the MIB itself doesn't specify
|
||||
# such a default)
|
||||
#
|
||||
# Philosophically, I'd like to just leave the row there and
|
||||
# re-enable the test if the row is there - but there's no easy
|
||||
# way to verify that the values haven't changed since the last
|
||||
# time we set it.
|
||||
sub ping($) {
|
||||
my $self = shift;
|
||||
my $pending = {};
|
||||
my $longest = 0;
|
||||
my $start = time;
|
||||
|
||||
# Empty out any RTTs from the last round. Otherwise, if we get an
|
||||
# SNMP error for a target, we'll report his last result.
|
||||
$self->{rtts} = {};
|
||||
|
||||
foreach my $t ( @{ $self->targets } ) {
|
||||
my $addr = $t->{addr};
|
||||
my $idx = idx($t);
|
||||
my $host = host($t);
|
||||
|
||||
# Delete any existing row. Ignore error.
|
||||
#Smokeping::do_log("DismanPing deleting for $host $t->{vars}{menu}");
|
||||
my $ret =
|
||||
snmpset( $host, "pingCtlRowStatus.$idx", "integer", 6 ); #destroy
|
||||
|
||||
if ( !defined($ret) ) {
|
||||
my ( $err ) = ( $SNMP_Session::errmsg =~ /error status: (\S+)/ );
|
||||
my $msgmap = {
|
||||
'notWritable' => 'does the remote support DISMAN-PING-MIB?',
|
||||
'inconsistentValue' => 'is an old ping running?',
|
||||
'noAccess' => 'is access control set up properly?'
|
||||
};
|
||||
if ( !defined( $err ) ) {
|
||||
# errmsg can have arbitrary text on the first line.
|
||||
$err = "SNMP error";
|
||||
}
|
||||
# SNMP::Session already carp()d errmsg, so don't include it here.
|
||||
# It's already in the log.
|
||||
Smokeping::do_log( "DismanPing: got $err trying to clean up $t->{vars}{host}" .
|
||||
( $msgmap->{ $err } ? " -- " . $msgmap->{ $err } : "" ) );
|
||||
next;
|
||||
}
|
||||
|
||||
my $targetaddr = inet_aton($addr);
|
||||
if ( not defined $targetaddr ) {
|
||||
Smokeping::do_log("DismanPing can't resolve destination address $addr for $t->{vars}{host}");
|
||||
next;
|
||||
}
|
||||
|
||||
#XXX consider ipv6 - esp. what does inet_aton() return
|
||||
#XXX todo: test failure handling code by setting ProbeCOunt and MaxRows
|
||||
# differently than pings
|
||||
my @values = (
|
||||
"pingCtlTargetAddressType.$idx", "integer", 1, #ipv4
|
||||
"pingCtlTargetAddress.$idx", "octetstring", $targetaddr,
|
||||
"pingCtlFrequency.$idx", "gauge", 0, # run test only once
|
||||
"pingCtlTimeOut.$idx", "gauge", 3, # timeout ping after 3 seconds (this is also the interval for sending pings)
|
||||
"pingCtlProbeCount.$idx", "gauge", $t->{vars}{pings},
|
||||
"pingCtlMaxRows.$idx", "gauge", $t->{vars}{pings},
|
||||
"pingCtlAdminStatus.$idx", "integer", 1, #enabled
|
||||
"pingCtlRowStatus.$idx", "integer", 4, #createAndGo
|
||||
);
|
||||
|
||||
# add pingsrc, packetsize into @values if defined
|
||||
if ( defined $t->{vars}{packetsize} ) {
|
||||
unshift( @values,
|
||||
"pingCtlDataSize.$idx", "gauge", $t->{vars}{packetsize} );
|
||||
}
|
||||
if ( defined $t->{vars}{pingsrc} ) {
|
||||
my $srcaddr = inet_aton( $t->{vars}{pingsrc} );
|
||||
if ( not defined $srcaddr ) {
|
||||
Smokeping::do_log("WARNING: DismanPing can't resolve source address $t->{vars}{pingsrc} for $t->{vars}{host}");
|
||||
}
|
||||
else {
|
||||
unshift(
|
||||
@values,
|
||||
"pingCtlSourceAddressType.$idx", "integer", 1, #ipv4
|
||||
"pingCtlSourceAddress.$idx", "octetstring", $srcaddr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# Todo: pingCtlDSField.
|
||||
# Todo: pingCtlTimeout.
|
||||
my @snmpsetret;
|
||||
if ( ( @snmpsetret = snmpset( $host, @values ) )
|
||||
and defined $snmpsetret[0] ) {
|
||||
$pending->{ $t->{tree} } = 1;
|
||||
}
|
||||
else {
|
||||
Smokeping::do_log( "ERROR: DismanPing row creation failed for $t->{vars}{host} on $t->{vars}{pinghost}: $SNMP_Session::errmsg" );
|
||||
}
|
||||
my $timeout = 3; # XXX DEFVAL for pingCtlTimeOut
|
||||
my $length = $t->{vars}{pings} * $timeout;
|
||||
if ( $length > $longest ) {
|
||||
$longest = $length;
|
||||
}
|
||||
}
|
||||
my $setup = time - $start;
|
||||
Smokeping::do_debuglog(
|
||||
"DismanPing took $setup s to set up, now sleeping for $longest s");
|
||||
sleep($longest);
|
||||
my $allok = 0;
|
||||
my $startend = time;
|
||||
while ( !$allok ) {
|
||||
$allok = 1;
|
||||
foreach my $t ( @{ $self->targets } ) {
|
||||
next unless ( $pending->{ $t->{tree} } );
|
||||
my $idx = idx($t);
|
||||
my $host = host($t);
|
||||
|
||||
# check if it's done - pingResultsOperStatus != 1
|
||||
my $status = snmpget( $host, "pingResultsOperStatus.$idx" );
|
||||
if ( not defined $status or $status == 1 ) {
|
||||
# if SNMP fails, assume it's not done.
|
||||
my $howlong = time - $start;
|
||||
if ( $howlong > $self->step ) {
|
||||
Smokeping::do_log( "DismanPing: abandoning $t->{vars}{host} after $howlong seconds" );
|
||||
$pending->{ $t->{tree} } = 0;
|
||||
}
|
||||
else {
|
||||
Smokeping::do_log( "DismanPing: $t->{vars}{host} is still running after $howlong seconds" );
|
||||
$allok = 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
# if so, get results from History Table
|
||||
my @times = ();
|
||||
|
||||
# TODO: log message if you have a bad status other than TimedOut
|
||||
my $ret = snmpmaptable(
|
||||
$host,
|
||||
sub() {
|
||||
my ( $index, $rtt, $status ) = @_;
|
||||
push @times, [ sprintf( "%.10e", $rtt / 1000 ), $status ];
|
||||
},
|
||||
"pingProbeHistoryResponse.$idx",
|
||||
"pingProbeHistoryStatus.$idx"
|
||||
);
|
||||
Smokeping::do_debuglog( "DismanPing: table download returned "
|
||||
. ( defined($ret) ? $ret : "undef" ) );
|
||||
|
||||
# Make sure we have exactly pings results.
|
||||
# Fewer are probably an implementation problem (we asked for
|
||||
# 15, it said the test was done, but didn't return 15).
|
||||
# More are a less-bad implementation problem - we can keep
|
||||
# the last 15.
|
||||
if ( @times < $t->{vars}{pings} ) {
|
||||
Smokeping::do_log( "DismanPing: $t->{vars}{host} only returned "
|
||||
. scalar(@times)
|
||||
. " results" );
|
||||
@times = ();
|
||||
}
|
||||
elsif ( @times > $t->{vars}{pings} ) {
|
||||
Smokeping::do_log( "DismanPing: $t->{vars}{host} returned "
|
||||
. scalar(@times)
|
||||
. " results, taking last $t->{vars}{pings}" );
|
||||
@times = @times[ $#times - $t->{vars}{pings} .. $#times ];
|
||||
}
|
||||
|
||||
if (@times) {
|
||||
my (@goodtimes) = ();
|
||||
foreach my $result (@times) {
|
||||
push( @goodtimes, $result->[0] )
|
||||
if ( $result->[1] == 1 ); # responseReceived(1)
|
||||
}
|
||||
$self->{rtts}{ $t->{tree} } = [ sort { $a <=> $b } @goodtimes ];
|
||||
}
|
||||
$pending->{ $t->{tree} } = 0;
|
||||
}
|
||||
sleep 5 unless ($allok);
|
||||
}
|
||||
my $howlong = time - $start;
|
||||
my $endtime = time - $startend;
|
||||
Smokeping::do_debuglog( "DismanPing took $howlong total, $endtime collecting results");
|
||||
}
|
||||
|
||||
# Return index string for this test:
|
||||
# INDEX {
|
||||
# pingCtlOwnerIndex,
|
||||
# pingCtlTestName
|
||||
# }
|
||||
# This is the full index for pingCtlTable and
|
||||
# pingResultsTable, and the prefix of the index for
|
||||
# pingProbeHistoryTable.
|
||||
#
|
||||
# Uses the last 32 characters of menu name to
|
||||
# get a unique test name.
|
||||
sub idx ($) {
|
||||
my $t = shift;
|
||||
my $ownerindex = substr($t->{vars}{ownerindex} || 'SP on '.hostname(),0,32);
|
||||
print STDERR $ownerindex;
|
||||
my $testname = substr($t->{vars}{host} . ' ICMP ping',0,32);
|
||||
return join( ".",
|
||||
length($ownerindex), unpack( "C*", $ownerindex ),
|
||||
length($testname), unpack( "C*", $testname )
|
||||
);
|
||||
}
|
||||
|
||||
sub host ($) {
|
||||
my $t = shift;
|
||||
# gotta be aggressive with the SNMP to keep within
|
||||
# the time budget, so set the timeout to 1 second
|
||||
# and only try twice.
|
||||
# hostname:port:timeout:retries:backoff:version
|
||||
return $t->{vars}{pinghost} . "::1:2::2";
|
||||
}
|
||||
|
||||
1;
|
||||
276
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPing.pm
vendored
Normal file
276
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPing.pm
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
package Smokeping::probes::EchoPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Carp;
|
||||
|
||||
my $DEFAULTBIN = "/usr/bin/echoping";
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPing - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures TCP or UDP echo (port 7) roundtrip times for SmokePing. Can also be
|
||||
used as a base class for other echoping(1) probes.
|
||||
DOC
|
||||
description => <<DOC,
|
||||
See echoping(1) for details of the options below.
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
Should we test the availability of the service at startup? After that it's
|
||||
too late to complain.
|
||||
|
||||
The location of the echoping binary should probably be a global variable
|
||||
instead of a probe-specific one. As things are, every EchoPing -derived probe
|
||||
has to declare it if the default ($DEFAULTBIN) isn't correct.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
echoping(1), L<Smokeping::probes::EchoPingHttp> etc., L<http://echoping.sourceforge.net/>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# derived class will mess with this through the 'features' method below
|
||||
my $featurehash = {
|
||||
waittime => "-w",
|
||||
timeout => "-t",
|
||||
size => "-s",
|
||||
tos => "-P",
|
||||
priority => "-p",
|
||||
fill => "-f",
|
||||
};
|
||||
|
||||
sub features {
|
||||
my $self = shift;
|
||||
my $newval = shift;
|
||||
$featurehash = $newval if defined $newval;
|
||||
return $featurehash;
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
|
||||
$self->_init if $self->can('_init');
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "TCP or UDP Echo pings using echoping(1)";
|
||||
}
|
||||
|
||||
# This can be overridden to tag the port number to the address
|
||||
# in derived classes (namely EchoPingHttp)
|
||||
sub make_host {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
return $target->{addr};
|
||||
}
|
||||
|
||||
# This will be overridden by the EchoPingPlugin-derived probes
|
||||
sub post_args {
|
||||
return ();
|
||||
}
|
||||
|
||||
# other than host, count and protocol-specific args come from here
|
||||
sub make_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args;
|
||||
my %arghash = %{$self->features};
|
||||
|
||||
for (keys %arghash) {
|
||||
my $val = $target->{vars}{$_};
|
||||
push @args, ($arghash{$_}, $val) if defined $val;
|
||||
}
|
||||
push @args, $self->ipversion_arg($target);
|
||||
push @args, $target->{vars}{extraopts} if exists $target->{vars}{extraopts};
|
||||
|
||||
return @args;
|
||||
}
|
||||
|
||||
# this is separated to make it possible to test the service
|
||||
# at startup, although we don't do it at the moment.
|
||||
sub count_args {
|
||||
my $self = shift;
|
||||
my $count = shift;
|
||||
|
||||
$count = $self->pings() unless defined $count;
|
||||
return ("-n", $count);
|
||||
}
|
||||
|
||||
# This is what derived classes will override
|
||||
sub proto_args {
|
||||
my $self = shift;
|
||||
return $self->udp_arg(@_);
|
||||
}
|
||||
|
||||
# UDP is defined only for echo and discard
|
||||
sub udp_arg {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args;
|
||||
|
||||
my $udp = $target->{vars}{udp};
|
||||
push @args, "-u" if (defined $udp and $udp ne "no" and $udp ne "0");
|
||||
|
||||
return @args;
|
||||
}
|
||||
|
||||
sub ipversion_arg {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $vers = $target->{vars}{ipversion};
|
||||
if (defined $vers and $vers =~ /^([46])$/) {
|
||||
return ("-" . $1);
|
||||
} else {
|
||||
$self->do_log("Invalid `ipversion' value: $vers") if defined $vers;
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
sub make_commandline {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $count = shift;
|
||||
|
||||
$count |= $self->pings($target);
|
||||
|
||||
my @args = $self->make_args($target);
|
||||
my @post_args = $self->post_args($target);
|
||||
my $host = $self->make_host($target);
|
||||
push @args, $self->proto_args($target);
|
||||
push @args, $self->count_args($count);
|
||||
|
||||
return ($self->{properties}{binary}, @args, $host, @post_args);
|
||||
}
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $t = shift;
|
||||
|
||||
my @cmd = $self->make_commandline($t);
|
||||
|
||||
my $cmd = join(" ", @cmd);
|
||||
|
||||
$self->do_debug("executing cmd $cmd");
|
||||
|
||||
my @times;
|
||||
|
||||
open(P, "$cmd 2>&1 |") or carp("fork: $!");
|
||||
|
||||
my @output;
|
||||
while (<P>) {
|
||||
chomp;
|
||||
push @output, $_;
|
||||
/^Elapsed time: (\d+\.\d+) seconds/ and push @times, $1;
|
||||
}
|
||||
close P;
|
||||
if ($?) {
|
||||
my $status = $? >> 8;
|
||||
my $signal = $? & 127;
|
||||
my $why = "with status $status";
|
||||
$why .= " [signal $signal]" if $signal;
|
||||
|
||||
# only log warnings on the first ping round
|
||||
my $function = ($self->rounds_count == 1 ? "do_log" : "do_debug");
|
||||
|
||||
$self->$function(qq(WARNING: "$cmd" exited $why - output follows));
|
||||
$self->$function(qq( $_)) for @output;
|
||||
}
|
||||
# carp("Got @times") if $self->debug;
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout};
|
||||
return $class->_makevars($h, {
|
||||
binary => {
|
||||
_doc => "The location of your echoping binary.",
|
||||
_default => $DEFAULTBIN,
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
-x $val or return "ERROR: binary '$val' is not executable";
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
timeout => {
|
||||
_doc => 'The "-t" echoping(1) option.',
|
||||
_example => 1,
|
||||
_default => 5,
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
waittime => {
|
||||
_doc => 'The "-w" echoping(1) option.',
|
||||
_example => 1,
|
||||
_re => '\d+(?:\.\d+)?',
|
||||
},
|
||||
size => {
|
||||
_doc => 'The "-s" echoping(1) option.',
|
||||
_example => 510,
|
||||
_re => '\d+',
|
||||
},
|
||||
udp => {
|
||||
_doc => q{The "-u" echoping(1) option. Values other than '0' and 'no' enable UDP.},
|
||||
_example => 'no',
|
||||
},
|
||||
fill => {
|
||||
_doc => 'The "-f" echoping(1) option.',
|
||||
_example => 'A',
|
||||
_re => '.',
|
||||
},
|
||||
priority => {
|
||||
_doc => 'The "-p" echoping(1) option.',
|
||||
_example => 6,
|
||||
_re => '\d+',
|
||||
},
|
||||
tos => {
|
||||
_doc => 'The "-P" echoping(1) option.',
|
||||
_example => '0xa0',
|
||||
},
|
||||
ipversion => {
|
||||
_doc => <<DOC,
|
||||
The IP protocol used. Possible values are "4" and "6".
|
||||
Passed to echoping(1) as the "-4" or "-6" options.
|
||||
DOC
|
||||
_example => 4,
|
||||
_re => '[46]'
|
||||
},
|
||||
extraopts => {
|
||||
_doc => 'Any extra options specified here will be passed unmodified to echoping(1).',
|
||||
_example => '-some-letter-the-author-did-not-think-of',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
56
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingChargen.pm
vendored
Normal file
56
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingChargen.pm
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package Smokeping::probes::EchoPingChargen;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingChargen>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingChargen>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPing);
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingChargen - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures TCP chargen (port 19) roundtrip times for SmokePing.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
The I<udp> variable is not supported.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub proto_args {
|
||||
return ("-c");
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "TCP Chargen pings using echoping(1)";
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
delete $h->{udp};
|
||||
return $h;
|
||||
}
|
||||
|
||||
1;
|
||||
95
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingDNS.pm
vendored
Normal file
95
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingDNS.pm
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package Smokeping::probes::EchoPingDNS;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingDNS>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingDNS>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingDNS - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures DNS roundtrip times for SmokePing with the echoping_dns plugin.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
notes => <<'DOC',
|
||||
The I<fill>, I<size> and I<udp> EchoPing variables are not valid.
|
||||
|
||||
Plugins, including echoping_dns, are available starting with echoping version 6.
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>,
|
||||
L<Smokeping::probes::EchoPingPlugin>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPingPlugin);
|
||||
use Carp;
|
||||
|
||||
sub plugin_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args = ("-t", $target->{vars}{dns_type});
|
||||
my $tcp = $target->{vars}{dns_tcp};
|
||||
if ($tcp and $tcp ne "no") {
|
||||
push @args, "--tcp";
|
||||
}
|
||||
push @args, $target->{vars}{dns_request};
|
||||
return @args;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "DNS pings using the echoping_dns plugin";
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
delete $h->{udp};
|
||||
delete $h->{fill};
|
||||
delete $h->{size};
|
||||
$h->{_mandatory} = [ grep { $_ ne "plugin" } @{$h->{_mandatory}}];
|
||||
$h->{plugin}{_default} = 'dns';
|
||||
$h->{plugin}{_example} = '/path/to/dns.so';
|
||||
return $class->_makevars($h, {
|
||||
_mandatory => [ 'dns_request' ],
|
||||
dns_request => {
|
||||
_doc => <<DOC,
|
||||
The DNS request (domain name) to be queried.
|
||||
DOC
|
||||
_example => 'example.org',
|
||||
},
|
||||
dns_type => {
|
||||
_doc => <<DOC,
|
||||
The echoping_dns '-t' option: type of data requested (NS, A, SOA etc.)
|
||||
DOC
|
||||
_example => 'AAAA',
|
||||
_default => 'A',
|
||||
},
|
||||
dns_tcp => {
|
||||
_doc => <<DOC,
|
||||
The echoping_dns '--tcp' option: use only TCP ('virtual circuit').
|
||||
Enabled if specified with a value other than 'no' or '0'.
|
||||
DOC
|
||||
_example => 'yes',
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
50
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingDiscard.pm
vendored
Normal file
50
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingDiscard.pm
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package Smokeping::probes::EchoPingDiscard;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingDiscard>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingDiscard>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingDiscard - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures TCP or UDP discard (port 9) roundtrip times for SmokePing.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPing);
|
||||
use Carp;
|
||||
|
||||
sub proto_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args = $self->udp_arg;
|
||||
return ("-d", @args);
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "TCP or UDP Discard pings using echoping(1)";
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
146
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingHttp.pm
vendored
Normal file
146
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingHttp.pm
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
package Smokeping::probes::EchoPingHttp;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingHttp>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingHttp>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPing);
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingHttp - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures HTTP roundtrip times (web servers and caches) for SmokePing.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
You should consider setting a lower value for the C<pings> variable than the
|
||||
default 20, as repetitive URL fetching may be quite heavy on the server.
|
||||
|
||||
The I<fill>, I<size> and I<udp> EchoPing variables are not valid for EchoPingHttp.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>, L<Smokeping::probes::EchoPingHttps>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub _init {
|
||||
my $self = shift;
|
||||
# HTTP doesn't fit with filling or size
|
||||
my $arghashref = $self->features;
|
||||
delete $arghashref->{size};
|
||||
delete $arghashref->{fill};
|
||||
}
|
||||
|
||||
# tag the port number after the hostname
|
||||
sub make_host {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my $host = $self->SUPER::make_host($target);
|
||||
my $port = $target->{vars}{port};
|
||||
|
||||
$host .= ":$port" if defined $port;
|
||||
return $host;
|
||||
}
|
||||
|
||||
sub proto_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $url = $target->{vars}{url};
|
||||
|
||||
my @args = ("-h", $url);
|
||||
|
||||
# -A : ignore cache
|
||||
my $ignore = $target->{vars}{ignore_cache};
|
||||
$ignore = 1
|
||||
if (defined $ignore and $ignore ne "no"
|
||||
and $ignore ne "0");
|
||||
push @args, "-A" if $ignore;
|
||||
|
||||
# -a : force cache to revalidate the data
|
||||
my $revalidate = $target->{vars}{revalidate_data};
|
||||
$revalidate= 1 if (defined $revalidate and $revalidate ne "no"
|
||||
and $revalidate ne "0");
|
||||
push @args, "-a" if $revalidate;
|
||||
|
||||
# -R : accept HTTP redirects
|
||||
my $accept_redirects = $target->{vars}{accept_redirects};
|
||||
$accept_redirects= 1 if (defined $accept_redirects
|
||||
and $accept_redirects ne "no"
|
||||
and $accept_redirects ne "0");
|
||||
push @args, "-R" if $accept_redirects;
|
||||
|
||||
return @args;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "HTTP pings using echoping(1)";
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
delete $h->{udp};
|
||||
delete $h->{fill};
|
||||
delete $h->{size};
|
||||
$h->{timeout}{_default} = 10;
|
||||
$h->{timeout}{_example} = 20;
|
||||
return $class->_makevars($h, {
|
||||
url => {
|
||||
_doc => <<DOC,
|
||||
The URL to be requested from the web server or cache. Can be either relative
|
||||
(/...) for web servers or absolute (http://...) for caches.
|
||||
DOC
|
||||
_default => '/',
|
||||
},
|
||||
port => {
|
||||
_doc => 'The TCP port to use.',
|
||||
_example => 80,
|
||||
_re => '\d+',
|
||||
},
|
||||
ignore_cache => {
|
||||
_doc => <<DOC,
|
||||
The echoping(1) "-A" option: force the proxy to ignore the cache.
|
||||
Enabled if the value is anything other than 'no' or '0'.
|
||||
DOC
|
||||
_example => 'yes',
|
||||
},
|
||||
revalidate_data => {
|
||||
_doc => <<DOC,
|
||||
The echoping(1) "-a" option: force the proxy to revalidate data with original
|
||||
server. Enabled if the value is anything other than 'no' or '0'.
|
||||
DOC
|
||||
_example => 'no',
|
||||
},
|
||||
accept_redirects => {
|
||||
_doc => <<DOC,
|
||||
The echoping(1) "-R" option: Accept HTTP status codes 3xx (redirections)
|
||||
as normal responses instead of treating them as errors. Note that this option
|
||||
is only available starting with Echoping 6.
|
||||
|
||||
Enabled if the value is anything other than 'no' or '0'.
|
||||
DOC
|
||||
_example => 'yes',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
66
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingHttps.pm
vendored
Normal file
66
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingHttps.pm
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package Smokeping::probes::EchoPingHttps;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingHttps>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingHttps>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPingHttp);
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingHttps - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures HTTPS (HTTP over SSL) roundtrip times (web servers and caches) for
|
||||
SmokePing.
|
||||
DOC
|
||||
description => <<DOC,
|
||||
As EchoPingHttp(3pm), but SSL-enabled.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
You should consider setting a lower value for the C<pings> variable than the
|
||||
default 20, as repetitive URL fetching may be quite heavy on the server.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPingHttp>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub proto_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args = $self->SUPER::proto_args($target);
|
||||
return ("-C", @args);
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "HTTPS pings using echoping(1)";
|
||||
}
|
||||
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
$h->{prot}{_example} = 3443;
|
||||
$h->{prot}{_default} = 443;
|
||||
return $h;
|
||||
}
|
||||
|
||||
1;
|
||||
79
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingIcp.pm
vendored
Normal file
79
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingIcp.pm
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package Smokeping::probes::EchoPingIcp;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingIcp>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingIcp>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPing);
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingIcp - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures ICP (Internet Cache Protocol, spoken by web caches)
|
||||
roundtrip times for SmokePing.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
The I<fill>, I<size> and I<udp> EchoPing variables are not valid.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>, L<Smokeping::probes::EchoPingHttp>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub _init {
|
||||
my $self = shift;
|
||||
# Icp doesn't fit with filling or size
|
||||
my $arghashref = $self->features;
|
||||
delete $arghashref->{size};
|
||||
delete $arghashref->{fill};
|
||||
}
|
||||
|
||||
sub proto_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $url = $target->{vars}{url};
|
||||
|
||||
my @args = ("-i", $url);
|
||||
|
||||
return @args;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "ICP pings using echoping(1)";
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
delete $h->{udp};
|
||||
delete $h->{fill};
|
||||
delete $h->{size};
|
||||
return $class->_makevars($h, {
|
||||
_mandatory => [ 'url' ],
|
||||
url => {
|
||||
_doc => "The URL to be requested from the web cache.",
|
||||
_example => 'http://www.example.org/',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
99
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingLDAP.pm
vendored
Normal file
99
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingLDAP.pm
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
package Smokeping::probes::EchoPingLDAP;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingLDAP>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingLDAP>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingLDAP - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures LDAP roundtrip times for SmokePing with the echoping_ldap plugin.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
notes => <<'DOC',
|
||||
The I<fill>, I<size> and I<udp> EchoPing variables are not valid.
|
||||
|
||||
Plugins, including echoping_ldap, are available starting with echoping version 6.
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>,
|
||||
L<Smokeping::probes::EchoPingPlugin>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPingPlugin);
|
||||
use Carp;
|
||||
|
||||
sub plugin_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args;
|
||||
my $req = $target->{vars}{ldap_request};
|
||||
push @args, "-r $req" if $req;
|
||||
|
||||
my $base = $target->{vars}{ldap_base};
|
||||
push @args, "-b $base" if $base;
|
||||
|
||||
my $scope = $target->{vars}{ldap_scope};
|
||||
push @args, "-s $scope" if $scope;
|
||||
|
||||
return @args;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "LDAP pings using the echoping_ldap plugin";
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
delete $h->{udp};
|
||||
delete $h->{fill};
|
||||
delete $h->{size};
|
||||
$h->{_mandatory} = [ grep { $_ ne "plugin" } @{$h->{_mandatory}}];
|
||||
$h->{plugin}{_default} = 'ldap';
|
||||
$h->{plugin}{_example} = '/path/to/ldap.so';
|
||||
return $class->_makevars($h, {
|
||||
ldap_request => {
|
||||
_doc => <<DOC,
|
||||
The echoping_ldap '-r' option:
|
||||
the request to the LDAP server, in LDAP filter language.
|
||||
DOC
|
||||
_example => '(objectclass=*)',
|
||||
},
|
||||
ldap_base => {
|
||||
_doc => <<DOC,
|
||||
The echoping_ldap '-b' option:
|
||||
base of the search.
|
||||
DOC
|
||||
_example => 'dc=current,dc=bugs,dc=debian,dc=org',
|
||||
},
|
||||
ldap_scope => {
|
||||
_doc => <<DOC,
|
||||
The echoping_ldap '-s' option:
|
||||
scope of the search, "sub", "one" or "base".
|
||||
DOC
|
||||
_example => 'one',
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
108
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingPlugin.pm
vendored
Normal file
108
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingPlugin.pm
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
package Smokeping::probes::EchoPingPlugin;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingPlugin>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingPlugin>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingPlugin - a basis for using echoping(1) plugins as probes for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures roundtrip times for SmokePing with an echoping(1) plugin. The plugins
|
||||
currently shipped with echoping are implemented as separate probes based
|
||||
on this class, but the class can also be used directly.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
notes => <<'DOC',
|
||||
The I<fill>, I<size> and I<udp> EchoPing variables are not valid by default for EchoPingPlugin -derived probes.
|
||||
|
||||
Plugins are available starting with echoping version 6.
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>,
|
||||
L<Smokeping::probes::EchoPingLDAP>,
|
||||
L<Smokeping::probes::EchoPingDNS>,
|
||||
L<Smokeping::probes::EchoPingWhois>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPing);
|
||||
use Carp;
|
||||
|
||||
sub _init {
|
||||
my $self = shift;
|
||||
# plugins don't generally fit with filling, size or udp.
|
||||
my $arghashref = $self->features;
|
||||
delete $arghashref->{size};
|
||||
delete $arghashref->{fill};
|
||||
delete $arghashref->{udp};
|
||||
}
|
||||
|
||||
sub post_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
return $self->plugin_args($target);
|
||||
}
|
||||
|
||||
# derived classes should override this
|
||||
sub plugin_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
return ();
|
||||
}
|
||||
|
||||
sub proto_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $plugin = $target->{vars}{plugin};
|
||||
return ("-m", $plugin);
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "Pings using an echoping(1) plugin";
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
delete $h->{udp};
|
||||
delete $h->{fill};
|
||||
delete $h->{size};
|
||||
return $class->_makevars($h, {
|
||||
_mandatory => [ 'plugin' ],
|
||||
plugin => {
|
||||
_doc => <<DOC,
|
||||
The echoping plugin that will be used. See echoping(1) for details.
|
||||
This can either be the name of the plugin or a full path to the
|
||||
plugin shared object.
|
||||
DOC
|
||||
_example => "random",
|
||||
},
|
||||
pluginargs => {
|
||||
_doc => <<DOC,
|
||||
Any extra arguments needed by the echoping plugin specified with the
|
||||
I<pluginname> variable. These are generally provided by the subclass probe.
|
||||
DOC
|
||||
_example => "-p plugin_specific_arg",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
66
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingSmtp.pm
vendored
Normal file
66
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingSmtp.pm
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package Smokeping::probes::EchoPingSmtp;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingSmtp>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingSmtp>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPing);
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingSmtp - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures SMTP roundtrip times (mail servers) for SmokePing.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
The I<fill>, I<size> and I<udp> EchoPing variables are not valid.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub _init {
|
||||
my $self = shift;
|
||||
# SMTP doesn't fit with filling or size
|
||||
my $arghashref = $self->features;
|
||||
delete $arghashref->{size};
|
||||
delete $arghashref->{fill};
|
||||
}
|
||||
|
||||
sub proto_args {
|
||||
return ("-S");
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "SMTP pings using echoping(1)";
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
delete $h->{udp};
|
||||
delete $h->{fill};
|
||||
delete $h->{size};
|
||||
return $h;
|
||||
}
|
||||
|
||||
1;
|
||||
78
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingWhois.pm
vendored
Normal file
78
debian/smokeping/usr/share/perl5/Smokeping/probes/EchoPingWhois.pm
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package Smokeping::probes::EchoPingWhois;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::EchoPingWhois>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::EchoPingWhois>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::EchoPingWhois - an echoping(1) probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures whois roundtrip times for SmokePing with the echoping_whois plugin.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
notes => <<'DOC',
|
||||
The I<fill>, I<size> and I<udp> EchoPing variables are not valid.
|
||||
|
||||
Plugins, including echoping_whois, are available starting with echoping version 6.
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::EchoPing>,
|
||||
L<Smokeping::probes::EchoPingPlugin>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::EchoPingPlugin);
|
||||
use Carp;
|
||||
|
||||
sub plugin_args {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my @args;
|
||||
push @args, $target->{vars}{whois_request};
|
||||
|
||||
return @args;
|
||||
}
|
||||
|
||||
sub ProbeDesc($) {
|
||||
return "whois pings using the echoping_whois plugin";
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::targetvars;
|
||||
delete $h->{udp};
|
||||
delete $h->{fill};
|
||||
delete $h->{size};
|
||||
$h->{_mandatory} = [ grep { $_ ne "plugin" } @{$h->{_mandatory}}];
|
||||
$h->{plugin}{_default} = 'whois';
|
||||
$h->{plugin}{_example} = '/path/to/whois.so';
|
||||
return $class->_makevars($h, {
|
||||
_mandatory => [ 'whois_request' ],
|
||||
whois_request => {
|
||||
_doc => <<DOC,
|
||||
The request to the whois server (typically a domain name).
|
||||
DOC
|
||||
_example => 'example.org',
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
286
debian/smokeping/usr/share/perl5/Smokeping/probes/FPing.pm
vendored
Normal file
286
debian/smokeping/usr/share/perl5/Smokeping/probes/FPing.pm
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
package Smokeping::probes::FPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::FPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::FPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::base);
|
||||
use IPC::Open3;
|
||||
use Symbol;
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::FPing - FPing Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates FPing as a probe into smokeping. The variable B<binary> must
|
||||
point to your copy of the FPing program. If it is not installed on
|
||||
your system yet, you can get a slightly enhanced version from L<www.smokeping.org/pub>.
|
||||
|
||||
The (optional) B<packetsize> option lets you configure the packetsize for the pings sent.
|
||||
|
||||
Since version 3.3 fping sends its statistics to stdout. Set B<usestdout> to 'true'
|
||||
so make smokeping read stdout instead of stderr.
|
||||
|
||||
In B<blazemode>, FPing sends one more ping than requested, and discards
|
||||
the first RTT value returned as it's likely to be an outlier.
|
||||
|
||||
The FPing manpage has the following to say on this topic:
|
||||
|
||||
Number of bytes of ping data to send. The minimum size (normally 12) allows
|
||||
room for the data that fping needs to do its work (sequence number,
|
||||
timestamp). The reported received data size includes the IP header
|
||||
(normally 20 bytes) and ICMP header (8 bytes), so the minimum total size is
|
||||
40 bytes. Default is 56, as in ping. Maximum is the theoretical maximum IP
|
||||
datagram size (64K), though most systems limit this to a smaller,
|
||||
system-dependent number.
|
||||
|
||||
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
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 $binary = join(" ", $self->binary);
|
||||
my $testhost = $self->testhost;
|
||||
my $return = `$binary -C 1 $testhost 2>&1`;
|
||||
$self->{enable}{S} = (`$binary -h 2>&1` =~ /\s-S[,\s]/);
|
||||
$self->{enable}{O} = (`$binary -h 2>&1` =~ /\s-O[,\s]/);
|
||||
croak "ERROR: fping ('$binary -C 1 $testhost') could not be run: $return"
|
||||
if $return =~ m/not found/;
|
||||
croak "ERROR: FPing must be installed setuid root or it will not work\n"
|
||||
if $return =~ m/only.+root/;
|
||||
|
||||
if ($return =~ m/bytes, ([0-9.]+)\sms\s+.*\n.*\n.*:\s+([0-9.]+)/ and $1 > 0){
|
||||
$self->{pingfactor} = 1000 * $2/$1;
|
||||
if ($1 != $2){
|
||||
warn "### fping seems to report in ", $2/$1, " milliseconds (old version?)";
|
||||
}
|
||||
} else {
|
||||
$self->{pingfactor} = 1000; # Gives us a good-guess default
|
||||
warn "### assuming you are using an fping copy reporting in milliseconds\n";
|
||||
}
|
||||
|
||||
# fping only has -4 and -6 switches starting with 3.16 and the binary refuses
|
||||
# to run if the switches are passed in to older versions.
|
||||
$self->{enable}{proto} = (`$binary -v 2>&1` =~ /Version (3.1[6-9]|[4-9])/);
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize}||56;
|
||||
return "ICMP Echo Pings ($bytes Bytes)";
|
||||
}
|
||||
|
||||
# derived class (ie. RemoteFPing) can override this
|
||||
sub binary {
|
||||
my $self = shift;
|
||||
return $self->{properties}{binary};
|
||||
}
|
||||
|
||||
# derived class (ie. FPing6) can override this
|
||||
sub testhost {
|
||||
return "localhost";
|
||||
}
|
||||
|
||||
sub ping ($){
|
||||
my $self = shift;
|
||||
# do NOT call superclass ... the ping method MUST be overridden
|
||||
|
||||
# increment the internal 'rounds' counter
|
||||
$self->increment_rounds_count;
|
||||
|
||||
my %upd;
|
||||
my $inh = gensym;
|
||||
my $outh = gensym;
|
||||
my $errh = gensym;
|
||||
# pinging nothing is pointless
|
||||
return unless @{$self->addresses};
|
||||
my @params = () ;
|
||||
push @params, "-$self->{properties}{protocol}" if $self->{properties}{protocol} and $self->{enable}{proto};
|
||||
push @params, "-b$self->{properties}{packetsize}" if $self->{properties}{packetsize};
|
||||
push @params, "-t" . int(1000 * $self->{properties}{timeout}) if $self->{properties}{timeout};
|
||||
push @params, "-i" . int(1000 * $self->{properties}{mininterval});
|
||||
push @params, "-p" . int(1000 * $self->{properties}{hostinterval}) if $self->{properties}{hostinterval};
|
||||
push @params, "--iface=$self->{properties}{interface}" if $self->{properties}{interface};
|
||||
if ($self->rounds_count == 1 and $self->{properties}{sourceaddress} and not $self->{enable}{S}){
|
||||
$self->do_log("WARNING: your fping binary doesn't support source address setting (-S), I will ignore any sourceaddress configurations - see http://bugs.debian.org/198486.");
|
||||
}
|
||||
push @params, "-S$self->{properties}{sourceaddress}" if $self->{properties}{sourceaddress} and $self->{enable}{S};
|
||||
|
||||
if ($self->rounds_count == 1 and $self->{properties}{tos} and not $self->{enable}{O}){
|
||||
$self->do_log("WARNING: your fping binary doesn't support type of service setting (-O), I will ignore any tos configurations.");
|
||||
}
|
||||
push @params, "-O$self->{properties}{tos}" if $self->{properties}{tos} and $self->{enable}{O};
|
||||
|
||||
my $pings = $self->pings;
|
||||
if (($self->{properties}{blazemode} || '') eq 'true'){
|
||||
$pings++;
|
||||
}
|
||||
my @cmd = (
|
||||
$self->binary,
|
||||
'-C', $pings, '-q','-B1','-r1',
|
||||
@params,
|
||||
@{$self->addresses});
|
||||
$self->do_debug("Executing @cmd");
|
||||
my $pid = open3($inh,$outh,$errh, @cmd);
|
||||
$self->{rtts}={};
|
||||
my $fh = ( $self->{properties}{usestdout} || '') eq 'true' ? $outh : $errh;
|
||||
while (<$fh>){
|
||||
chomp;
|
||||
$self->do_debug("Got fping output: '$_'");
|
||||
next unless /^\S+\s+:\s+[-\d\.]/; #filter out error messages from fping
|
||||
my @times = split /\s+/;
|
||||
my $ip = shift @times;
|
||||
next unless ':' eq shift @times; #drop the colon
|
||||
if (($self->{properties}{blazemode} || '') eq 'true'){
|
||||
shift @times;
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep /^\d/, @times;
|
||||
map { $self->{rtts}{$_} = [@times] } @{$self->{addrlookup}{$ip}} ;
|
||||
}
|
||||
waitpid $pid,0;
|
||||
# Exit status (of fping) is
|
||||
# 0 if all the hosts are reachable,
|
||||
# 1 if some hosts were unreachable,
|
||||
# 2 if any IP addresses were not found,
|
||||
# 3 for invalid command line arguments, and
|
||||
# 4 for a system call failure.
|
||||
# Don't log 0 or 1 as an unreachable host is not unexpected for a monitoring software
|
||||
my $rc = $?;
|
||||
my $status = $rc >> 8;
|
||||
carp join(" ",@cmd) . " returned with exit code $rc. run with debug enabled to get more information" unless $status == 0 or $status == 1;
|
||||
close $inh;
|
||||
close $outh;
|
||||
close $errh;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'binary' ],
|
||||
binary => {
|
||||
_sub => sub {
|
||||
my ($val) = @_;
|
||||
return undef if $ENV{SERVER_SOFTWARE}; # don't check for fping presence in cgi mode
|
||||
return "ERROR: FPing 'binary' does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
_doc => "The location of your fping binary.",
|
||||
_example => '/usr/bin/fping',
|
||||
},
|
||||
packetsize => {
|
||||
_re => '\d+',
|
||||
_example => 5000,
|
||||
_sub => sub {
|
||||
my ($val) = @_;
|
||||
return "ERROR: FPing packetsize must be between 12 and 64000"
|
||||
if ( $val < 12 or $val > 64000 );
|
||||
return undef;
|
||||
},
|
||||
_doc => "The ping packet size (in the range of 12-64000 bytes).",
|
||||
|
||||
},
|
||||
blazemode => {
|
||||
_re => '(true|false)',
|
||||
_example => 'true',
|
||||
_doc => "Send an extra ping and then discard the first answer since the first is bound to be an outlier.",
|
||||
|
||||
},
|
||||
protocol => {
|
||||
_re => '(4|6)',
|
||||
_example => '4',
|
||||
_doc => "Choose if the ping should use IPv4 or IPv6.",
|
||||
|
||||
},
|
||||
usestdout => {
|
||||
_re => '(true|false)',
|
||||
_example => 'true',
|
||||
_doc => "Listen for FPing output on stdout instead of stderr ... (version 3.3+ sends its statistics on stdout).",
|
||||
|
||||
},
|
||||
timeout => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => 1.5,
|
||||
_doc => <<DOC,
|
||||
The fping "-t" parameter, but in (possibly fractional) seconds rather than
|
||||
milliseconds, for consistency with other Smokeping probes. Note that as
|
||||
Smokeping uses the fping 'counting' mode (-C), this apparently only affects
|
||||
the last ping.
|
||||
DOC
|
||||
},
|
||||
hostinterval => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => 1.5,
|
||||
_doc => <<DOC,
|
||||
The fping "-p" parameter, but in (possibly fractional) seconds rather than
|
||||
milliseconds, for consistency with other Smokeping probes. From fping(1):
|
||||
|
||||
This parameter sets the time that fping waits between successive packets
|
||||
to an individual target.
|
||||
DOC
|
||||
},
|
||||
mininterval => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => .001,
|
||||
_default => .01,
|
||||
_doc => <<DOC,
|
||||
The fping "-i" parameter, but in (probably fractional) seconds rather than
|
||||
milliseconds, for consistency with other Smokeping probes. From fping(1):
|
||||
|
||||
The minimum amount of time between sending a ping packet to any target.
|
||||
DOC
|
||||
},
|
||||
sourceaddress => {
|
||||
_re => '\d+(\.\d+){3}',
|
||||
_example => '192.168.0.1',
|
||||
_doc => <<DOC,
|
||||
The fping "-S" parameter . From fping(1):
|
||||
|
||||
Set source address.
|
||||
DOC
|
||||
},
|
||||
tos => {
|
||||
_re => '\d+|0x[0-9a-zA-Z]+',
|
||||
_example => '0x20',
|
||||
_doc => <<DOC,
|
||||
Set the type of service (TOS) of outgoing ICMP packets.
|
||||
You need at laeast fping-2.4b2_to3-ipv6 for this to work. Find
|
||||
a copy on www.smokeping.org/pub.
|
||||
DOC
|
||||
},
|
||||
interface => {
|
||||
_example => 'eth0',
|
||||
_doc => "The name of the network interface to perform the ping on.",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
62
debian/smokeping/usr/share/perl5/Smokeping/probes/FPing6.pm
vendored
Normal file
62
debian/smokeping/usr/share/perl5/Smokeping/probes/FPing6.pm
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package Smokeping::probes::FPing6;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::FPing6>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::FPing6>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::FPing);
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::FPing6 - FPing6 Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates FPing6 as a probe into smokeping. This probe is derived from
|
||||
FPing; the only difference is that the target host used for checking
|
||||
the fping command output is ::1 instead of localhost.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC
|
||||
L<Smokeping::probes::FPing>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub testhost {
|
||||
return "::1";
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $self = shift;
|
||||
my $h = $self->SUPER::probevars;
|
||||
$h->{binary}{_example} = "/usr/bin/fping6";
|
||||
$h->{protocol}{_example} = "6";
|
||||
$h->{protocol}{_default} = "6";
|
||||
$h->{sourceaddress}{_re} = "[0-9A-Fa-f:.]+";
|
||||
$h->{sourceaddress}{_example} = "::1";
|
||||
return $h;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize}||56;
|
||||
return "IPv6-ICMP Echo Pings ($bytes Bytes)";
|
||||
}
|
||||
|
||||
1;
|
||||
447
debian/smokeping/usr/share/perl5/Smokeping/probes/FPingContinuous.pm
vendored
Normal file
447
debian/smokeping/usr/share/perl5/Smokeping/probes/FPingContinuous.pm
vendored
Normal file
@@ -0,0 +1,447 @@
|
||||
package Smokeping::probes::FPingContinuous;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::FPingContinuous>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::FPingContinuous>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::base);
|
||||
use IPC::Open3;
|
||||
use IO::Pipe;
|
||||
use IO::Select;
|
||||
use Symbol;
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::FPingContinuous - FPingContinuous Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates FPingContinuous as a probe into smokeping. The variable B<binary> must
|
||||
point to your copy of the FPing program. If it is not installed on
|
||||
your system yet, you can get a slightly enhanced version from L<www.smokeping.org/pub>.
|
||||
|
||||
The (optional) B<packetsize> option lets you configure the packetsize for the pings sent.
|
||||
|
||||
Continuous output is normally sent to stdout, but you can set B<usestdout> to 'false'
|
||||
to make smokeping read stderr instead of stdout.
|
||||
|
||||
The FPing manpage has the following to say on this topic:
|
||||
|
||||
Number of bytes of ping data to send. The minimum size (normally 12) allows
|
||||
room for the data that fping needs to do its work (sequence number,
|
||||
timestamp). The reported received data size includes the IP header
|
||||
(normally 20 bytes) and ICMP header (8 bytes), so the minimum total size is
|
||||
40 bytes. Default is 56, as in ping. Maximum is the theoretical maximum IP
|
||||
datagram size (64K), though most systems limit this to a smaller,
|
||||
system-dependent number.
|
||||
|
||||
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Steven Wilton <swilton@fluentit.com.au>
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
my $pinger_request=undef;
|
||||
my $pinger_reply=undef;
|
||||
# Do 5% more pings than required to make sure we have enough results for each poll
|
||||
my $error_pct=5;
|
||||
|
||||
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 $binary = join(" ", $self->binary);
|
||||
my $testhost = $self->testhost;
|
||||
my $return = `$binary -C 1 $testhost 2>&1`;
|
||||
$self->{enable}{S} = (`$binary -h 2>&1` =~ /\s-S[,\s]/);
|
||||
$self->{enable}{O} = (`$binary -h 2>&1` =~ /\s-O[,\s]/);
|
||||
croak "ERROR: fping ('$binary -C 1 $testhost') could not be run: $return"
|
||||
if $return =~ m/not found/;
|
||||
croak "ERROR: FPing must be installed setuid root or it will not work\n"
|
||||
if $return =~ m/only.+root/;
|
||||
croak "ERROR: We can only do one ping every 21ms. Either reduce the number of pings or increase the step to fix the issue\n"
|
||||
if($self->interval() < 20);
|
||||
|
||||
if ($return =~ m/bytes, ([0-9.]+)\sms\s+.*\n.*\n.*:\s+([0-9.]+)/ and $1 > 0){
|
||||
$self->{pingfactor} = 1000 * $2/$1;
|
||||
if ($1 != $2){
|
||||
warn "### fping seems to report in ", $2/$1, " milliseconds (old version?)";
|
||||
}
|
||||
} else {
|
||||
$self->{pingfactor} = 1000; # Gives us a good-guess default
|
||||
warn "### assuming you are using an fping copy reporting in milliseconds\n";
|
||||
}
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub interval {
|
||||
my $self=shift;
|
||||
return (($self->step/$self->pings) * (1-($error_pct/100)) * 1000);
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize}||56;
|
||||
return "ICMP Echo Pings ($bytes Bytes)";
|
||||
}
|
||||
|
||||
# derived class (ie. RemoteFPingContinuous) can override this
|
||||
sub binary {
|
||||
my $self = shift;
|
||||
return $self->{properties}{binary};
|
||||
}
|
||||
|
||||
# derived class (ie. FPingContinuous6) can override this
|
||||
sub testhost {
|
||||
return "localhost";
|
||||
}
|
||||
|
||||
sub run_pinger {
|
||||
my $self=shift;
|
||||
my $input=shift;
|
||||
my $output=shift;
|
||||
|
||||
my $select = IO::Select->new();
|
||||
$select->add($input);
|
||||
my ($fping_stdin, $fping_stdout, $fping_stderr, $fping_pid)=$self->run_fping($select);
|
||||
my %results=();
|
||||
foreach my $address(@{$self->addresses}) {
|
||||
$results{$address}{results}=[];
|
||||
$results{$address}{assumed_drops}=0;
|
||||
$results{$address}{reply_seq}=0;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
my @ready=$select->can_read(1);
|
||||
foreach my $fh(@ready) {
|
||||
if($fh->fileno == $input->fileno) {
|
||||
if($fh->eof) {
|
||||
$self->do_log("Input pipe has been closed - exiting");
|
||||
exit(0);
|
||||
}
|
||||
my $input_cmd=<$input>;
|
||||
#$self->do_log($input_cmd);
|
||||
|
||||
if($input_cmd =~ /^FETCH (.+)$/) {
|
||||
my $address=$1;
|
||||
chomp($address);
|
||||
if(!exists($results{$address})) {
|
||||
$self->do_log("We are not gathering results for $address");
|
||||
print $output "\n";
|
||||
} else {
|
||||
my @ret;
|
||||
if(scalar(@{$results{$address}{results}}) < $self->pings) {
|
||||
my $fakeloss=$self->pings-scalar(@{$results{$address}{results}});
|
||||
$self->do_log("Adding $fakeloss lost pings to $address due to insufficient data");
|
||||
@ret=@{$results{$address}{results}};
|
||||
|
||||
# Record the number of assumed drops, adding the error margin to ensure we do not over-report packet loss
|
||||
$results{$address}{assumed_drops}+=($fakeloss / (1-($error_pct/100)));
|
||||
while($fakeloss-- > 0) {
|
||||
push @ret,"-";
|
||||
}
|
||||
|
||||
# Reset the results array
|
||||
$results{$address}{results}=[];
|
||||
} else {
|
||||
# Return the correct number of items from the beginning of the result array
|
||||
@ret=splice(@{$results{$address}{results}}, 0, $self->pings);
|
||||
|
||||
# Leave 2* the error percent of items in the array, but remove extra items
|
||||
my $extra=scalar(@{$results{$address}{results}}) - ($self->pings * ($error_pct*2/100));
|
||||
if($extra > 0) {
|
||||
$self->do_debug("Removing $extra of ". scalar(@{$results{$address}{results}}) ." ping results from array for $address");
|
||||
splice(@{$results{$address}{results}}, 0, $extra);
|
||||
} else {
|
||||
$self->do_debug(scalar(@{$results{$address}{results}}) ." ping results remaining for $address ($extra)");
|
||||
}
|
||||
}
|
||||
$self->do_debug("Data for $address: ". join(" ", @ret));
|
||||
print $output join(" ", @ret) ."\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if($fh->eof) {
|
||||
$self->do_log("fping process exited - restarting");
|
||||
waitpid $fping_pid,0;
|
||||
my $rc = $?;
|
||||
carp "fping process returned with exit code $rc. run with debug enabled to get more information" unless $rc == 0;
|
||||
close($fping_stdin);
|
||||
close($fping_stdout);
|
||||
close($fping_stderr);
|
||||
$select->remove($fping_stdout);
|
||||
$select->remove($fping_stderr);
|
||||
%results=();
|
||||
foreach my $address(@{$self->addresses}) {
|
||||
$results{$address}{results}=[];
|
||||
$results{$address}{assumed_drops}=0;
|
||||
$results{$address}{reply_seq}=0;
|
||||
}
|
||||
($fping_stdin, $fping_stdout, $fping_stderr, $fping_pid)=$self->run_fping($select);
|
||||
}
|
||||
|
||||
while(my $data=<$fh>) {
|
||||
if($data =~ /(\S+)\s+:\s+\[(\d+)\],.+bytes,\s+([0-9\.]+)\s+ms\s+\(/) {
|
||||
my $address=$1;
|
||||
my $this_seq=$2;
|
||||
my $pingtime=$3;
|
||||
|
||||
# See if we missed any sequence numbers since the last reply.
|
||||
# Also reduce the detected drop count by any assumed loss so we do not over-report packet loss
|
||||
my $drops=($results{$address}{reply_seq} && $this_seq > $results{$address}{reply_seq})?($this_seq - $results{$address}{reply_seq} - 1 - $results{$address}{assumed_drops}):0;
|
||||
|
||||
# Add records for dropped packets
|
||||
if($drops) {
|
||||
$self->do_debug("Detected $drops packets dropped in sequence numbers");
|
||||
while($drops-- > 0) {
|
||||
push @{$results{$address}{results}}, "-";
|
||||
}
|
||||
}
|
||||
|
||||
# Record this packet
|
||||
push @{$results{$address}{results}}, $pingtime;
|
||||
|
||||
# Update the sequence number
|
||||
$results{$address}{reply_seq}=$this_seq;
|
||||
|
||||
# We can forget about any assumed drops since we have handles actual packet loss above
|
||||
$results{$address}{assumed_drops}=0;
|
||||
} else {
|
||||
# We only care about input from either stdin or stderr. We need to
|
||||
# clear data from both to avoid deadlocks, but we only want to log
|
||||
# garbage data from the fd that is generating the good data
|
||||
my $data_fh = ( $self->{properties}{usestdout} || '') ne 'false' ? $fping_stdout : $fping_stderr;
|
||||
if($fh->fileno == $data_fh->fileno) {
|
||||
$self->do_log("Unknown input data: $data");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# See if any pipes have been closed
|
||||
my @gone=$select->has_exception(0);
|
||||
foreach my $fh(@gone) {
|
||||
if($fh->fileno == $input->fileno) {
|
||||
$self->do_log("Input pipe has been closed - exiting");
|
||||
exit(0);
|
||||
} else {
|
||||
$self->do_log("fping process exited - restarting");
|
||||
waitpid $fping_pid,0;
|
||||
my $rc = $?;
|
||||
carp "fping process returned with exit code $rc. run with debug enabled to get more information" unless $rc == 0;
|
||||
close($fping_stdin);
|
||||
close($fping_stdout);
|
||||
close($fping_stderr);
|
||||
$select->remove($fping_stdout);
|
||||
$select->remove($fping_stderr);
|
||||
%results=();
|
||||
foreach my $address(@{$self->addresses}) {
|
||||
$results{$address}{results}=[];
|
||||
$results{$address}{assumed_drops}=0;
|
||||
$results{$address}{reply_seq}=0;
|
||||
}
|
||||
($fping_stdin, $fping_stdout, $fping_stderr, $fping_pid)=$self->run_fping($select);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub run_fping {
|
||||
my $self = shift;
|
||||
my $select = shift;
|
||||
|
||||
my $inh = gensym;
|
||||
my $outh = gensym;
|
||||
my $errh = gensym;
|
||||
my @params = () ;
|
||||
push @params, "-b$self->{properties}{packetsize}" if $self->{properties}{packetsize};
|
||||
push @params, "-t" . int(1000 * $self->{properties}{timeout}) if $self->{properties}{timeout};
|
||||
push @params, "-p" . int(1000 * $self->{properties}{hostinterval}) if $self->{properties}{hostinterval};
|
||||
if ($self->rounds_count == 1 and $self->{properties}{sourceaddress} and not $self->{enable}{S}){
|
||||
$self->do_log("WARNING: your fping binary doesn't support source address setting (-S), I will ignore any sourceaddress configurations - see http://bugs.debian.org/198486.");
|
||||
}
|
||||
push @params, "-S$self->{properties}{sourceaddress}" if $self->{properties}{sourceaddress} and $self->{enable}{S};
|
||||
|
||||
if ($self->rounds_count == 1 and $self->{properties}{tos} and not $self->{enable}{O}){
|
||||
$self->do_log("WARNING: your fping binary doesn't support type of service setting (-O), I will ignore any tos configurations.");
|
||||
}
|
||||
push @params, "-O$self->{properties}{tos}" if $self->{properties}{tos} and $self->{enable}{O};
|
||||
|
||||
my @cmd = (
|
||||
$self->binary,
|
||||
'-l','-B1','-r1','-p',$self->interval(),
|
||||
@params,
|
||||
@{$self->addresses}
|
||||
);
|
||||
$self->do_debug("Executing @cmd");
|
||||
my $pid = open3($inh,$outh,$errh, @cmd);
|
||||
$outh->blocking(0);
|
||||
$errh->blocking(0);
|
||||
$inh->autoflush(1);
|
||||
$select->add($outh);
|
||||
$select->add($errh);
|
||||
|
||||
return ($inh,$outh,$errh,$pid);
|
||||
}
|
||||
|
||||
sub ping ($){
|
||||
my $self = shift;
|
||||
# do NOT call superclass ... the ping method MUST be overridden
|
||||
|
||||
# pinging nothing is pointless
|
||||
return unless @{$self->addresses};
|
||||
|
||||
# Fork off our worker if needed
|
||||
if(!$pinger_request) {
|
||||
$pinger_request=IO::Pipe->new();
|
||||
$pinger_reply=IO::Pipe->new();
|
||||
my $pid;
|
||||
if($pid = fork()) { # Parent
|
||||
$pinger_request->writer();
|
||||
$pinger_request->autoflush(1);
|
||||
|
||||
$pinger_reply->reader();
|
||||
foreach my $address(@{$self->addresses}) {
|
||||
map { $self->{rtts}{$_} = undef } @{$self->{addrlookup}{$address}};
|
||||
}
|
||||
} elsif(defined($pid)) {
|
||||
$pinger_request->reader();
|
||||
|
||||
$pinger_reply->writer();
|
||||
$pinger_reply->autoflush(1);
|
||||
|
||||
$self->run_pinger($pinger_request, $pinger_reply);
|
||||
exit(0);
|
||||
}
|
||||
} else {
|
||||
foreach my $address(@{$self->addresses}) {
|
||||
print $pinger_request "FETCH $address\n";
|
||||
my $reply=<$pinger_reply>;
|
||||
chomp($reply);
|
||||
|
||||
# Send back the results
|
||||
my @times = split /\s+/, $reply;
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep /^\d/, @times;
|
||||
map { $self->{rtts}{$_} = [@times] } @{$self->{addrlookup}{$address}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If we explicitly set the rtts to undef, we want to record UNDEF for packet loss, which is different from the base module
|
||||
sub rrdupdate_string($$) {
|
||||
my $self = shift;
|
||||
my $tree = shift;
|
||||
|
||||
my $pings = $self->pings;
|
||||
if(exists($self->{rtts}{$tree}) && !defined($self->{rtts}{$tree})) {
|
||||
$self->do_debug("No data exists - returning undef");
|
||||
my $age='U';
|
||||
my $loss='U';
|
||||
my $median='U';
|
||||
my @times=map {"U"} 1..($pings);
|
||||
|
||||
# Return all values as "U"
|
||||
return "${age}:${loss}:${median}:".(join ":", @times);
|
||||
} else {
|
||||
&Smokeping::probes::base::rrdupdate_string($self, $tree);
|
||||
}
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'binary' ],
|
||||
binary => {
|
||||
_sub => sub {
|
||||
my ($val) = @_;
|
||||
return undef if $ENV{SERVER_SOFTWARE}; # don't check for fping presence in cgi mode
|
||||
return "ERROR: FPing 'binary' does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
_doc => "The location of your fping binary.",
|
||||
_example => '/usr/bin/fping',
|
||||
},
|
||||
packetsize => {
|
||||
_re => '\d+',
|
||||
_example => 5000,
|
||||
_sub => sub {
|
||||
my ($val) = @_;
|
||||
return "ERROR: FPing packetsize must be between 12 and 64000"
|
||||
if ( $val < 12 or $val > 64000 );
|
||||
return undef;
|
||||
},
|
||||
_doc => "The ping packet size (in the range of 12-64000 bytes).",
|
||||
|
||||
},
|
||||
usestdout => {
|
||||
_re => '(true|false)',
|
||||
_example => 'false',
|
||||
_doc => "Listen for FPing output on stdout instead of stderr ... (continuous output is normally sent to stdout).",
|
||||
|
||||
},
|
||||
timeout => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => 1.5,
|
||||
_doc => <<DOC,
|
||||
The fping "-t" parameter, but in (possibly fractional) seconds rather than
|
||||
milliseconds, for consistency with other Smokeping probes. Note that as
|
||||
Smokeping uses the fping 'counting' mode (-C), this apparently only affects
|
||||
the last ping.
|
||||
DOC
|
||||
},
|
||||
hostinterval => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => 1.5,
|
||||
_doc => <<DOC,
|
||||
The fping "-p" parameter, but in (possibly fractional) seconds rather than
|
||||
milliseconds, for consistency with other Smokeping probes. From fping(1):
|
||||
|
||||
This parameter sets the time that fping waits between successive packets
|
||||
to an individual target.
|
||||
DOC
|
||||
},
|
||||
sourceaddress => {
|
||||
_re => '\d+(\.\d+){3}',
|
||||
_example => '192.168.0.1',
|
||||
_doc => <<DOC,
|
||||
The fping "-S" parameter . From fping(1):
|
||||
|
||||
Set source address.
|
||||
DOC
|
||||
},
|
||||
tos => {
|
||||
_re => '\d+|0x[0-9a-zA-Z]+',
|
||||
_example => '0x20',
|
||||
_doc => <<DOC,
|
||||
Set the type of service (TOS) of outgoing ICMP packets.
|
||||
You need at laeast fping-2.4b2_to3-ipv6 for this to work. Find
|
||||
a copy on www.smokeping.org/pub.
|
||||
DOC
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
240
debian/smokeping/usr/share/perl5/Smokeping/probes/FTPtransfer.pm
vendored
Normal file
240
debian/smokeping/usr/share/perl5/Smokeping/probes/FTPtransfer.pm
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
package Smokeping::probes::FTPtransfer;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::FTPtransfer>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::FTPtransfer>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::passwordchecker);
|
||||
use Net::FTP;
|
||||
use Time::HiRes qw(gettimeofday sleep);
|
||||
use Carp;
|
||||
|
||||
my $DEFAULTINTERVAL = 1;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::FTPtransfer - intrusive bandwidth probe
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
This probe send and retrieve files to or from an ftp server. It will plot
|
||||
the bandwidth it could use.
|
||||
DOC
|
||||
description => <<DOC,
|
||||
The probe uses the Net::FTP perl client to run performance tests using an
|
||||
FTP server as a target. This probe is B<intrusive> as it transfers real
|
||||
data. By using real data we get a fair shot at figuring out what a link is
|
||||
capable of when it comes to transferring actual files.
|
||||
|
||||
The password can be specified either (in order of precedence, with
|
||||
the latter overriding the former) in the probe-specific variable
|
||||
`password', in an external file or in the target-specific variable
|
||||
`password'. The location of this external file is given in the probe-specific
|
||||
variable `passwordfile'. See Smokeping::probes::passwordchecker(3pm) for the
|
||||
format of this file (summary: colon-separated triplets of the form
|
||||
`<host>:<username>:<password>')
|
||||
|
||||
The probe tries to be nice to the server and waits at least X seconds
|
||||
between starting filetransfers, where X is the value of the probe
|
||||
specific `min_interval' variable ($DEFAULTINTERVAL by default).
|
||||
|
||||
Many variables can be specified either in the probe or in the target definition,
|
||||
the target-specific variable will override the prove-specific variable.
|
||||
|
||||
If your transfer takes a lot of time, you may want to make sure to set the
|
||||
B<timeout> and B<max_rtt> properly so that smokeping does not abort the
|
||||
transfers of limit the graph size.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Tobias Oetiker <tobi@oetiker.ch> sponsored by Virtela
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
This probe has the capability for saturating your links, so don't use it
|
||||
unless you know what you are doing.
|
||||
|
||||
The FTPtransfer probe measures bandwidth, but we report the number of
|
||||
seconds it took to transfer the 'reference' file. This is because currently
|
||||
the notion of I<Round Trip Time> is at the core of the application. It would
|
||||
take some re-engineering to split this out in plugins and thus make it
|
||||
configurable ...
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
# returns the last part of a path
|
||||
sub _get_filename ($) {
|
||||
return (split m|/|, $_[0])[-1];
|
||||
}
|
||||
|
||||
sub ProbeDesc ($) {
|
||||
my $self = shift;
|
||||
my $srcfile = $self->{properties}{srcfile};
|
||||
my $destfile = $self->{properties}{destfile} || _get_filename $self->{properties}{srcfile};
|
||||
my $mode = $self->{properties}{mode};
|
||||
my $size = $mode eq 'get' ? -s $destfile : -s $srcfile;
|
||||
return sprintf("FTP File transfers (%.0f KB)",$size/1024);
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $host = $target->{addr};
|
||||
my $vars = $target->{vars};
|
||||
my $mininterval = $self->{properties}{min_interval};
|
||||
my $srcfile = $self->{properties}{srcfile};
|
||||
my $destfile = $self->{properties}{destfile} || _get_filename $self->{properties}{srcfile};
|
||||
my $mode = $self->{properties}{mode};
|
||||
my $username = $vars->{username};
|
||||
|
||||
$self->do_log("Missing FTP username for $host"), return
|
||||
unless defined $username;
|
||||
|
||||
my $password = $self->password($host, $username) || $vars->{password};
|
||||
|
||||
$self->do_log("Missing FTP password for $host/$username"), return
|
||||
unless defined $password;
|
||||
|
||||
my @options = ();
|
||||
push (@options, Timeout => $vars->{timeout});
|
||||
push (@options, Port => $vars->{port} ) if $vars->{port};
|
||||
push (@options, LocalAddr => $vars->{localaddr} ) if $vars->{localaddr};
|
||||
push (@options, Passive => 1 ) if $vars->{passive} and $vars->{passive} eq 'yes';
|
||||
|
||||
my @times;
|
||||
my $elapsed;
|
||||
|
||||
for (1..$self->pings($target)) {
|
||||
if (defined $elapsed) {
|
||||
my $timeleft = $mininterval - $elapsed;
|
||||
sleep $timeleft if $timeleft > 0;
|
||||
}
|
||||
my $ftp = Net::FTP->new($host, @options) or
|
||||
$self->do_log("Problem with $host: ftp session $@"), return;
|
||||
$ftp->login($username,$password) or
|
||||
$self->do_log("Problem with $host: ftp login ".$ftp->message), return;
|
||||
my $start = gettimeofday();
|
||||
my $ok;
|
||||
my $size;
|
||||
if ($mode eq 'get'){
|
||||
$ok = $ftp->get($srcfile,$destfile) or
|
||||
$self->do_log("Problem with $host: ftp get ".$ftp->message);
|
||||
$size = -s $destfile;
|
||||
} else {
|
||||
$ok = $ftp->put($srcfile,$destfile) or
|
||||
$self->do_log("Problem with $host: ftp put ".$ftp->message);
|
||||
$size = -s $srcfile;
|
||||
}
|
||||
my $end = gettimeofday();
|
||||
$ftp->quit;
|
||||
$elapsed = ( $end - $start );
|
||||
$ok or next;
|
||||
$self->do_debug("$host - $mode mode transferred $size Bytes in ${elapsed}s");
|
||||
push @times, $elapsed;
|
||||
}
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout}{_default}; # force a timeout to be defined
|
||||
$h->{timeout}{_doc} = <<DOC;
|
||||
The timeout is the maximum amount of time you will allow the probe to
|
||||
transfer the file. If the probe does not succeed to transfer in the time specified,
|
||||
it will get killed and a 'loss' will be logged.
|
||||
|
||||
Since FTPtransfer is an invasive probe you should make sure you do not load
|
||||
the link for more than a few seconds anyway. Smokeping currently has a hard
|
||||
limit of 180 seconds for any RTT.
|
||||
DOC
|
||||
|
||||
return $class->_makevars($h, {
|
||||
_mandatory => [ 'srcfile','mode','timeout' ],
|
||||
srcfile => {
|
||||
_doc => <<DOC,
|
||||
The name of the source file. If the probe is in B<put> mode, this file
|
||||
has to be on the local machine, if the probe is in B<get> mode then this
|
||||
file should sit in the remote ftp account.
|
||||
DOC
|
||||
_example => 'src/path/mybig.pdf',
|
||||
},
|
||||
destfile => {
|
||||
_doc => <<DOC,
|
||||
Normally the destination filename is the same as the source filename
|
||||
(without the path). If you want keep files in different directories this may not
|
||||
work, and you have to specify destfile as well.
|
||||
DOC
|
||||
_example => 'path/to/destinationfile.xxx',
|
||||
},
|
||||
mode => {
|
||||
_doc => <<DOC,
|
||||
The ftp probe can be in either put or get mode. If it is in put mode then it will send a file to the ftp server. In get mode it will retrieve a file
|
||||
from the ftp server.
|
||||
DOC
|
||||
_example => 'get',
|
||||
_re => '(put|get)',
|
||||
},
|
||||
|
||||
min_interval => {
|
||||
_default => $DEFAULTINTERVAL,
|
||||
_doc => "The minimum interval between each starting ftp sessions in seconds.",
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
username => {
|
||||
_doc => 'The username to be tested.',
|
||||
_example => 'test-user',
|
||||
},
|
||||
password => {
|
||||
_doc => 'The password for the user, if not present in the password file.',
|
||||
_example => 'test-password',
|
||||
},
|
||||
timeout => {
|
||||
_doc => "Timeout in seconds for the FTP transfer to complete.",
|
||||
_re => '\d+',
|
||||
_example => 10,
|
||||
},
|
||||
port => {
|
||||
_doc => 'A non-standard FTP port to be used',
|
||||
_re => '\d+',
|
||||
_example => '3255',
|
||||
},
|
||||
localaddr => {
|
||||
_doc => 'The local address to be used when making connections',
|
||||
_example => 'myhost-nat-if',
|
||||
},
|
||||
passive => {
|
||||
_doc => 'Use passive FTP protocol',
|
||||
_re => '(yes|no)',
|
||||
_example => 'yes',
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
264
debian/smokeping/usr/share/perl5/Smokeping/probes/IOSPing.pm
vendored
Normal file
264
debian/smokeping/usr/share/perl5/Smokeping/probes/IOSPing.pm
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
package Smokeping::probes::IOSPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::IOSPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::IOSPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use IPC::Open2;
|
||||
use Symbol;
|
||||
use Carp;
|
||||
|
||||
my $e = "=";
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::IOSPing - Cisco IOS Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates Cisco IOS as a probe into smokeping. Uses the rsh / remsh
|
||||
protocol to run a ping from an IOS device.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
=head2 IOS Configuration
|
||||
|
||||
The IOS device must have rsh enabled and an appropriate trust defined,
|
||||
eg:
|
||||
|
||||
!
|
||||
ip rcmd rsh-enable
|
||||
ip rcmd remote-host smoke 192.168.1.2 smoke enable
|
||||
!
|
||||
|
||||
Some IOS devices have a maximum of 5 VTYs available, so be careful not to
|
||||
hit a limit with the 'forks' variable.
|
||||
|
||||
${e}head2 Password authentication
|
||||
|
||||
It is not possible to use password authentication with rsh or remsh
|
||||
due to fundamental limitations of the protocol.
|
||||
|
||||
${e}head2 Ping packet size
|
||||
|
||||
The FPing manpage has the following to say on the topic of ping packet
|
||||
size:
|
||||
|
||||
Number of bytes of ping data to send. The minimum size (normally 12)
|
||||
allows room for the data that fping needs to do its work (sequence
|
||||
number, timestamp). The reported received data size includes the IP
|
||||
header (normally 20 bytes) and ICMP header (8 bytes), so the minimum
|
||||
total size is 40 bytes. Default is 56, as in ping. Maximum is the
|
||||
theoretical maximum IP datagram size (64K), though most systems limit
|
||||
this to a smaller, system-dependent number.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Paul J Murphy <paul@murph.org>
|
||||
|
||||
based on L<Smokeping::probes::FPing|Smokeping::probes::FPing> by
|
||||
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
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} ) {
|
||||
$self->{pingfactor} = 1000; # Gives us a good-guess default
|
||||
print "### assuming you are using an IOS reporting in milliseconds\n";
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
return "Cisco IOS - ICMP Echo Pings ($bytes Bytes)";
|
||||
}
|
||||
|
||||
sub pingone ($$){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
# do NOT call superclass ... the ping method MUST be overridden
|
||||
my %upd;
|
||||
my $inh = gensym;
|
||||
my $outh = gensym;
|
||||
my @args = ();
|
||||
my $pings = $self->pings($target);
|
||||
|
||||
push(@args,$self->{properties}{binary});
|
||||
push(@args,'-l',$target->{vars}{iosuser})
|
||||
if defined $target->{vars}{iosuser};
|
||||
push(@args,$target->{vars}{ioshost});
|
||||
push(@args,'ping');
|
||||
|
||||
my $pid = open2($outh,$inh,@args);
|
||||
#
|
||||
# The following comments are the dialog produced by
|
||||
# "remsh <router> ping" to a Cisco 800 series running IOS 12.2T
|
||||
#
|
||||
# Other hardware or versions of IOS may need adjustments here.
|
||||
#
|
||||
# Protocol [ip]:
|
||||
print { $inh } "\n";
|
||||
# Target IP address:
|
||||
print { $inh } $target->{addr},"\n";
|
||||
# Repeat count [5]:
|
||||
print { $inh } $pings,"\n";
|
||||
# Datagram size [100]:
|
||||
print { $inh } $bytes,"\n";
|
||||
# Timeout in seconds [2]:
|
||||
print { $inh } "\n";
|
||||
# Extended commands [n]:
|
||||
print { $inh } "y\n";
|
||||
# Source address or interface:
|
||||
print { $inh } "".($target->{vars}{iosint} || "") ,"\n";
|
||||
# Added by Mars Wei to make
|
||||
# Source address an option
|
||||
# Type of service [0]:
|
||||
print { $inh } "\n";
|
||||
# Set DF bit in IP header? [no]:
|
||||
print { $inh } "\n";
|
||||
# Validate reply data? [no]:
|
||||
print { $inh } "\n";
|
||||
# Data pattern [0xABCD]:
|
||||
print { $inh } "\n";
|
||||
# Loose, Strict, Record, Timestamp, Verbose[none]:
|
||||
print { $inh } "V\n";
|
||||
# Loose, Strict, Record, Timestamp, Verbose[V]:
|
||||
print { $inh } "\n";
|
||||
# Sweep range of sizes [n]:
|
||||
print { $inh } "\n";
|
||||
#
|
||||
# Type escape sequence to abort.
|
||||
# Sending 20, 56-byte ICMP Echos to 192.168.1.2, timeout is 2 seconds:
|
||||
# Reply to request 0 (4 ms)
|
||||
# Reply to request 1 (4 ms)
|
||||
# Reply to request 2 (4 ms)
|
||||
# Reply to request 3 (1 ms)
|
||||
# Reply to request 4 (1 ms)
|
||||
# Reply to request 5 (1 ms)
|
||||
# Reply to request 6 (4 ms)
|
||||
# Reply to request 7 (4 ms)
|
||||
# Reply to request 8 (4 ms)
|
||||
# Reply to request 9 (4 ms)
|
||||
# Reply to request 10 (1 ms)
|
||||
# Reply to request 11 (1 ms)
|
||||
# Reply to request 12 (1 ms)
|
||||
# Reply to request 13 (1 ms)
|
||||
# Reply to request 14 (4 ms)
|
||||
# Reply to request 15 (4 ms)
|
||||
# Reply to request 16 (4 ms)
|
||||
# Reply to request 17 (4 ms)
|
||||
# Reply to request 18 (1 ms)
|
||||
# Reply to request 19 (1 ms)
|
||||
# Success rate is 100 percent (20/20), round-trip min/avg/max = 1/2/4 ms
|
||||
|
||||
my @times = ();
|
||||
while (<$outh>){
|
||||
chomp;
|
||||
/^Reply to request \d+ \((\d+) ms\)/ && push(@times,$1);
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} @times;
|
||||
|
||||
waitpid $pid,0;
|
||||
my $rc = $?;
|
||||
carp join(" ",@args) . " returned with exit code $rc. run with debug enabled to get more information" unless $rc == 0;
|
||||
close $inh;
|
||||
close $outh;
|
||||
|
||||
return @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => ['binary'],
|
||||
binary => {
|
||||
_doc => <<DOC,
|
||||
The binary option specifies the path of the binary to be used to
|
||||
connect to the IOS device. Commonly used binaries are /usr/bin/rsh
|
||||
and /usr/bin/remsh, although any script or binary should work if can
|
||||
be called as
|
||||
|
||||
/path/to/binary [ -l user ] router ping
|
||||
|
||||
to produce the IOS ping dialog on stdin & stdout.
|
||||
DOC
|
||||
_example => '/usr/bin/rsh',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
-x $val or return "ERROR: binary '$val' is not executable";
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
packetsize => {
|
||||
_doc => <<DOC,
|
||||
The (optional) packetsize option lets you configure the packetsize for
|
||||
the pings sent.
|
||||
DOC
|
||||
_default => 56,
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: packetsize must be between 12 and 64000"
|
||||
unless $val >= 12 and $val <= 64000;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'ioshost' ],
|
||||
ioshost => {
|
||||
_doc => <<DOC,
|
||||
The ioshost option specifies the IOS device which should be used for
|
||||
the ping.
|
||||
DOC
|
||||
_example => 'my.cisco.router',
|
||||
},
|
||||
iosuser => {
|
||||
_doc => <<DOC,
|
||||
The (optional) iosuser option allows you to specify the remote
|
||||
username the IOS device. If this option is omitted, the username
|
||||
defaults to the default user used by the remsh command (usually the
|
||||
user running the remsh command, ie the user running SmokePing).
|
||||
DOC
|
||||
_example => 'admin',
|
||||
},
|
||||
iosint => {
|
||||
_doc => <<DOC,
|
||||
The (optional) iosint option allows you to specify the source address
|
||||
or interface in the IOS device. The value should be an IP address or
|
||||
an interface name such as "Ethernet 1/0". If this option is omitted,
|
||||
the IOS device will pick the IP address of the outbound interface to
|
||||
use.
|
||||
DOC
|
||||
_example => 'Ethernet 1/0',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
512
debian/smokeping/usr/share/perl5/Smokeping/probes/IRTT.pm
vendored
Normal file
512
debian/smokeping/usr/share/perl5/Smokeping/probes/IRTT.pm
vendored
Normal file
@@ -0,0 +1,512 @@
|
||||
package Smokeping::probes::IRTT;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::IRTT>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::IRTT>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
#use Data::Dumper;
|
||||
use IPC::Open2 qw(open2);
|
||||
use JSON::PP qw(decode_json);
|
||||
use Path::Tiny qw(path);
|
||||
use Scalar::Util qw(looks_like_number);
|
||||
use Symbol qw(gensym);
|
||||
use Time::HiRes qw(usleep gettimeofday tv_interval);
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::IRTT - a SmokePing Probe for L<IRTT|https://github.com/peteheist/irtt>
|
||||
DOC
|
||||
description => <<DOC,
|
||||
This SmokePing probe uses L<IRTT|https://github.com/peteheist/irtt> to record
|
||||
network L<round-trip time|https://en.wikipedia.org/wiki/Round-trip_delay_time>,
|
||||
L<one-way delay|https://en.wikipedia.org/wiki/End-to-end_delay> or
|
||||
L<IPDV|https://en.wikipedia.org/wiki/Packet_delay_variation> (jitter), based on
|
||||
the value of the B<metric> variable.
|
||||
|
||||
Additionally, the probe provides a results sharing feature, which allows using
|
||||
results from a single IRTT run to record multiple metrics for a given host at
|
||||
the same time. One target is defined with the B<writeto> variable set, which
|
||||
selects the name of a temporary file to save the IRTT output to. Additional
|
||||
targets are defined with the B<readfrom> variable set to the same value, which,
|
||||
instead of running IRTT, wait for the main target's output to become available,
|
||||
then parse it to record the chosen metric from the same data. See the
|
||||
B<writeto> and B<readfrom> variables for more information.
|
||||
|
||||
=head2 WARNING
|
||||
|
||||
The results sharing feature (B<writeto> and B<readfrom> variables) requires the
|
||||
number of B<forks> for the IRTT probe to be at least the total number of IRTT
|
||||
targets defined (regardless of whether they have B<writeto> and B<readfrom>
|
||||
set). Otherwise, there can be a deadlock while B<readfrom> targets wait for their
|
||||
corresponding B<writeto> target to complete, which may never start.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Pete Heist <pete@heistp.net>
|
||||
DOC
|
||||
};
|
||||
}
|
||||
|
||||
sub new ($$$) {
|
||||
my $self = shift->SUPER::new(@_);
|
||||
|
||||
# no need for this if we run as a cgi (still run at startup)
|
||||
unless ( $ENV{SERVER_SOFTWARE} ) {
|
||||
# check irtt version
|
||||
my $vout = `$self->{properties}->{binary} version`
|
||||
or die "ERROR: irtt version return code " . ($? >> 8);
|
||||
if ($vout =~ /irtt version: (\d+)\.(\d+)\.(\d+)/ ) {
|
||||
if ($1 == '0' && $2 < '9') {
|
||||
die "ERROR: unsupported irtt version: $1.$2.$3";
|
||||
}
|
||||
} else {
|
||||
die "ERROR: irtt version unexpected output: $vout";
|
||||
}
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub probevars ($) {
|
||||
my $class = shift;
|
||||
my $pv = $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'binary' ],
|
||||
binary => {
|
||||
_doc => "The location of your irtt binary.",
|
||||
_default => '/usr/bin/irtt',
|
||||
_example => '/usr/local/bin/irtt',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: irtt 'binary' does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
tmpdir => {
|
||||
_doc => "A temporary directory in which to place files for writeto/readfrom.",
|
||||
_default => '/tmp/smokeping-irtt',
|
||||
},
|
||||
});
|
||||
|
||||
# TODO Delete probe timeout and define it per-target based on interval
|
||||
# (not ready yet as need to figure out logic in targetvars)
|
||||
#delete $pv->{timeout};
|
||||
|
||||
return $pv;
|
||||
}
|
||||
|
||||
sub targetvars ($) {
|
||||
my $class = shift;
|
||||
my $tv = $class->_makevars($class->SUPER::targetvars, {
|
||||
dscp => {
|
||||
_doc => <<DOC,
|
||||
The packet L<DSCP|https://en.wikipedia.org/wiki/Differentiated_services> value
|
||||
to use (C<irtt client --dscp>). This is the same as the classic one byte IP ToS
|
||||
field, but on the modern Internet, typically only the lower 6 bits are used,
|
||||
and this is called the DSCP value. The upper two bits are reserved for
|
||||
L<ECN|https://en.wikipedia.org/wiki/Explicit_Congestion_Notification>. Hex may
|
||||
be used if prefixed by C<0x>.
|
||||
DOC
|
||||
_example => '46',
|
||||
_re => '(\d+|0x[0-9a-fA-F]{1,2})',
|
||||
},
|
||||
extraargs => {
|
||||
_doc => <<DOC,
|
||||
Extra arguments to C<irtt client> (see L<irtt-client(1)>). B<Be careful> with
|
||||
extra arguments, as some can corrupt the results.
|
||||
DOC
|
||||
_example => '--ttl=32',
|
||||
},
|
||||
fill => {
|
||||
_doc => <<DOC,
|
||||
The fill to use in the payload for the client to server packet (C<irtt client
|
||||
--fill>). The B<length> variable must be large enough so there's a payload to fill.
|
||||
Use rand for random fill, or see L<irtt-client(1)> for more options.
|
||||
DOC
|
||||
_example => 'rand',
|
||||
},
|
||||
hmac => {
|
||||
_doc => <<DOC,
|
||||
The
|
||||
L<HMAC|https://en.wikipedia.org/wiki/Hash-based_message_authentication_code>
|
||||
key to use when sending packets to the server (C<irtt client --hmac>).
|
||||
DOC
|
||||
_example => 'opensesame',
|
||||
},
|
||||
interval => {
|
||||
_doc => <<DOC,
|
||||
The interval between successive requests, in seconds (C<irtt client -i>, but the
|
||||
unit is always seconds (s)).
|
||||
|
||||
B<WARNING>
|
||||
|
||||
If B<interval> is increased to greater than 5 seconds, the B<timeout> (which
|
||||
defaults to B<pings> * 5 seconds + 1) must be modified so that SmokePing
|
||||
doesn't kill the probe prematurely. Additionally, B<interval> must not be
|
||||
increased such that B<pings> * B<interval> is greater than B<step>. For
|
||||
example, at B<step>=300 and B<pings>=20, the B<interval> must not be greater
|
||||
than 15 seconds, but should preferably be less to account for handshake and
|
||||
packet wait times.
|
||||
DOC
|
||||
_example => 1.5,
|
||||
_default => 1,
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
ipversion => {
|
||||
_doc => <<DOC,
|
||||
The IP version to use for packets (4 or 6, corresponding to C<irtt client -4>
|
||||
or C<irtt client -6>). By default the IP version is chosen based on the
|
||||
supplied host variable.
|
||||
DOC
|
||||
_example => 6,
|
||||
_re => '^(4|6)$',
|
||||
},
|
||||
length => {
|
||||
_doc => <<DOC,
|
||||
The length (size) of the packet (C<irtt client -l>). The length includes IRTT
|
||||
headers, but not IP or UDP headers. The actual packet length is increased to
|
||||
accommodate the IRTT headers, if necessary. Header size as of IRTT 0.9.0 as used
|
||||
in SmokePing is 48 bytes when B<writeto> is set (since both monotonic and wall
|
||||
clock values are requested) and 40 bytes otherwise.
|
||||
DOC
|
||||
_example => 172,
|
||||
_re => '\d+',
|
||||
},
|
||||
localaddr => {
|
||||
_doc => <<DOC,
|
||||
The local address to bind to when sending packets (C<irtt client --local>).
|
||||
See L<irtt-client(1)> Host formats for valid syntax.
|
||||
DOC
|
||||
_example => '192.168.1.10:63814',
|
||||
},
|
||||
metric => {
|
||||
_doc => <<DOC,
|
||||
The metric to record, one of:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
rtt: L<round-trip time|https://en.wikipedia.org/wiki/Round-trip_delay_time>
|
||||
|
||||
=item *
|
||||
|
||||
send: L<one-way send delay|https://en.wikipedia.org/wiki/End-to-end_delay>
|
||||
I<(requires external time synchronization)>
|
||||
|
||||
=item *
|
||||
|
||||
receive: L<one-way receive delay|https://en.wikipedia.org/wiki/End-to-end_delay>
|
||||
I<(requires external time synchronization)>
|
||||
|
||||
=item *
|
||||
|
||||
ipdv: L<IPDV|https://en.wikipedia.org/wiki/Packet_delay_variation>
|
||||
(instantaneous packet delay variation, or jitter)
|
||||
|
||||
=item *
|
||||
|
||||
send_ipdv: IPDV for sent packets
|
||||
|
||||
=item *
|
||||
|
||||
receive_ipdv: IPDV for received packets
|
||||
|
||||
=back
|
||||
|
||||
Note that the C<send> and C<receive> metrics require accurate external system
|
||||
clock synchronization, otherwise the values from one will be abnormally high and
|
||||
the other will be abnormally low or even negative, in which case the value 0
|
||||
will be given SmokePing. It is recommended to install ntp on both the SmokePing
|
||||
client and IRTT server. Properly configured NTP may be able to synchronize time to
|
||||
within a few milliseconds, which is usually enough to provide useful results.
|
||||
PTP over a LAN may achieve microsecond-level accuracy. For best results between
|
||||
geographically remote hosts, GPS receivers may be used. Since C<send_ipdv> and
|
||||
C<receive_ipdv> measure the variation in times between successive packets,
|
||||
and since C<rtt> and C<ipdv> use monotonic clock values on the client side
|
||||
only, external time synchronization is not required for these metrics.
|
||||
|
||||
DOC
|
||||
_default => 'rtt',
|
||||
_re => '^(rtt|send|receive|ipdv|send_ipdv|receive_ipdv)$',
|
||||
},
|
||||
readfrom => {
|
||||
_doc => <<DOC,
|
||||
The name of a file to read results from, instead of running IRTT. Use in
|
||||
combination with B<writeto> to use the results from one IRTT run to record
|
||||
multiple metrics. The value will become the name of a file in B<tmpdir>, and
|
||||
must be the same as another target's setting for B<writeto>. Multiple targets
|
||||
may use the same value for B<readfrom>, but B<writeto> and B<readfrom> may not
|
||||
be both set for a given target. When B<readfrom> is set, any variables that
|
||||
affect C<irtt client> are ignored because IRTT is not being invoked, including:
|
||||
B<dscp>, B<extraargs>, B<fill>, B<hmac>, B<interval>, B<ipversion>, B<length>,
|
||||
B<localaddr> and B<serverfill>. These values are only relevant in the
|
||||
corresponding B<writeto> target.
|
||||
|
||||
Note that the B<host> variable must still be defined for targets that define
|
||||
B<readfrom>, otherwise the target won't be used.
|
||||
|
||||
When using this feature, be sure to have at least as many B<forks> for the
|
||||
IRTT probe as you have total IRTT targets defined. See the L</DESCRIPTION>
|
||||
section for more information.
|
||||
DOC
|
||||
_example => 'irtt1',
|
||||
},
|
||||
readfrompollinterval => {
|
||||
_doc => <<DOC,
|
||||
The integer interval in seconds on which to poll for results when B<readfrom>
|
||||
is set. Lower numbers will allow B<readfrom> to see the results a bit sooner,
|
||||
at the cost of higher CPU usage. Polling does not begin until the soonest time
|
||||
at which the IRTT client could have terminated normally.
|
||||
DOC
|
||||
_default => 5,
|
||||
_re => '[1-9]\d*',
|
||||
_example => '2',
|
||||
},
|
||||
serverfill => {
|
||||
_doc => <<DOC,
|
||||
The fill to use in the payload for the server to client packet (C<irtt client
|
||||
--sfill>). The B<length> variable must be large enough to accommodate a
|
||||
payload. Use C<rand> for random fill, or see L<irtt-client(1)> for more
|
||||
options.
|
||||
DOC
|
||||
_example => 'rand',
|
||||
},
|
||||
sleep => {
|
||||
_doc => <<DOC,
|
||||
The amount of time to sleep before starting requests or processing results (a
|
||||
float in seconds). This may be used to avoid CPU spikes caused by invoking
|
||||
multiple instances of IRTT at the same time.
|
||||
DOC
|
||||
_example => '0.5',
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
writeto => {
|
||||
_doc => <<DOC,
|
||||
The name of a file to write results to after running IRTT. Use in combination
|
||||
with B<readfrom> to use the results from this IRTT run to record multiple
|
||||
metrics. The value will become the name of a file in B<tmpdir>, and any targets
|
||||
with B<readfrom> set to the same value will use this target's results. There
|
||||
must be only one target with B<writeto> set for a given file, and B<writeto>
|
||||
and B<readfrom> may not be both set for a given target.
|
||||
|
||||
When using this feature, be sure to have at least as many B<forks> for the IRTT
|
||||
probe as you have total IRTT targets defined. See the L</DESCRIPTION> section
|
||||
for more information.
|
||||
DOC
|
||||
_example => 'irtt1',
|
||||
},
|
||||
});
|
||||
|
||||
# TODO Here I would like to be able to set the target-specific timeout
|
||||
# based on the interval and number of pings, but I'm currently unable to
|
||||
# get the number of pings in this method, before I have a value for target.
|
||||
#my $pings = $tv->{pings} ? $tv->{pings} : $class->SUPER::pings();
|
||||
#$tv->{timeout} = $tv->{interval} * $pings + 5;
|
||||
|
||||
return $tv;
|
||||
}
|
||||
|
||||
sub ProbeDesc ($) {
|
||||
my $self = shift;
|
||||
return "IRTT round-trips";
|
||||
}
|
||||
|
||||
sub get_json_from_file ($$) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $t = $target;
|
||||
my $tv = $t->{vars};
|
||||
my $p = $self->{properties};
|
||||
my $fname = path($p->{tmpdir}, $tv->{readfrom});
|
||||
|
||||
# mark start
|
||||
my $t0 = [gettimeofday];
|
||||
|
||||
# sleep, if requested
|
||||
usleep($tv->{sleep} * 1000000) if $tv->{sleep};
|
||||
|
||||
# wait for earliest possible finish, then 5 seconds at a time
|
||||
sleep $tv->{interval} * $self->pings($t) + 2;
|
||||
while (1) {
|
||||
# break when the file is found
|
||||
last if -f $fname;
|
||||
|
||||
# die if step elapsed, which should never happen as we should
|
||||
# be killed by smokeping's timeout sooner than this
|
||||
if (tv_interval ($t0, [gettimeofday]) > $self->step) {
|
||||
die("ERROR: step elapsed and $fname not found");
|
||||
}
|
||||
|
||||
sleep $tv->{readfrompollinterval};
|
||||
};
|
||||
|
||||
# return file contents
|
||||
return path($fname)->slurp;
|
||||
}
|
||||
|
||||
sub run_irtt ($$) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $t = $target;
|
||||
my $tv = $t->{vars};
|
||||
my $p = $self->{properties};
|
||||
|
||||
# choose clock for requested metric
|
||||
my $clock;
|
||||
if ($tv->{writeto}) {
|
||||
$clock = 'both';
|
||||
} else {
|
||||
$clock = $tv->{metric} =~ /(send|receive)/ ? 'wall' : 'monotonic';
|
||||
}
|
||||
|
||||
# build command
|
||||
my $count = $self->pings($t);
|
||||
my $interval = $tv->{interval};
|
||||
my $duration = $interval * $count;
|
||||
my @cmd = (
|
||||
$p->{binary}, 'client',
|
||||
'-i', $interval . 's',
|
||||
'-d', $duration . 's',
|
||||
'-Q',
|
||||
'--clock=' . $clock,
|
||||
'--tstamp=midpoint',
|
||||
'--stats=none',
|
||||
'-o', '-',
|
||||
);
|
||||
push @cmd, ("-l", $tv->{length}) if $tv->{length};
|
||||
push @cmd, "--hmac=" . $tv->{hmac} if $tv->{hmac};
|
||||
push @cmd, "--dscp=" . $tv->{dscp} if $tv->{dscp};
|
||||
push @cmd, "--fill=" . $tv->{fill} if $tv->{fill};
|
||||
push @cmd, "--sfill=" . $tv->{serverfill} if $tv->{serverfill};
|
||||
push @cmd, "--local=" . $tv->{localaddr} if $tv->{localaddr};
|
||||
push @cmd, "-$tv->{ipversion}" if $tv->{ipversion};
|
||||
push @cmd, $t->{addr};
|
||||
|
||||
# sleep, if requested
|
||||
usleep($tv->{sleep} * 1000000) if $tv->{sleep};
|
||||
|
||||
# execute irtt
|
||||
$self->do_debug("Executing @cmd");
|
||||
my $inh = gensym;
|
||||
my $outh = gensym;
|
||||
my $pid = open2($outh, $inh, @cmd);
|
||||
my $out = do { local $/; <$outh> };
|
||||
waitpid $pid,0;
|
||||
close $inh;
|
||||
close $outh;
|
||||
|
||||
# write json output atomically if writeto set (empty for errors)
|
||||
if ($tv->{writeto}) {
|
||||
path($p->{tmpdir}, $tv->{writeto})->spew($out);
|
||||
}
|
||||
|
||||
# die on non-zero status codes
|
||||
my $status = $? >> 8;
|
||||
die "ERROR: irtt client return code $status" if $status;
|
||||
|
||||
return $out
|
||||
}
|
||||
|
||||
sub nstos ($) {
|
||||
my $ns = shift;
|
||||
return $ns / 1000000000.0;
|
||||
}
|
||||
|
||||
sub median {
|
||||
my @vals = sort {$a <=> $b} @_;
|
||||
my $len = @vals;
|
||||
if ($len%2) {
|
||||
return $vals[int($len/2)];
|
||||
} else {
|
||||
return ($vals[int($len/2)-1] + $vals[int($len/2)])/2;
|
||||
}
|
||||
}
|
||||
|
||||
sub pingone ($$) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $t = $target;
|
||||
my $tv = $t->{vars};
|
||||
my $p = $self->{properties};
|
||||
|
||||
# if writeto set, create temp directory or remove temp file
|
||||
if ($tv->{writeto}) {
|
||||
if ($tv->{readfrom}) {
|
||||
die("ERROR: writeto and readfrom must not both be set for the same target");
|
||||
}
|
||||
my $d = $p->{tmpdir};
|
||||
if (-d $d) {
|
||||
path($d, $tv->{writeto})->remove;
|
||||
} else {
|
||||
mkdir $d or die("ERROR: unable to create temp dir $d ($!)");
|
||||
}
|
||||
}
|
||||
|
||||
# get json from irtt, or file if readfrom set
|
||||
my $json;
|
||||
if ($tv->{readfrom}) {
|
||||
$json = get_json_from_file($self, $target);
|
||||
} else {
|
||||
$json = run_irtt($self, $target);
|
||||
}
|
||||
die("ERROR: json content empty") if $json eq "";
|
||||
|
||||
# decode json
|
||||
my $dec = decode_json($json) or die "ERROR: decode_json failed $!";
|
||||
|
||||
# get times for chosen metric from json
|
||||
my @times;
|
||||
foreach my $rt ( @{$dec->{'round_trips'}} ) {
|
||||
if ($rt->{'lost'} eq 'false') {
|
||||
my $ns;
|
||||
my $dl = $rt->{'delay'};
|
||||
my $pv = $rt->{'ipdv'};
|
||||
for ($tv->{metric}) {
|
||||
/^(rtt|send|receive)$/ && do {
|
||||
$ns = $dl->{$tv->{metric}};
|
||||
if ($ns < 0) {
|
||||
$ns = 0;
|
||||
}
|
||||
next;
|
||||
};
|
||||
/^ipdv$/ && do {
|
||||
$ns = $pv->{'rtt'};
|
||||
next;
|
||||
};
|
||||
/^send_ipdv$/ && do {
|
||||
$ns = $pv->{'send'};
|
||||
next;
|
||||
};
|
||||
/^receive_ipdv$/ && do {
|
||||
$ns = $pv->{'receive'};
|
||||
next;
|
||||
};
|
||||
die("ERROR: impossible metric $tv->{metric}")
|
||||
}
|
||||
push @times, nstos(abs($ns)) if looks_like_number($ns);
|
||||
}
|
||||
}
|
||||
|
||||
# push an extra median value for ipdv, which has one fewer values
|
||||
# than pings, so there isn't a lost packet reported
|
||||
if ($tv->{metric} =~ /ipdv/ && @times > 0) {
|
||||
push @times, median(@times);
|
||||
}
|
||||
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
1;
|
||||
281
debian/smokeping/usr/share/perl5/Smokeping/probes/LDAP.pm
vendored
Normal file
281
debian/smokeping/usr/share/perl5/Smokeping/probes/LDAP.pm
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
package Smokeping::probes::LDAP;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::LDAP>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::LDAP>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use Smokeping::probes::passwordchecker;
|
||||
use Net::LDAP;
|
||||
use Time::HiRes qw(gettimeofday sleep);
|
||||
use base qw(Smokeping::probes::passwordchecker);
|
||||
|
||||
# don't bail out if IO::Socket::SSL
|
||||
# can't be loaded, just warn
|
||||
# about it when doing starttls
|
||||
|
||||
my $havessl = 0;
|
||||
|
||||
eval "use IO::Socket::SSL;";
|
||||
$havessl = 1 unless $@;
|
||||
|
||||
my $DEFAULTINTERVAL = 1;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::LDAP - a LDAP probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures LDAP search latency for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
This probe measures LDAP query latency for SmokePing.
|
||||
The query is specified by the target-specific variable `filter' and,
|
||||
optionally, by the target-specific variable `base'. The attributes
|
||||
queried can be specified in the comma-separated list `attrs'.
|
||||
|
||||
The TCP port of the LDAP server and the LDAP version to be used can
|
||||
be specified by the variables `port' and `version'.
|
||||
|
||||
The probe can issue the starttls command to convert the connection
|
||||
into encrypted mode, if so instructed by the `start_tls' variable.
|
||||
This requires the 'IO::Socket::SSL' perl module to be installed.
|
||||
|
||||
The probe can also optionally do an authenticated LDAP bind, if the `binddn'
|
||||
variable is present. The password to be used can be specified by the
|
||||
target-specific variable `password' or in an external file.
|
||||
The location of this file is given in the probe-specific variable
|
||||
`passwordfile'. See Smokeping::probes::passwordchecker(3pm) for the format
|
||||
of this file (summary: colon-separated triplets of the form
|
||||
`<host>:<bind-dn>:<password>')
|
||||
|
||||
The probe tries to be nice to the server and does not send authentication
|
||||
requests more frequently than once every X seconds, where X is the value
|
||||
of the target-specific "min_interval" variable ($DEFAULTINTERVAL by default).
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
There should be a way of specifying TLS options, such as the certificates
|
||||
involved etc.
|
||||
|
||||
The probe has an ugly way of working around the fact that the
|
||||
IO::Socket::SSL class complains if start_tls() is done more than once
|
||||
in the same program. But It Works For Me (tm).
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub ProbeDesc {
|
||||
return "LDAP queries";
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout};
|
||||
return $h;
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'filter' ],
|
||||
port => {
|
||||
_re => '\d+',
|
||||
_doc => "TCP port of the LDAP server",
|
||||
_example => 389,
|
||||
},
|
||||
|
||||
scheme => {
|
||||
_re => '(ldap|ldaps|ldapi)',
|
||||
_doc => "LDAP scheme to use: ldap, ldaps or ldapi",
|
||||
_example => 'ldap',
|
||||
_default => 'ldap',
|
||||
},
|
||||
|
||||
|
||||
version => {
|
||||
_re => '\d+',
|
||||
_doc => "The LDAP version to be used.",
|
||||
_example => 3,
|
||||
},
|
||||
start_tls => {
|
||||
_doc => "If true, encrypt the connection with the starttls command. Disabled by default.",
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: start_tls defined but IO::Socket::SSL couldn't be loaded"
|
||||
if $val and not $havessl;
|
||||
return undef;
|
||||
},
|
||||
_example => "1",
|
||||
},
|
||||
timeout => {
|
||||
_doc => "LDAP query timeout in seconds.",
|
||||
_re => '\d+',
|
||||
_example => 10,
|
||||
_default => 5,
|
||||
},
|
||||
base => {
|
||||
_doc => "The base to be used in the LDAP query",
|
||||
_example => "dc=foo,dc=bar",
|
||||
},
|
||||
filter => {
|
||||
_doc => "The actual search to be made",
|
||||
_example => "uid=testuser",
|
||||
},
|
||||
attrs => {
|
||||
_doc => "The attributes queried.",
|
||||
_example => "uid,someotherattr",
|
||||
},
|
||||
binddn => {
|
||||
_doc => "If present, authenticate the LDAP bind with this DN.",
|
||||
_example => "uid=testuser,dc=foo,dc=bar",
|
||||
},
|
||||
password => {
|
||||
_doc => "The password to be used, if not present in <passwordfile>.",
|
||||
_example => "mypass",
|
||||
},
|
||||
mininterval => {
|
||||
_default => $DEFAULTINTERVAL,
|
||||
_doc => "The minimum interval between each query sent, in (possibly fractional) second
|
||||
s.",
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
scope => {
|
||||
_doc => "The scope of the query. Can be either 'base', 'one' or 'sub'. See the Net::LDAP documentation for details.",
|
||||
_example => "one",
|
||||
_re => "(base|one|sub)",
|
||||
_default => "sub",
|
||||
},
|
||||
verify => {
|
||||
_doc => "The TLS verification level. Can be either 'none', 'optional', 'require'. See the Net::LDAPS documentation for details.",
|
||||
_example => "optional",
|
||||
_re => "(none|optional|require)",
|
||||
_default => "require",
|
||||
},
|
||||
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $host = $target->{addr};
|
||||
my $vars = $target->{vars};
|
||||
|
||||
my $version = $vars->{version} || 3;
|
||||
my $port = $vars->{port};
|
||||
|
||||
my $mininterval = $vars->{mininterval};
|
||||
|
||||
my $binddn = $vars->{binddn};
|
||||
my $scheme = $vars->{scheme};
|
||||
my $timeout = $vars->{timeout};
|
||||
|
||||
my $scope = $vars->{scope};
|
||||
|
||||
|
||||
my $verify = $vars->{verify};
|
||||
|
||||
my $password;
|
||||
if (defined $binddn) {
|
||||
$password = $self->password($host, $binddn);
|
||||
if (defined $vars->{password} and
|
||||
$vars->{password} ne ($self->{properties}{password}||"")) {
|
||||
$password = $vars->{password};
|
||||
}
|
||||
$password ||= $self->{properties}{password};
|
||||
}
|
||||
|
||||
my $start_tls = $vars->{start_tls};
|
||||
|
||||
my $filter = $vars->{filter};
|
||||
|
||||
my $base = $vars->{base};
|
||||
|
||||
my $attrs = $vars->{attrs};
|
||||
|
||||
my @attrs = split(/,/, $attrs||"");
|
||||
my $attrsref = @attrs ? \@attrs : undef;
|
||||
|
||||
my @times;
|
||||
|
||||
my $start;
|
||||
for (1..$self->pings($target)) {
|
||||
if (defined $start) {
|
||||
my $elapsed = gettimeofday() - $start;
|
||||
my $timeleft = $mininterval - $elapsed;
|
||||
sleep $timeleft if $timeleft > 0;
|
||||
}
|
||||
local $IO::Socket::SSL::SSL_Context_obj; # ugly but necessary
|
||||
$start = gettimeofday();
|
||||
my $ldap = new Net::LDAP($host, scheme => $scheme, port => $port, version => $version, timeout => $timeout, verify => $verify )
|
||||
or do {
|
||||
$self->do_log("connection error on $host: $!");
|
||||
next;
|
||||
};
|
||||
my $mesg;
|
||||
if ($start_tls) {
|
||||
$mesg = $ldap->start_tls;
|
||||
$mesg->code and do {
|
||||
$self->do_log("start_tls error on $host: " . $mesg->error);
|
||||
$ldap->unbind;
|
||||
next;
|
||||
}
|
||||
}
|
||||
if (defined $binddn and defined $password) {
|
||||
$mesg = $ldap->bind($binddn, password => $password);
|
||||
} else {
|
||||
if (defined $binddn and not defined $password) {
|
||||
$self->do_debug("No password specified for $binddn, doing anonymous bind instead");
|
||||
}
|
||||
$mesg = $ldap->bind();
|
||||
}
|
||||
$mesg->code and do {
|
||||
$self->do_log("bind error on $host: " . $mesg->error);
|
||||
$ldap->unbind;
|
||||
next;
|
||||
};
|
||||
$mesg = $ldap->search(base => $base, filter => $filter,
|
||||
attrs => $attrsref, scope => $scope);
|
||||
$mesg->code and do {
|
||||
$self->do_log("filter error on $host: " . $mesg->error);
|
||||
$ldap->unbind;
|
||||
next;
|
||||
};
|
||||
$ldap->unbind;
|
||||
my $end = gettimeofday();
|
||||
my $elapsed = $end - $start;
|
||||
|
||||
$self->do_debug("$host: LDAP query $_ took $elapsed seconds");
|
||||
|
||||
push @times, $elapsed;
|
||||
}
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
203
debian/smokeping/usr/share/perl5/Smokeping/probes/NFSping.pm
vendored
Normal file
203
debian/smokeping/usr/share/perl5/Smokeping/probes/NFSping.pm
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
package Smokeping::probes::NFSping;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::NFSping>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::NFSping>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::base);
|
||||
use IPC::Open3;
|
||||
use Symbol;
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::NFSping - NFSping Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates NFSping as a probe into smokeping. The variable B<binary> must
|
||||
point to your copy of the NFSping program.
|
||||
|
||||
NFSping can be downloaded from:
|
||||
|
||||
L<https://github.com/mprovost/NFSping>
|
||||
|
||||
In B<blazemode>, NFSping sends one more ping than requested, and discards
|
||||
the first RTT value returned as it's likely to be an outlier.
|
||||
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
Matt Provost <mprovost@termcap.net>
|
||||
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 $binary = join(" ", $self->binary);
|
||||
my $testhost = $self->testhost;
|
||||
my $return = `$binary -C 1 $testhost 2>&1`;
|
||||
croak "ERROR: nfsping ('$binary -C 1 $testhost') could not be run: $return"
|
||||
if $return =~ m/not found/;
|
||||
|
||||
if ($return =~ m/([0-9.]+)\sms\s+.*\n.*\n.*:\s+([0-9.]+)/ and $1 > 0){
|
||||
$self->{pingfactor} = 1000 * $2/$1;
|
||||
if ($1 != $2){
|
||||
warn "### nfsping seems to report in ", $2/$1, " milliseconds (old version?)";
|
||||
}
|
||||
} else {
|
||||
$self->{pingfactor} = 1000; # Gives us a good-guess default
|
||||
warn "### assuming you are using an nfsping copy reporting in milliseconds\n";
|
||||
}
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc{
|
||||
return "NFSping";
|
||||
}
|
||||
|
||||
# derived class (ie. RemoteNFSping) can override this
|
||||
sub binary {
|
||||
my $self = shift;
|
||||
return $self->{properties}{binary};
|
||||
}
|
||||
|
||||
# derived class (ie. NFSping6) can override this
|
||||
sub testhost {
|
||||
return "localhost";
|
||||
}
|
||||
|
||||
sub ping ($){
|
||||
my $self = shift;
|
||||
# do NOT call superclass ... the ping method MUST be overridden
|
||||
|
||||
# increment the internal 'rounds' counter
|
||||
$self->increment_rounds_count;
|
||||
|
||||
my %upd;
|
||||
my $inh = gensym;
|
||||
my $outh = gensym;
|
||||
my $errh = gensym;
|
||||
# pinging nothing is pointless
|
||||
return unless @{$self->addresses};
|
||||
my @params = () ;
|
||||
push @params, "-t" . int(1000 * $self->{properties}{timeout}) if $self->{properties}{timeout};
|
||||
push @params, "-i" . int(1000 * $self->{properties}{mininterval});
|
||||
push @params, "-p" . int(1000 * $self->{properties}{hostinterval}) if $self->{properties}{hostinterval};
|
||||
if (($self->{properties}{tcp} || '') eq 'true'){
|
||||
push @params, "-T";
|
||||
}
|
||||
|
||||
|
||||
my $pings = $self->pings;
|
||||
if (($self->{properties}{blazemode} || '') eq 'true'){
|
||||
$pings++;
|
||||
}
|
||||
my @cmd = (
|
||||
$self->binary,
|
||||
#'-C', $pings, '-q','-B1','-r1',
|
||||
'-C', $pings, '-q',
|
||||
@params,
|
||||
@{$self->addresses});
|
||||
$self->do_debug("Executing @cmd");
|
||||
my $pid = open3($inh,$outh,$errh, @cmd);
|
||||
$self->{rtts}={};
|
||||
while (<$errh>){
|
||||
chomp;
|
||||
$self->do_debug("Got nfsping output: '$_'");
|
||||
next unless /^\S+\s+:\s+[-\d\.]/; #filter out error messages from nfsping
|
||||
my @times = split /\s+/;
|
||||
my $ip = shift @times;
|
||||
next unless ':' eq shift @times; #drop the colon
|
||||
if (($self->{properties}{blazemode} || '') eq 'true'){
|
||||
shift @times;
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep /^\d/, @times;
|
||||
map { $self->{rtts}{$_} = [@times] } @{$self->{addrlookup}{$ip}} ;
|
||||
}
|
||||
waitpid $pid,0;
|
||||
my $rc = $?;
|
||||
carp join(" ",@cmd) . " returned with exit code $rc. run with debug enabled to get more information" unless $rc == 0;
|
||||
close $inh;
|
||||
close $outh;
|
||||
close $errh;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'binary' ],
|
||||
binary => {
|
||||
_sub => sub {
|
||||
my ($val) = @_;
|
||||
return undef if $ENV{SERVER_SOFTWARE}; # don't check for nfsping presence in cgi mode
|
||||
return "ERROR: NFSping 'binary' does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
_doc => "The location of your nfsping binary.",
|
||||
_example => '/usr/local/bin/nfsping',
|
||||
},
|
||||
blazemode => {
|
||||
_re => '(true|false)',
|
||||
_example => 'true',
|
||||
_doc => "Send an extra ping and then discard the first answer since the first is bound to be an outlier.",
|
||||
|
||||
},
|
||||
tcp => {
|
||||
_re => '(true|false)',
|
||||
_example => 'true',
|
||||
_doc => "Use TCP insteadof UDP.",
|
||||
},
|
||||
timeout => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => 1.5,
|
||||
_doc => <<DOC,
|
||||
The nfsping "-t" parameter, but in (possibly fractional) seconds rather than
|
||||
milliseconds, for consistency with other Smokeping probes.
|
||||
DOC
|
||||
},
|
||||
hostinterval => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => 1.5,
|
||||
_doc => <<DOC,
|
||||
The nfsping "-p" parameter, but in (possibly fractional) seconds rather than
|
||||
milliseconds, for consistency with other Smokeping probes. This
|
||||
parameter sets the time that nfsping waits between successive packets
|
||||
to an individual target.
|
||||
DOC
|
||||
},
|
||||
mininterval => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => .001,
|
||||
_default => .01,
|
||||
_doc => <<DOC,
|
||||
The nfsping "-i" parameter, but in (probably fractional) seconds rather than
|
||||
milliseconds, for consistency with other Smokeping probes. This is the
|
||||
interval between pings to successive targets.
|
||||
DOC
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
206
debian/smokeping/usr/share/perl5/Smokeping/probes/OpenSSHEOSPing.pm
vendored
Normal file
206
debian/smokeping/usr/share/perl5/Smokeping/probes/OpenSSHEOSPing.pm
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
package Smokeping::probes::OpenSSHEOSPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::OpenSSHEOSPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::OpenSSHEOSPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Net::OpenSSH;
|
||||
use Carp;
|
||||
|
||||
my $e = "=";
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::OpenSSHEOSPing - Arista EOS SSH Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Connect to Arista EOS via OpenSSH to run ping commands.
|
||||
This probe uses the "ping" cli of the Arista EOS. You have
|
||||
the option to specify which interface the ping is sourced from as well.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
${e}head2 EOS configuration
|
||||
|
||||
The EOS device should have a username/password configured, and
|
||||
the ssh server must not be disabled.
|
||||
|
||||
Make sure to connect to the remote host once from the command line as the
|
||||
user who is running smokeping. On the first connect ssh will ask to add the
|
||||
new host to its known_hosts file. This will not happen automatically so the
|
||||
script will fail to login until the ssh key of your EOS box is in the
|
||||
known_hosts file.
|
||||
|
||||
${e}head2 Requirements
|
||||
|
||||
This module requires the L<Net::OpenSSH> and L<IO::Pty> perl modules.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Bill Fenner E<lt>fenner@aristanetworks.comE<gt>
|
||||
|
||||
based on L<Smokeping::Probes::OpenSSHJunOSPing> by Tobias Oetiker E<lt>tobi@oetiker.chE<gt>,
|
||||
which itself is
|
||||
based on L<Smokeping::probes::TelnetJunOSPing> by S H A N E<lt>shanali@yahoo.comE<gt>.
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub new($$$)
|
||||
{
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
|
||||
$self->{pingfactor} = 1000; # Gives us a good-guess default
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
return "Arista EOS - ICMP Echo Pings ($bytes Bytes)";
|
||||
}
|
||||
|
||||
sub pingone ($$){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $source = $target->{vars}{source};
|
||||
my $dest = $target->{vars}{host};
|
||||
my $psource = $target->{vars}{psource};
|
||||
my @output = ();
|
||||
my $login = $target->{vars}{eosuser};
|
||||
my $password = $target->{vars}{eospass};
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
my $pings = $self->pings($target);
|
||||
my $unpriv = $target->{vars}{unpriv} || 0;
|
||||
|
||||
# do NOT call superclass ... the ping method MUST be overridden
|
||||
my %upd;
|
||||
my @args = ();
|
||||
|
||||
my $ssh = Net::OpenSSH->new(
|
||||
$source,
|
||||
$login ? ( user => $login ) : (),
|
||||
$password ? ( password => $password ) : (),
|
||||
timeout => 60,
|
||||
batch_mode => 1
|
||||
);
|
||||
if ($ssh->error) {
|
||||
$self->do_log( "OpenSSHEOSPing connecting $source: ".$ssh->error );
|
||||
return ();
|
||||
};
|
||||
|
||||
if ( $unpriv ) {
|
||||
@output = $ssh->capture("ping $dest");
|
||||
} else {
|
||||
if ( $psource ) {
|
||||
@output = $ssh->capture("ping $dest repeat $pings size $bytes source $psource");
|
||||
} else {
|
||||
@output = $ssh->capture("ping $dest repeat $pings size $bytes");
|
||||
}
|
||||
}
|
||||
|
||||
if ($ssh->error) {
|
||||
$self->do_log( "OpenSSHEOSPing running commands on $source: ".$ssh->error );
|
||||
return ();
|
||||
};
|
||||
|
||||
if ($output[ 0 ] !~ /^PING/) {
|
||||
$self->do_log( "OpenSSHEOSPing got error on $source for $dest: "." / ".join( @output ) );
|
||||
return ();
|
||||
}
|
||||
my @times = ();
|
||||
for (@output){
|
||||
chomp;
|
||||
/^\d+ bytes from .+: icmp_req=\d+ ttl=\d+ time=(\d+\.\d+) ms$/ and push @times,$1;
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} @times;
|
||||
return @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
packetsize => {
|
||||
_doc => <<DOC,
|
||||
The (optional) packetsize option lets you configure the packetsize for
|
||||
the pings sent.
|
||||
DOC
|
||||
_default => 100,
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: packetsize must be between 12 and 64000"
|
||||
unless $val >= 12 and $val <= 64000;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'eosuser', 'eospass', 'source' ],
|
||||
source => {
|
||||
_doc => <<DOC,
|
||||
The source option specifies the EOS device that is going to run the ping commands. This
|
||||
address will be used for the ssh connection.
|
||||
DOC
|
||||
_example => "192.168.2.1",
|
||||
},
|
||||
psource => {
|
||||
_doc => <<DOC,
|
||||
The (optional) psource option specifies an alternate IP address or
|
||||
Interface from which you wish to source your pings from. Routers
|
||||
can have many many IP addresses, and interfaces. When you ping from a
|
||||
router you have the ability to choose which interface and/or which IP
|
||||
address the ping is sourced from. Specifying an IP/interface does not
|
||||
necessarily specify the interface from which the ping will leave, but
|
||||
will specify which address the packet(s) appear to come from. If this
|
||||
option is left out the EOS Device will source the packet automatically
|
||||
based on routing and/or metrics. If this doesn't make sense to you
|
||||
then just leave it out.
|
||||
DOC
|
||||
_example => "192.168.2.129",
|
||||
},
|
||||
eosuser => {
|
||||
_doc => <<DOC,
|
||||
The eosuser option allows you to specify a username that has ping
|
||||
capability on the EOS Device.
|
||||
DOC
|
||||
_example => 'user',
|
||||
},
|
||||
eospass => {
|
||||
_doc => <<DOC,
|
||||
The eospass option allows you to specify the password for the username
|
||||
specified with the option eosuser.
|
||||
DOC
|
||||
_example => 'password',
|
||||
},
|
||||
unpriv => {
|
||||
_doc => <<DOC,
|
||||
If the account is unprivileged, specify the 'unpriv' option.
|
||||
You must also configure "pings = 5", since that is the only
|
||||
value supported, and values specified for packetsize or
|
||||
psource are ignored.
|
||||
DOC
|
||||
_example => '1',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
207
debian/smokeping/usr/share/perl5/Smokeping/probes/OpenSSHJunOSPing.pm
vendored
Normal file
207
debian/smokeping/usr/share/perl5/Smokeping/probes/OpenSSHJunOSPing.pm
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
package Smokeping::probes::OpenSSHJunOSPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::OpenSSHJunOSPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::OpenSSHJunOSPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Net::OpenSSH;
|
||||
use Carp;
|
||||
|
||||
my $e = "=";
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::OpenSSHJunOSPing - Juniper SSH JunOS Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Connect to Juniper JunOS via OpenSSH to run ping commands.
|
||||
This probe uses the "extended ping" of the Juniper JunOS. You have
|
||||
the option to specify which interface the ping is sourced from as well.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
${e}head2 JunOS configuration
|
||||
|
||||
The JunOS device should have a username/password configured, as well as
|
||||
the ability to connect to the VTY(s).
|
||||
|
||||
Make sure to connect to the remote host once from the command line as the
|
||||
user who is running smokeping. On the first connect ssh will ask to add the
|
||||
new host to its known_hosts file. This will not happen automatically so the
|
||||
script will fail to login until the ssh key of your juniper box is in the
|
||||
known_hosts file.
|
||||
|
||||
Some JunOS devices have a maximum of 5 VTYs available, so be careful not
|
||||
to hit a limit with the 'forks' variable.
|
||||
|
||||
${e}head2 Requirements
|
||||
|
||||
This module requires the L<Net::OpenSSH> and L<IO::Pty>.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
|
||||
|
||||
based on L<Smokeping::probes::TelnetJunOSPing> by S H A N E<lt>shanali@yahoo.comE<gt>.
|
||||
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} ) {
|
||||
$self->{pingfactor} = 1000; # Gives us a good-guess default
|
||||
print "### assuming you are using an JunOS reporting in milliseconds\n";
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
my $ret = "Juniper JunOS - ICMP Echo Pings ($bytes Bytes";
|
||||
if (defined (my $tos = $self->{properties}{tos})){
|
||||
$ret = " tos $tos";
|
||||
}
|
||||
return $ret.")";
|
||||
}
|
||||
|
||||
sub pingone ($$){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $source = $target->{vars}{source};
|
||||
my $dest = $target->{vars}{host};
|
||||
my $psource = $target->{vars}{psource};
|
||||
my @output = ();
|
||||
my $login = $target->{vars}{junosuser};
|
||||
my $password = $target->{vars}{junospass};
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
my $tos = $self->{properties}{tos};
|
||||
my $pings = $self->pings($target);
|
||||
|
||||
# do NOT call superclass ... the ping method MUST be overridden
|
||||
my %upd;
|
||||
my @args = ();
|
||||
|
||||
my $ssh = Net::OpenSSH->new(
|
||||
$source,
|
||||
$login ? ( user => $login ) : (),
|
||||
$password ? ( password => $password ) : (),
|
||||
timeout => 60
|
||||
);
|
||||
if ($ssh->error) {
|
||||
warn "OpenSSHJunOSPing connecting $source: ".$ssh->error."\n";
|
||||
return undef;
|
||||
};
|
||||
my $tosadd = '';
|
||||
if ( defined $tos){
|
||||
$tosadd = " tos $tos";
|
||||
}
|
||||
if ( $psource ) {
|
||||
@output = $ssh->capture("ping $dest count $pings size $bytes source $psource$tosadd");
|
||||
} else {
|
||||
@output = $ssh->capture("ping $dest count $pings size $bytes$tosadd");
|
||||
}
|
||||
$ssh->system("quit");
|
||||
|
||||
my @times = ();
|
||||
for (@output){
|
||||
chomp;
|
||||
/^\d+ bytes from \S+[:,] icmp_seq=\d+ (?:ttl|hlim)=\d+ time=(\d+\.\d+) ms$/ and push @times,$1;
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} @times;
|
||||
return @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
packetsize => {
|
||||
_doc => <<DOC,
|
||||
The (optional) packetsize option lets you configure the packetsize for
|
||||
the pings sent.
|
||||
DOC
|
||||
_default => 100,
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: packetsize must be between 12 and 64000"
|
||||
unless $val >= 12 and $val <= 64000;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
tos => {
|
||||
_doc => <<DOC,
|
||||
The (optional) type of service for the pings sent.
|
||||
DOC
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: tos must be 0-255"
|
||||
if $val and not ( $val =~ /^\d+$/ and int($val) <= 255);
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'junosuser', 'junospass', 'source' ],
|
||||
source => {
|
||||
_doc => <<DOC,
|
||||
The source option specifies the JunOS device that is going to run the ping commands. This
|
||||
address will be used for the ssh connection.
|
||||
DOC
|
||||
_example => "192.168.2.1",
|
||||
},
|
||||
psource => {
|
||||
_doc => <<DOC,
|
||||
The (optional) psource option specifies an alternate IP address or
|
||||
Interface from which you wish to source your pings from. Routers
|
||||
can have many many IP addresses, and interfaces. When you ping from a
|
||||
router you have the ability to choose which interface and/or which IP
|
||||
address the ping is sourced from. Specifying an IP/interface does not
|
||||
necessarily specify the interface from which the ping will leave, but
|
||||
will specify which address the packet(s) appear to come from. If this
|
||||
option is left out the JunOS Device will source the packet automatically
|
||||
based on routing and/or metrics. If this doesn't make sense to you
|
||||
then just leave it out.
|
||||
DOC
|
||||
_example => "192.168.2.129",
|
||||
},
|
||||
junosuser => {
|
||||
_doc => <<DOC,
|
||||
The junosuser option allows you to specify a username that has ping
|
||||
capability on the JunOS Device.
|
||||
DOC
|
||||
_example => 'user',
|
||||
},
|
||||
junospass => {
|
||||
_doc => <<DOC,
|
||||
The junospass option allows you to specify the password for the username
|
||||
specified with the option junosuser.
|
||||
DOC
|
||||
_example => 'password',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
203
debian/smokeping/usr/share/perl5/Smokeping/probes/Qstat.pm
vendored
Normal file
203
debian/smokeping/usr/share/perl5/Smokeping/probes/Qstat.pm
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
package Smokeping::probes::Qstat;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::Qstat>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::Qstat>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use IPC::Open3;
|
||||
use Symbol;
|
||||
use Carp;
|
||||
use Time::HiRes qw(usleep);
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::Qstat - Qstat Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates Qstat as a probe into smokeping. The variable B<binary> must
|
||||
point to your copy of the Qstat program.
|
||||
|
||||
Make sure to set your pings to 10, most Quake servers seem to throttle
|
||||
after 10 rapid pings.
|
||||
|
||||
Set the game parameter to one of the valid options to check a different type
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Walter Huf <hufman@gmail.com>
|
||||
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 $binary = join(" ", $self->binary);
|
||||
my $return = `$binary 2>&1`;
|
||||
$self->{enable}{S} = (`$binary 2>&1` =~ /\s-S\s/);
|
||||
croak "ERROR: Qstat ('$binary') could not be run: $return"
|
||||
if $return =~ m/not found/;
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $game = $self->{properties}{game}||'q3s';
|
||||
return "Game server $game pings";
|
||||
}
|
||||
|
||||
# derived class can override this
|
||||
sub binary {
|
||||
my $self = shift;
|
||||
return $self->{properties}{binary};
|
||||
}
|
||||
|
||||
sub pingone($$) {
|
||||
my $self = shift;
|
||||
my $address = shift;
|
||||
|
||||
my @times;
|
||||
for (my $count = 0; $count < $self->pings($address); $count++) {
|
||||
push @times, $self->pinghost($address);
|
||||
}
|
||||
return @times
|
||||
}
|
||||
|
||||
sub pinghost($$) {
|
||||
my $self = shift;
|
||||
my $address = shift;
|
||||
|
||||
my $inh = gensym;
|
||||
my $outh = gensym;
|
||||
my $errh = gensym;
|
||||
my $time;
|
||||
# pinging nothing is pointless
|
||||
return unless $address;
|
||||
$address = $address->{addr};
|
||||
my @params = ();
|
||||
push @params, "-nocfg";
|
||||
push @params, "-xml";
|
||||
push @params, "-timeout", $self->{properties}{timeout} if $self->{properties}{timeout};
|
||||
push @params, "-srcip", $self->{properties}{sourceaddress} if $self->{properties}{sourceaddress};
|
||||
push @params, "-srcport", $self->{properties}{sourceport} if $self->{properties}{sourceport};
|
||||
push @params, "-" . $self->{properties}{game};
|
||||
if ($self->{properties}{port} && $address !~ /:/) {
|
||||
push @params, $address . ':' . $self->{properties}{port};
|
||||
} else {
|
||||
push @params, $address;
|
||||
}
|
||||
|
||||
my @cmd = (
|
||||
$self->binary,
|
||||
@params);
|
||||
$self->do_debug("Executing @cmd");
|
||||
my $pid = open3($inh,$outh,$errh, @cmd);
|
||||
while (<$outh>){
|
||||
chomp;
|
||||
$self->do_debug("Got quakestat output: '$_'");
|
||||
next unless /^\s*<ping>(\d+)<\/ping>\s*$/; #filter out the ping latency line
|
||||
$time = $1;
|
||||
}
|
||||
waitpid $pid,0;
|
||||
my $rc = $?;
|
||||
carp join(" ",@cmd) . " returned with exit code $rc. run with debug enabled to get more information" unless $rc == 0;
|
||||
close $inh;
|
||||
close $outh;
|
||||
close $errh;
|
||||
return $time/1000.0 if defined($time);
|
||||
return;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'binary' ],
|
||||
binary => {
|
||||
_sub => sub {
|
||||
my ($val) = @_;
|
||||
return undef if $ENV{SERVER_SOFTWARE}; # don't check for qstat presence in cgi mode
|
||||
return "ERROR: Qstat 'binary' does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
_doc => "The location of your quakestat binary.",
|
||||
_example => '/usr/bin/quakestatba',
|
||||
},
|
||||
game => {
|
||||
_example => "nexuizs",
|
||||
_default => "q3s",
|
||||
_doc => <<DOC,
|
||||
What game type to check, from the -default flag of quakestat
|
||||
DOC
|
||||
},
|
||||
port => {
|
||||
_re => '\d+',
|
||||
_example => 27970,
|
||||
_doc => <<DOC,
|
||||
The game server port to check. It can also be overridden by adding :port to the host parameter in the Target config.
|
||||
DOC
|
||||
},
|
||||
timeout => {
|
||||
_re => '\d+',
|
||||
_example => 1,
|
||||
_doc => <<DOC,
|
||||
The quakestat "-timeout" parameter, in seconds.
|
||||
DOC
|
||||
},
|
||||
mininterval => {
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => .1,
|
||||
_default => .5,
|
||||
_doc => <<DOC,
|
||||
The minimum amount of time between sending a ping packet to the target.
|
||||
DOC
|
||||
},
|
||||
sourceaddress => {
|
||||
_re => '\d+(\.\d+){3}',
|
||||
_example => '192.168.0.1',
|
||||
_doc => <<DOC,
|
||||
The quakestat "-srcip" parameter . From quakestat(1):
|
||||
|
||||
Send packets using this IP address
|
||||
DOC
|
||||
},
|
||||
sourceport => {
|
||||
_re => '\d{1,5}(-\d{1,5})?',
|
||||
_example => '9923-9943',
|
||||
_sub => sub {
|
||||
my ($val) = @_;
|
||||
my @ports = split('-', $val);
|
||||
if (scalar @ports == 2 and $ports[0] > $ports[1]) {
|
||||
return "ERROR: Qstat invalid source port range";
|
||||
}
|
||||
return undef;
|
||||
},
|
||||
_doc => <<DOC,
|
||||
The quakestat "-srcport" parameter . From quakestat(1):
|
||||
|
||||
Send packets from these network ports
|
||||
DOC
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
264
debian/smokeping/usr/share/perl5/Smokeping/probes/Radius.pm
vendored
Normal file
264
debian/smokeping/usr/share/perl5/Smokeping/probes/Radius.pm
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
package Smokeping::probes::Radius;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::Radius>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::Radius>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::passwordchecker);
|
||||
use Authen::Radius;
|
||||
use Time::HiRes qw(gettimeofday sleep);
|
||||
use Carp;
|
||||
|
||||
my $DEFAULTINTERVAL = 1;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::Radius - a RADIUS authentication probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures RADIUS authentication latency for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
This probe measures RADIUS (RFC 2865) authentication latency for SmokePing.
|
||||
|
||||
The username to be tested is specified in either the probe-specific or the
|
||||
target-specific variable `username', with the target-specific one overriding
|
||||
the probe-specific one.
|
||||
|
||||
The password can be specified either (in order of precedence, with
|
||||
the latter overriding the former) in the probe-specific variable
|
||||
`password', in an external file or in the target-specific variable
|
||||
`password'. The location of this file is given in the probe-specific
|
||||
variable `passwordfile'. See Smokeping::probes::passwordchecker(3pm) for the
|
||||
format of this file (summary: colon-separated triplets of the form
|
||||
`<host>:<username>:<password>')
|
||||
|
||||
The RADIUS protocol requires a shared secret between the server and the client.
|
||||
This secret can be specified either (in order of precedence, with the latter
|
||||
overriding the former) in the probe-specific variable `secret', in an external file
|
||||
or in the target-specific variable `secret'.
|
||||
This external file is located by the probe-specific variable `secretfile', and it should
|
||||
contain whitespace-separated pairs of the form `<host> <secret>'. Comments and blank lines
|
||||
are OK.
|
||||
|
||||
If the optional probe-specific variable `nas_ip_address' is specified, its
|
||||
value is inserted into the authentication requests as the `NAS-IP-Address'
|
||||
RADIUS attribute.
|
||||
|
||||
The probe tries to be nice to the server and does not send authentication
|
||||
requests more frequently than once every X seconds, where X is the value
|
||||
of the target-specific "min_interval" variable ($DEFAULTINTERVAL by default).
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
There should be a more general way of specifying RADIUS attributes.
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub ProbeDesc {
|
||||
return "RADIUS queries";
|
||||
}
|
||||
|
||||
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}) {
|
||||
if (defined $self->{properties}{secretfile}) {
|
||||
my @stat = stat($self->{properties}{secretfile});
|
||||
my $mode = $stat[2];
|
||||
carp("Warning: secret file $self->{properties}{secretfile} is world-readable\n")
|
||||
if defined $mode and $mode & 04;
|
||||
open(S, "<$self->{properties}{secretfile}")
|
||||
or croak("Error opening specified secret file $self->{properties}{secretfile}: $!");
|
||||
while (<S>) {
|
||||
chomp;
|
||||
next unless /\S/;
|
||||
next if /^\s*#/;
|
||||
my ($host, $secret) = split;
|
||||
carp("Line $. in $self->{properties}{secretfile} is invalid"), next
|
||||
unless defined $host and defined $secret;
|
||||
$self->secret($host, $secret);
|
||||
}
|
||||
close S;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub secret {
|
||||
my $self = shift;
|
||||
my $host = shift;
|
||||
my $newval = shift;
|
||||
|
||||
$self->{secret}{$host} = $newval if defined $newval;
|
||||
return $self->{secret}{$host};
|
||||
}
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $host = $target->{addr};
|
||||
my $vars = $target->{vars};
|
||||
my $mininterval = $vars->{mininterval};
|
||||
my $username = $vars->{username};
|
||||
my $secret = $self->secret($host);
|
||||
if (defined $vars->{secret} and
|
||||
$vars->{secret} ne ($self->{properties}{secret}||"")) {
|
||||
$secret = $vars->{secret};
|
||||
}
|
||||
$secret ||= $self->{properties}{secret};
|
||||
|
||||
my $timeout = $vars->{timeout};
|
||||
|
||||
my $allowreject = $vars->{allowreject};
|
||||
$self->do_debug("$host: radius allowreject is $allowreject");
|
||||
$allowreject=(defined($allowreject)
|
||||
and $allowreject eq "true");
|
||||
|
||||
$self->do_log("Missing RADIUS secret for $host"), return
|
||||
unless defined $secret;
|
||||
|
||||
$self->do_log("Missing RADIUS username for $host"), return
|
||||
unless defined $username;
|
||||
|
||||
my $password = $self->password($host, $username);
|
||||
if (defined $vars->{password} and
|
||||
$vars->{password} ne ($self->{properties}{password}||"")) {
|
||||
$password = $vars->{password};
|
||||
}
|
||||
$password ||= $self->{properties}{password};
|
||||
|
||||
$self->do_log("Missing RADIUS password for $host/$username"), return
|
||||
unless defined $password;
|
||||
|
||||
my $port = $vars->{port};
|
||||
$host .= ":$port" if defined $port;
|
||||
|
||||
my @times;
|
||||
my $elapsed;
|
||||
for (1..$self->pings($target)) {
|
||||
if (defined $elapsed) {
|
||||
my $timeleft = $mininterval - $elapsed;
|
||||
sleep $timeleft if $timeleft > 0;
|
||||
}
|
||||
my $r = new Authen::Radius(Host => $host, Secret => $secret, TimeOut => $timeout);
|
||||
$r->add_attributes(
|
||||
{ Name => 1, Value => $username, Type => 'string' },
|
||||
{ Name => 2, Value => $password, Type => 'string' },
|
||||
);
|
||||
$r->add_attributes( { Name => 4, Type => 'ipaddr', Value => $vars->{nas_ip_address} })
|
||||
if exists $vars->{nas_ip_address};
|
||||
my $c;
|
||||
my $start = gettimeofday();
|
||||
$r->send_packet(&ACCESS_REQUEST) and $c = $r->recv_packet;
|
||||
my $end = gettimeofday();
|
||||
my $result;
|
||||
if (defined $c) {
|
||||
$result = $c;
|
||||
$result = "OK" if $c == &ACCESS_ACCEPT;
|
||||
$result = "fail" if $c == &ACCESS_REJECT;
|
||||
$result = "fail-OK" if $c == &ACCESS_REJECT and $allowreject;
|
||||
} else {
|
||||
if (defined $r->get_error) {
|
||||
$result = "error: " . $r->strerror;
|
||||
} else {
|
||||
$result = "no reply";
|
||||
}
|
||||
}
|
||||
$elapsed = $end - $start;
|
||||
$self->do_debug("$host: radius query $_: $result, $elapsed");
|
||||
if (defined $c) {
|
||||
if ( $c == &ACCESS_ACCEPT or
|
||||
($c == &ACCESS_REJECT and $allowreject) ) {
|
||||
push @times, $elapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout};
|
||||
return $class->_makevars($h, {
|
||||
secretfile => {
|
||||
_doc => <<DOC,
|
||||
A file containing the RADIUS shared secrets for the targets. It should contain
|
||||
whitespace-separated pairs of the form `<host> <secret>'. Comments and blank lines
|
||||
are OK.
|
||||
DOC
|
||||
_example => '/another/place/secret',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
-r $val or return "ERROR: secret file $val is not readable.";
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'username' ],
|
||||
username => {
|
||||
_doc => 'The username to be tested.',
|
||||
_example => 'test-user',
|
||||
},
|
||||
password => {
|
||||
_doc => 'The password for the user, if not present in the password file.',
|
||||
_example => 'test-password',
|
||||
},
|
||||
secret => {
|
||||
_doc => 'The RADIUS shared secret for the target, if not present in the secrets file.',
|
||||
_example => 'test-secret',
|
||||
},
|
||||
nas_ip_address => {
|
||||
_doc => 'The NAS-IP-Address RADIUS attribute for the authentication requests. Not needed everywhere.',
|
||||
_example => '10.1.2.3',
|
||||
},
|
||||
mininterval => {
|
||||
_default => $DEFAULTINTERVAL,
|
||||
_doc => "The minimum interval between each authentication request sent, in (possibly fractional) seconds.",
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
timeout => {
|
||||
_default => 5,
|
||||
_doc => "Timeout in seconds for the RADIUS queries.",
|
||||
_re => '\d+',
|
||||
},
|
||||
port => {
|
||||
_doc => 'The RADIUS port to be used',
|
||||
_re => '\d+',
|
||||
_example => 1645,
|
||||
},
|
||||
allowreject => {
|
||||
_doc => 'Treat "reject" responses as OK',
|
||||
_re => '(true|false)',
|
||||
_example => 'true',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
130
debian/smokeping/usr/share/perl5/Smokeping/probes/RemoteFPing.pm
vendored
Normal file
130
debian/smokeping/usr/share/perl5/Smokeping/probes/RemoteFPing.pm
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
package Smokeping::probes::RemoteFPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::RemoteFPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::RemoteFPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::RemoteFPing - Remote FPing Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates the remote execution of FPing via ssh/rsh into smokeping.
|
||||
The variable B<binary> must point to your copy of the ssh/rsh program.
|
||||
The variable B<rbinary> must point to your copy of the fping program
|
||||
at the remote end.
|
||||
DOC
|
||||
notes => <<'DOC',
|
||||
It is important to make sure that you can access the remote machine
|
||||
without a password prompt, otherwise this probe will not work properly.
|
||||
To test just try something like this:
|
||||
|
||||
$ ssh foo@HostA.foobar.com fping HostB.barfoo.com
|
||||
|
||||
The next thing you see must be fping's output.
|
||||
|
||||
The B<rhost>, B<ruser>, B<rport> and B<rbinary> variables used to be configured
|
||||
in the Targets section of the first target or its parents They were moved
|
||||
to the Probes section, because the variables aren't really target-specific
|
||||
(all the targets are measured with the same parameters). The Targets
|
||||
sections aren't recognized anymore.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Luis F Balbinot <hades@inf.ufrgs.br>
|
||||
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
|
||||
derived from Smokeping::probes::FPing by
|
||||
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
DOC
|
||||
bugs => <<DOC
|
||||
This functionality should be in a generic 'remote execution' module
|
||||
so that it could be used for the other probes too.
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::FPing);
|
||||
|
||||
sub ProbeDesc($) {
|
||||
my $self = shift;
|
||||
my $superdesc = $self->SUPER::ProbeDesc;
|
||||
return "Remote $superdesc";
|
||||
}
|
||||
|
||||
sub binary {
|
||||
my $self = shift;
|
||||
my @ret = ( $self->SUPER::binary );
|
||||
for my $what (qw(ruser rport rhost rbinary)) {
|
||||
my $prefix = ($what eq 'ruser' ? "-l" : "");
|
||||
my $port = ($what eq 'rport' ? "-p" : "");
|
||||
if (defined $self->{properties}{$what}) {
|
||||
push @ret, $prefix . $port . $self->{properties}{$what};
|
||||
}
|
||||
}
|
||||
return @ret;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
$h->{rbinary} = $h->{binary};
|
||||
delete $h->{binary};
|
||||
delete $h->{rbinary}{_sub}; # we can't check the remote program's -x bit
|
||||
@{$h->{_mandatory}} = map { $_ ne 'binary' ? $_ : 'rbinary' } @{$h->{_mandatory}};
|
||||
return $class->_makevars($h, {
|
||||
_mandatory => [ 'binary', 'rhost' ],
|
||||
binary => {
|
||||
_doc => <<DOC,
|
||||
This variable specifies the path of the remote shell program (usually ssh,
|
||||
rsh or remsh). Any other script or binary that can be called as
|
||||
|
||||
binary [ -l ruser ] [ -p rport ] rhost rbinary
|
||||
|
||||
may be used.
|
||||
DOC
|
||||
_example => '/usr/bin/ssh',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
-x $val or return "ERROR: binary '$val' is not executable";
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
rhost => {
|
||||
_doc => <<DOC,
|
||||
The B<rhost> option specifies the remote device from where fping will
|
||||
be launched.
|
||||
DOC
|
||||
_example => 'my.pinger.host',
|
||||
},
|
||||
ruser => {
|
||||
_doc => <<DOC,
|
||||
The (optional) B<ruser> option allows you to specify the remote user,
|
||||
if different from the one running the smokeping daemon.
|
||||
DOC
|
||||
_example => 'foo',
|
||||
},
|
||||
rport => {
|
||||
_doc => <<DOC,
|
||||
The (optional) B<rport> option allows you to specify the port of the
|
||||
remote host.
|
||||
DOC
|
||||
_example => '22',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
173
debian/smokeping/usr/share/perl5/Smokeping/probes/SSH.pm
vendored
Normal file
173
debian/smokeping/usr/share/perl5/Smokeping/probes/SSH.pm
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package Smokeping::probes::SSH;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::SSH>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::SSH>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use IPC::Open3;
|
||||
use Symbol;
|
||||
use Carp;
|
||||
use Time::HiRes qw(gettimeofday tv_interval);
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::SSH - Secure Shell Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates ssh-keyscan as a probe into smokeping. The variable B<binary> must
|
||||
point to your copy of the ssh-keyscan program. If it is not installed on
|
||||
your system yet, you should install openssh >= 3.8p1
|
||||
|
||||
The Probe asks the given host n-times for it's public key, where n is
|
||||
the amount specified in the config File.
|
||||
|
||||
As part of the initialization, the probe asks 127.0.0.1 for it's public key
|
||||
and tries to parse the output. This is to ensure that the specified ssh-keyscan
|
||||
binary provides output in the expected formatm before relying on it.Make sure
|
||||
you have SSH running on the localhost as well, or specify an alternative
|
||||
init_host target to test against, that is expected to be available during any
|
||||
smokeping restart.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Christian Recktenwald <smokeping-contact@citecs.de>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
my $ssh_re=qr/^# \S+ SSH-/i;
|
||||
|
||||
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 $call = "$self->{properties}{binary} -t dsa,rsa,ecdsa $self->{properties}{init_host}";
|
||||
my $return = `$call 2>&1`;
|
||||
if ($return =~ m/$ssh_re/s){
|
||||
print "### parsing ssh-keyscan output...OK\n";
|
||||
} else {
|
||||
croak "ERROR: output of '$call' does not match $ssh_re\n";
|
||||
}
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
return "SSH requests";
|
||||
}
|
||||
|
||||
sub pingone ($){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my $inh = gensym;
|
||||
my $outh = gensym;
|
||||
my $errh = gensym;
|
||||
|
||||
my $host = $target->{addr};
|
||||
|
||||
my $query = "$self->{properties}{binary} -t $target->{vars}->{keytype} -p $target->{vars}->{port}";
|
||||
my @times;
|
||||
|
||||
# if ipv4/ipv6 proto was specified in the target, add it unless it is "0"
|
||||
if ($target->{vars}->{ssh_af} && $target->{vars}->{ssh_af} ne "0") {
|
||||
$query .= " -$target->{vars}->{ssh_af}";
|
||||
}
|
||||
$query .= " $host";
|
||||
# get the user and system times before and after the test
|
||||
$self->do_debug("query=$query\n");
|
||||
for (my $run = 0; $run < $self->pings; $run++) {
|
||||
my $t0 = [gettimeofday()];
|
||||
|
||||
my $pid = open3($inh,$outh,$errh, $query);
|
||||
# OpenSSH 9.8 compatibility - output is on stdout now
|
||||
while (<$outh>) {
|
||||
if (/$ssh_re/i) {
|
||||
push @times, tv_interval($t0);
|
||||
last;
|
||||
}
|
||||
}
|
||||
while (<$errh>) {
|
||||
if (/$ssh_re/i) {
|
||||
push @times, tv_interval($t0);
|
||||
last;
|
||||
}
|
||||
}
|
||||
waitpid $pid,0;
|
||||
my $rc = $?;
|
||||
carp "$query returned with exit code $rc. run with debug enabled to get more information" unless $rc == 0;
|
||||
close $errh;
|
||||
close $inh;
|
||||
close $outh;
|
||||
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ } sort {$a <=> $b} @times;
|
||||
|
||||
# $self->do_debug("time=@times\n");
|
||||
return @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'binary' ],
|
||||
binary => {
|
||||
_doc => "The location of your ssh-keyscan binary.",
|
||||
_example => '/usr/bin/ssh-keyscan',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
-x $val or return "ERROR: binary '$val' is not executable";
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
init_host => {
|
||||
_doc => "Host to use for initialization, defaults to IPv4 localhost of 127.0.0.1",
|
||||
_example => '127.0.0.1',
|
||||
_default => '127.0.0.1',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
keytype => {
|
||||
_doc => "Type of key, used in ssh-keyscan -t I<keytype>",
|
||||
_re => "[ecdr]sa*",
|
||||
_example => 'dsa',
|
||||
_default => 'rsa',
|
||||
},
|
||||
port => {
|
||||
_doc => "Port to use when testing the ssh connection -p I<port>",
|
||||
_re => '\d+',
|
||||
_example => '5000',
|
||||
_default => '22',
|
||||
},
|
||||
ssh_af => {
|
||||
_doc => "Address family (IPv4/IPV6) to use when testing the ssh connection, specify 4 or 6. Specify 0 to reset to default system preference, instead of inheriting the value from parent sections.",
|
||||
_re => '\d+',
|
||||
_example => '4',
|
||||
_default => '0',
|
||||
},
|
||||
})
|
||||
}
|
||||
1;
|
||||
178
debian/smokeping/usr/share/perl5/Smokeping/probes/SendEmail.pm
vendored
Normal file
178
debian/smokeping/usr/share/perl5/Smokeping/probes/SendEmail.pm
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
package Smokeping::probes::SendEmail;
|
||||
|
||||
# Copyright (c) 2012 Florian Coulmier <florian@coulmier.fr>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. 1
|
||||
#
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::skel>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::skel>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Carp;
|
||||
use Sys::Hostname;
|
||||
use Time::HiRes;
|
||||
use Net::SMTP;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::SendEmail - a Smokeping probe that measure time needed to send an mail
|
||||
DOC
|
||||
description => <<DOC,
|
||||
This probe actually send a mail to a MX server and measure time it took. You can choose the sender and recipient address as well as the size of the mail.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Florian Coulmier <florian@coulmier.fr>,
|
||||
DOC
|
||||
see_also => <<DOC
|
||||
L<smokeping_extend>
|
||||
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} ) {
|
||||
# if you have to test the program output
|
||||
# or something like that, do it here
|
||||
# and bail out if necessary
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
# Probe-specific variables declaration
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'from', 'to' ],
|
||||
from => {
|
||||
_doc => "Mail from address",
|
||||
_example => 'test@test.com',
|
||||
},
|
||||
to => {
|
||||
_doc => "Rcpt to address",
|
||||
_example => 'test@test.com',
|
||||
},
|
||||
subject => {
|
||||
_doc => "Subject of the mail",
|
||||
_example => "Test Smokeping",
|
||||
_default => "Test",
|
||||
},
|
||||
bodysize => {
|
||||
_doc => "Size of the mail to send in bytes. If set to 0, a default mail content will be set. Note that mail always contain From, To and Subject headers.",
|
||||
_example => "1024",
|
||||
_default => "0",
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# Target-specific variables declaration
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
port => { _doc => "Port of the SMTP server to reach",
|
||||
_example => 25,
|
||||
_default => 25,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
return "Measure time to send a complete email";
|
||||
}
|
||||
|
||||
# this is where the actual stuff happens
|
||||
sub pingone ($){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
my @times;
|
||||
|
||||
# Retrieve probe-specific and target-specific variables
|
||||
my $count = $self->pings($target);
|
||||
my $from = $self->{properties}{from};
|
||||
my $to = $self->{properties}{to};
|
||||
my $subject = $self->{properties}{subject} || "Smokeping Test";
|
||||
my $bodysize = $self->{properties}{bodysize} || 0;
|
||||
|
||||
my $host = $target->{addr};
|
||||
my $port = $target->{vars}{port} || 25;
|
||||
|
||||
# Get Hostname
|
||||
my $hostname = hostname();
|
||||
|
||||
|
||||
# Send a mail as many times as requested
|
||||
for (1..$count) {
|
||||
# Start counting time
|
||||
my $start = Time::HiRes::gettimeofday();
|
||||
|
||||
# Open the connection and then send the mail
|
||||
my $smtp = new Net::SMTP("$host:$port", Timeout => 5, Hello => $hostname);
|
||||
next if (!$smtp);
|
||||
|
||||
$smtp->mail($from) || next;
|
||||
$smtp->to($to, { Notify => ['NEVER'] }) || next;
|
||||
$smtp->data() || next;
|
||||
$smtp->datasend("From: <$from>\n");
|
||||
$smtp->datasend("To: <$to>\n");
|
||||
$smtp->datasend("Subject: $subject\n");
|
||||
$smtp->datasend("\n");
|
||||
|
||||
# If user specified a bodysize for the probe, send the request number of characters instead of the default content.
|
||||
if ($bodysize > 0) {
|
||||
my $nbLines = $bodysize / 80;
|
||||
for (1..$nbLines) {
|
||||
$smtp->datasend(sprintf("%s\n", "A" x 79));
|
||||
}
|
||||
$smtp->datasend(sprintf("%s\n", "A" x ($bodysize % 80)));
|
||||
} else {
|
||||
$smtp->datasend("This is a test email sent by Smokeping to check speed of mx server $host.\n");
|
||||
$smtp->datasend("If you receive this mail in your mailbox, you are likely to be spammed in just few minutes!\n");
|
||||
}
|
||||
|
||||
$smtp->dataend() || next;
|
||||
$smtp->quit();
|
||||
|
||||
# End measure of time and save it
|
||||
my $end = Time::HiRes::gettimeofday();
|
||||
push(@times, $end - $start);
|
||||
}
|
||||
|
||||
return sort {$a <=> $b } @times;
|
||||
}
|
||||
|
||||
# That's all, folks!
|
||||
|
||||
1;
|
||||
148
debian/smokeping/usr/share/perl5/Smokeping/probes/SipSak.pm
vendored
Normal file
148
debian/smokeping/usr/share/perl5/Smokeping/probes/SipSak.pm
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package Smokeping::probes::SipSak;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::SipSak>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::SipSak>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Carp;
|
||||
use IO::Select;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::SipSak - tests sip server
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
This probe sends OPTIONS messages to a sip server testing the latency.
|
||||
DOC
|
||||
description => <<DOC,
|
||||
The probe uses the L<sipsak|http://sipsak.org/> tool to measure sip server latency by sending an OPTIONS message.
|
||||
|
||||
The sipsak command supports a large number of additional parameters to fine-tune its operation. Use the
|
||||
params variable to configure them.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Tobias Oetiker <tobi@oetiker.ch> sponsored by ANI Networks
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub ProbeDesc ($) {
|
||||
my $self = shift;
|
||||
return sprintf("SIP OPTIONS messages");
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $host = $target->{addr};
|
||||
my $vars = $target->{vars};
|
||||
my @times;
|
||||
my $elapsed;
|
||||
my $pingcount = $self->pings($target);
|
||||
my $keep = $vars->{keep_second};
|
||||
$host = $vars->{user}.'@'.$host if $vars->{user};
|
||||
$host = $host . ':' . $vars->{port} if $vars->{port};
|
||||
my @extra_opts = ();
|
||||
@extra_opts = split /\s/, $vars->{params} if $vars->{params};
|
||||
open (my $sak,'-|',$self->{properties}{binary},'-vv','-A',$pingcount,'-s','sip:'.$host,@extra_opts)
|
||||
or die("ERROR: $self->{properties}{binary}: $!\n");
|
||||
my $sel = IO::Select->new();
|
||||
$sel->add($sak);
|
||||
if (not $sel->can_read($vars->{sipsak_timeout})){
|
||||
$self->do_debug("SipSak: timeout for $host");
|
||||
return '';
|
||||
}
|
||||
|
||||
my $reply = join ("",<$sak>);
|
||||
close $sak;
|
||||
|
||||
my @reply = split /\*\*\sreply/, $reply;
|
||||
# don't need the stuff before the first replyx
|
||||
shift @reply;
|
||||
|
||||
my $filter = '.*';
|
||||
$self->do_debug("SipSak: got ".(scalar @reply)." replies, expected $pingcount");
|
||||
if (scalar @reply > $pingcount){
|
||||
$filter = $keep eq 'yes' ? 'final received' : 'provisional received';
|
||||
}
|
||||
for my $item (@reply){
|
||||
$self->do_debug("SipSak: looking at '$item'");
|
||||
if (not $item =~ /$filter/){
|
||||
$self->do_debug("SipSak: skipping as there was not match for $filter");
|
||||
next;
|
||||
}
|
||||
if ($item =~ /(?:\sand|\sreceived\safter)\s(\d+(?:\.\d+)?)\sms\s/){
|
||||
$self->do_debug("SipSak: match");
|
||||
push @times,$1/1000;
|
||||
}
|
||||
else {
|
||||
$self->do_debug("SipSak: no match");
|
||||
}
|
||||
}
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
return $class->_makevars($h, {
|
||||
binary => {
|
||||
_doc => "The location of your echoping binary.",
|
||||
_default => '/usr/bin/sipsak',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
-x $val or return "ERROR: binary '$val' is not executable";
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
user => {
|
||||
_doc => "User to use for sip connection.",
|
||||
_example => 'nobody',
|
||||
},
|
||||
port => {
|
||||
_doc => "usa non-default port for the sip connection.",
|
||||
_example => 5061,
|
||||
},
|
||||
params => {
|
||||
_doc => "additional sipsak options. The options will get split on space.",
|
||||
_example => '--numeric --password=mysecret'
|
||||
},
|
||||
keep_second => {
|
||||
_doc => "If OPTIONS is actually implemented by the server, SipSak will receive two responses. If this option is set, the timing from the second, final response will be counter",
|
||||
_example => 'yes',
|
||||
_re => 'yes|no'
|
||||
},
|
||||
sipsak_timeout => {
|
||||
_doc => "Timeout for sipsak in seconds (fractional)",
|
||||
_default => 2,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
169
debian/smokeping/usr/share/perl5/Smokeping/probes/TCPPing.pm
vendored
Normal file
169
debian/smokeping/usr/share/perl5/Smokeping/probes/TCPPing.pm
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
package Smokeping::probes::TCPPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::FPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::FPing>
|
||||
|
||||
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<binary> must
|
||||
point to your copy of the TCPPing program. If it is not installed on
|
||||
your system yet, you can get it from https://github.com/deajan/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 <norman@rasmussen.co.za>
|
||||
Patched for Smokeping 2.x compatibility by Anton Chernev <maznio@doom.bg>
|
||||
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 overridden
|
||||
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)
|
||||
);
|
||||
|
||||
push @cmd, $target->{addr}, @port;
|
||||
|
||||
$self->do_debug("Executing @cmd");
|
||||
my $pid = open3($inh,$outh,$errh, @cmd);
|
||||
while (<$outh>){
|
||||
chomp;
|
||||
$self->do_debug("Received: $outh");
|
||||
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;
|
||||
my $rc = $?;
|
||||
carp join(" ",@cmd) . " returned with exit code $rc. run with debug enabled to get more information" unless $rc == 0;
|
||||
close $inh;
|
||||
close $outh;
|
||||
close $errh;
|
||||
|
||||
return @times;
|
||||
}
|
||||
|
||||
1;
|
||||
256
debian/smokeping/usr/share/perl5/Smokeping/probes/TacacsPlus.pm
vendored
Normal file
256
debian/smokeping/usr/share/perl5/Smokeping/probes/TacacsPlus.pm
vendored
Normal file
@@ -0,0 +1,256 @@
|
||||
package Smokeping::probes::TacacsPlus;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::TacacsPlus>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::TacacsPlus>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::passwordchecker);
|
||||
use Authen::TacacsPlus;
|
||||
use Time::HiRes qw(gettimeofday sleep);
|
||||
use Carp;
|
||||
|
||||
my $DEFAULTINTERVAL = 1;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::TacacsPlus - a TacacsPlus authentication probe for SmokePing
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Measures TacacsPlus authentication latency for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
This probe measures TacacsPlus authentication latency for SmokePing.
|
||||
|
||||
The username to be tested is specified in either the probe-specific or the
|
||||
target-specific variable `username', with the target-specific one overriding
|
||||
the probe-specific one.
|
||||
|
||||
The password can be specified either (in order of precedence, with
|
||||
the latter overriding the former) in the probe-specific variable
|
||||
`password', in an external file or in the target-specific variable
|
||||
`password'. The location of this file is given in the probe-specific
|
||||
variable `passwordfile'. See Smokeping::probes::passwordchecker(3pm) for the
|
||||
format of this file (summary: colon-separated triplets of the form
|
||||
`<host>:<username>:<password>')
|
||||
|
||||
The TacacsPlus protocol requires a shared secret between the server and the client.
|
||||
This secret can be specified either (in order of precedence, with the latter
|
||||
overriding the former) in the probe-specific variable `secret', in an external file
|
||||
or in the target-specific variable `secret'.
|
||||
This external file is located by the probe-specific variable `secretfile', and it should
|
||||
contain whitespace-separated pairs of the form `<host> <secret>'. Comments and blank lines
|
||||
are OK.
|
||||
|
||||
The default TacacsPlus authentication type is ASCII. PAP and CHAP are also available.
|
||||
See the Authen::TacacsPlus documentation for more information;
|
||||
|
||||
The probe tries to be nice to the server and does not send authentication
|
||||
requests more frequently than once every X seconds, where X is the value
|
||||
of the target-specific "min_interval" variable ($DEFAULTINTERVAL by default).
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Gary Mikula <g2ugzm@hotmail.com>
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
Not as yet....
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub ProbeDesc {
|
||||
return "TacacsPlus Authentication Attempts";
|
||||
}
|
||||
|
||||
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}) {
|
||||
if (defined $self->{properties}{secretfile}) {
|
||||
my @stat = stat($self->{properties}{secretfile});
|
||||
my $mode = $stat[2];
|
||||
carp("Warning: secret file $self->{properties}{secretfile} is world-readable\n")
|
||||
if defined $mode and $mode & 04;
|
||||
open(S, "<$self->{properties}{secretfile}")
|
||||
or croak("Error opening specified secret file $self->{properties}{secretfile}: $!");
|
||||
while (<S>) {
|
||||
chomp;
|
||||
next unless /\S/;
|
||||
next if /^\s*#/;
|
||||
my ($host, $secret) = split;
|
||||
carp("Line $. in $self->{properties}{secretfile} is invalid"), next
|
||||
unless defined $host and defined $secret;
|
||||
$self->secret($host, $secret);
|
||||
}
|
||||
close S;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub secret {
|
||||
my $self = shift;
|
||||
my $host = shift;
|
||||
my $newval = shift;
|
||||
|
||||
$self->{secret}{$host} = $newval if defined $newval;
|
||||
return $self->{secret}{$host};
|
||||
}
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $host = $target->{addr};
|
||||
my $vars = $target->{vars};
|
||||
my $mininterval = $vars->{mininterval};
|
||||
my $username = $vars->{username};
|
||||
my $authen_type = $vars->{authtype};
|
||||
my $secret = $self->secret($host);
|
||||
my @times;
|
||||
my $elapsed;
|
||||
my $result;
|
||||
my $start;
|
||||
my $authen;
|
||||
my $end;
|
||||
|
||||
if (defined $vars->{secret} and
|
||||
$vars->{secret} ne ($self->{properties}{secret}||"")) {
|
||||
$secret = $vars->{secret};
|
||||
}
|
||||
$secret ||= $self->{properties}{secret};
|
||||
|
||||
my $timeout = $vars->{timeout};
|
||||
|
||||
$self->do_log("Missing TacacsPlus secret for $host"), return
|
||||
unless defined $secret;
|
||||
|
||||
$self->do_log("Missing TacacsPlus username for $host"), return
|
||||
unless defined $username;
|
||||
|
||||
my $password = $self->password($host, $username);
|
||||
if (defined $vars->{password} and
|
||||
$vars->{password} ne ($self->{properties}{password}||"")) {
|
||||
$password = $vars->{password};
|
||||
}
|
||||
$password ||= $self->{properties}{password};
|
||||
|
||||
$self->do_log("Missing TacacsPlus password for $host/$username"), return
|
||||
unless defined $password;
|
||||
|
||||
my $port = $vars->{port};
|
||||
$host .= ":$port" if defined $port;
|
||||
|
||||
for (1..$self->pings($target)) {
|
||||
if (defined $elapsed) {
|
||||
my $timeleft = $mininterval - $elapsed;
|
||||
sleep $timeleft if $timeleft > 0;
|
||||
}
|
||||
$host =~ s/:[0-9]+//g;
|
||||
my $r = new Authen::TacacsPlus(Host => $host, Key => $secret, Port =>$port);
|
||||
if( $r ) {
|
||||
$start = gettimeofday();
|
||||
if( $authen_type eq 'PAP' ){
|
||||
$authen = &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_PAP;
|
||||
}elsif( $authen_type eq 'CHAP'){
|
||||
$authen = &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_CHAP;
|
||||
}else{
|
||||
$authen = &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_ASCII;
|
||||
}
|
||||
if( $r->authen($username, $password, $authen ) ) {
|
||||
$end = gettimeofday();
|
||||
$elapsed = $end - $start;
|
||||
$self->do_debug("$host: TacacsPlus Authen Granted: $elapsed time");
|
||||
push @times, $elapsed;
|
||||
$r->close();
|
||||
}else{
|
||||
$self->do_log("Unable to Authenticate to:$host with ID:$username Key:$secret");
|
||||
$result = "Unable to Authenticate Msg: " . Authen::TacacsPlus::errmsg();
|
||||
$self->do_debug("$result");
|
||||
}
|
||||
}else{
|
||||
$self->do_log("Unable to Create Constructor Authen::TacacsPlus for host:$host");
|
||||
$result = "Unable to Build Constructor Msg: " . Authen::TacacsPlus::errmsg();
|
||||
$self->do_debug("$result");
|
||||
}
|
||||
}
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{timeout};
|
||||
return $class->_makevars($h, {
|
||||
secretfile => {
|
||||
_doc => <<DOC,
|
||||
A file containing the TacacsPlus shared secrets for the targets. It should contain
|
||||
whitespace-separated pairs of the form `<host> <secret>'. Comments and blank lines
|
||||
are OK.
|
||||
DOC
|
||||
_example => '/another/place/secret',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
-r $val or return "ERROR: secret file $val is not readable.";
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'username' ],
|
||||
username => {
|
||||
_doc => 'The username to be tested.',
|
||||
_example => 'test-user',
|
||||
},
|
||||
password => {
|
||||
_doc => 'The password for the user, if not present in the password file.',
|
||||
_example => 'test-password',
|
||||
},
|
||||
secret => {
|
||||
_doc => 'The TacacsPlus shared secret for the target, if not present in the secrets file.',
|
||||
_example => 'test-secret',
|
||||
},
|
||||
mininterval => {
|
||||
_default => $DEFAULTINTERVAL,
|
||||
_doc => "The minimum interval between each authentication request sent, in (possibly fractional) seconds.",
|
||||
_re => '(\d*\.)?\d+',
|
||||
},
|
||||
timeout => {
|
||||
_default => 5,
|
||||
_doc => "Timeout in seconds for the TacacsPlus queries.",
|
||||
_re => '\d+',
|
||||
},
|
||||
port => {
|
||||
_default => 49,
|
||||
_doc => 'The TacacsPlus port to be used',
|
||||
_re => '\d+',
|
||||
_example => 49,
|
||||
},
|
||||
authtype => {
|
||||
_default => 'ASCII',
|
||||
_doc => 'The TacacsPlus Authentication type:ASCII(default), CHAP, PAP',
|
||||
_re => '(ASCII|CHAP|PAP)',
|
||||
_example => 'CHAP',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
294
debian/smokeping/usr/share/perl5/Smokeping/probes/TelnetIOSPing.pm
vendored
Normal file
294
debian/smokeping/usr/share/perl5/Smokeping/probes/TelnetIOSPing.pm
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
package Smokeping::probes::TelnetIOSPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::TelnetIOSPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::TelnetIOSPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Net::Telnet ();
|
||||
use Carp;
|
||||
|
||||
my $e = "=";
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::TelnetIOSPing - Cisco IOS Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates Cisco IOS as a probe into smokeping. Uses the telnet protocol
|
||||
to run a ping from an IOS device (source) to another device (host).
|
||||
This probe basically uses the "extended ping" of the Cisco IOS. You have
|
||||
the option to specify which interface the ping is sourced from as well.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
${e}head2 IOS configuration
|
||||
|
||||
The IOS device should have a username/password configured, as well as
|
||||
the ability to connect to the VTY(s).
|
||||
eg:
|
||||
|
||||
!
|
||||
username smokeping privilege 5 password 0 SmokepingPassword
|
||||
!
|
||||
line vty 0 4
|
||||
login local
|
||||
transport input telnet
|
||||
!
|
||||
|
||||
Some IOS devices have a maximum of 5 VTYs available, so be careful not
|
||||
to hit a limit with the 'forks' variable.
|
||||
|
||||
${e}head2 Requirements
|
||||
|
||||
This module requires the Net::Telnet module for perl. This is usually
|
||||
included on most newer OSs which include perl.
|
||||
|
||||
${e}head2 Debugging
|
||||
|
||||
There is some VERY rudimentary debugging code built into this module (it's
|
||||
based on the debugging code written into Net::Telnet). It will log
|
||||
information into three files "TIPreturn", "TIPoutlog", and "TIPdump".
|
||||
These files will be written out into your current working directory (CWD).
|
||||
You can change the names of these files to something with more meaning to
|
||||
you.
|
||||
|
||||
${e}head2 Password authentication
|
||||
|
||||
You should be advised that the authentication method of telnet uses
|
||||
clear text transmissions...meaning that without proper network security
|
||||
measures someone could sniff your username and password off the network.
|
||||
I may attempt to incorporate SSH in a future version of this module, but
|
||||
it is very doubtful. Right now SSH adds a LOT of processing overhead to
|
||||
a router, and isn't incredibly easy to implement in perl.
|
||||
|
||||
Having said this, don't be too scared of telnet. Remember, the
|
||||
original IOSPing module used RSH, which is even more scary to use from
|
||||
a security perspective.
|
||||
|
||||
${e}head2 Ping packet size
|
||||
|
||||
The FPing manpage has the following to say on the topic of ping packet
|
||||
size:
|
||||
|
||||
Number of bytes of ping data to send. The minimum size (normally 12)
|
||||
allows room for the data that fping needs to do its work (sequence
|
||||
number, timestamp). The reported received data size includes the IP
|
||||
header (normally 20 bytes) and ICMP header (8 bytes), so the minimum
|
||||
total size is 40 bytes. Default is 56, as in ping. Maximum is the
|
||||
theoretical maximum IP datagram size (64K), though most systems limit
|
||||
this to a smaller, system-dependent number.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
John A Jackson <geonjay@infoave.net>
|
||||
|
||||
based HEAVILY on Smokeping::probes::IOSPing by
|
||||
|
||||
Paul J Murphy <paul@murph.org>
|
||||
|
||||
based on Smokeping::probes::FPing by
|
||||
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
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} ) {
|
||||
$self->{pingfactor} = 1000; # Gives us a good-guess default
|
||||
print "### assuming you are using an IOS reporting in milliseconds\n";
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
return "InfoAve Cisco IOS - ICMP Echo Pings ($bytes Bytes)";
|
||||
}
|
||||
|
||||
sub pingone ($$){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $source = $target->{vars}{source};
|
||||
my $dest = $target->{vars}{host};
|
||||
my $psource = $target->{vars}{psource} || "";
|
||||
my $port = 23;
|
||||
my @output = ();
|
||||
my $login = $target->{vars}{iosuser};
|
||||
my $pssword = $target->{vars}{iospass};
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
my $pings = $self->pings($target);
|
||||
my $timeout = $self->{properties}{timeout};
|
||||
my $vrf ="";
|
||||
if ( defined ($target->{vars}{vrf}) ) {
|
||||
$vrf = " vrf $target->{vars}{vrf}";
|
||||
}
|
||||
# do NOT call superclass ... the ping method MUST be overridden
|
||||
my %upd;
|
||||
my @args = ();
|
||||
|
||||
|
||||
my $telnet = Net::Telnet->new( Timeout => $timeout );
|
||||
# These are for debugging
|
||||
# $telnet->errmode("TIPreturn");
|
||||
# $telnet->input_log("TIPinlog");
|
||||
# $telnet->dump_log("TIPdumplog");
|
||||
|
||||
#Open the Connection to the router
|
||||
# open(OUTF,">outfile.IA") || die "Can't open OUTF: $!";
|
||||
# print OUTF "target => $dest\nsource => $source\nuser => $login\n";
|
||||
my $ok = $telnet->open(Host => $source,
|
||||
Port => $port);
|
||||
# print OUTF "Connection is a $ok\n";
|
||||
|
||||
#Authenticate
|
||||
$telnet->waitfor('/(ogin|name|word):.*$/');
|
||||
$telnet->print("$login");
|
||||
$telnet->waitfor('/word:.*$/');
|
||||
$telnet->print("$pssword");
|
||||
#Do the work
|
||||
$telnet->waitfor('/[\@\w\-\.]+[>#][ ]*$/');
|
||||
$telnet->print("terminal length 0");
|
||||
$telnet->waitfor('/[\@\w\-\.]+[>#][ ]*$/');
|
||||
$telnet->print("ping$vrf");
|
||||
$telnet->waitfor('/Protocol \[ip\]: $/');
|
||||
$telnet->print("");
|
||||
$telnet->waitfor('/Target IP address: $/');
|
||||
$telnet->print("$dest");
|
||||
$telnet->waitfor('/Repeat count \[5\]: $/');
|
||||
$telnet->print($pings);
|
||||
$telnet->waitfor('/Datagram size \[100\]: $/');
|
||||
$telnet->print("$bytes");
|
||||
$telnet->waitfor('/Timeout in seconds \[2\]: $/');
|
||||
$telnet->print("");
|
||||
$telnet->waitfor('/Extended commands \[n\]: $/');
|
||||
$telnet->print("y");
|
||||
$telnet->waitfor('/Source address or interface: $/');
|
||||
$telnet->print("$psource");
|
||||
$telnet->waitfor('/Type of service \[0\]: $/');
|
||||
$telnet->print("");
|
||||
$telnet->waitfor('/Set DF bit in IP header\? \[no\]: $/');
|
||||
$telnet->print("");
|
||||
$telnet->waitfor('/Validate reply data\? \[no\]: $/');
|
||||
$telnet->print("");
|
||||
$telnet->waitfor('/Data pattern \[0xABCD\]: $/');
|
||||
$telnet->print("");
|
||||
$telnet->waitfor('/Loose, Strict, Record, Timestamp, Verbose\[none\]: $/');
|
||||
$telnet->print("v");
|
||||
$telnet->waitfor('/Loose, Strict, Record, Timestamp, Verbose\[V\]: $/');
|
||||
$telnet->print("");
|
||||
$telnet->waitfor('/Sweep range of sizes.+$/');
|
||||
|
||||
$telnet->prompt('/[\@\w\-\.]+[>#][ ]*$/');
|
||||
@output = $telnet->cmd("n");
|
||||
|
||||
#$telnet->waitfor('/[\@\w\-\.]+[>#][ ]*$/');
|
||||
$telnet->print("quit");
|
||||
$telnet->close;
|
||||
# print OUTF "closed Telnet connection\n";
|
||||
|
||||
my @times = ();
|
||||
while (@output) {
|
||||
my $outputline = shift @output;
|
||||
chomp($outputline);
|
||||
# print OUTF "$outputline\n";
|
||||
$outputline =~ /^Reply to request \d+ \((\d+) ms\)/ && push(@times,$1);
|
||||
#print OUTF "$outputline => $1\n";
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} @times;
|
||||
# close(OUTF);
|
||||
return @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
packetsize => {
|
||||
_doc => <<DOC,
|
||||
The (optional) packetsize option lets you configure the packetsize for
|
||||
the pings sent.
|
||||
DOC
|
||||
_default => 56,
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: packetsize must be between 12 and 64000"
|
||||
unless $val >= 12 and $val <= 64000;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'iosuser', 'iospass', 'source' ],
|
||||
source => {
|
||||
_doc => <<DOC,
|
||||
The source option specifies the IOS device to which we telnet. This
|
||||
is an IP address of an IOS Device that you/your server:
|
||||
1) Have the ability to telnet to
|
||||
2) Have a valid username and password for
|
||||
DOC
|
||||
_example => "192.168.2.1",
|
||||
},
|
||||
psource => {
|
||||
_doc => <<DOC,
|
||||
The (optional) psource option specifies an alternate IP address or
|
||||
Interface from which you wish to source your pings from. Routers
|
||||
can have many many IP addresses, and interfaces. When you ping from a
|
||||
router you have the ability to choose which interface and/or which IP
|
||||
address the ping is sourced from. Specifying an IP/interface does not
|
||||
necessarily specify the interface from which the ping will leave, but
|
||||
will specify which address the packet(s) appear to come from. If this
|
||||
option is left out the IOS Device will source the packet automatically
|
||||
based on routing and/or metrics. If this doesn't make sense to you
|
||||
then just leave it out.
|
||||
DOC
|
||||
_example => "192.168.2.129",
|
||||
},
|
||||
iosuser => {
|
||||
_doc => <<DOC,
|
||||
The iosuser option allows you to specify a username that has ping
|
||||
capability on the IOS Device.
|
||||
DOC
|
||||
_example => 'user',
|
||||
},
|
||||
iospass => {
|
||||
_doc => <<DOC,
|
||||
The iospass option allows you to specify the password for the username
|
||||
specified with the option iosuser.
|
||||
DOC
|
||||
_example => 'password',
|
||||
},
|
||||
|
||||
vrf => {
|
||||
_doc => <<DOC,
|
||||
The vrf option allows you to specify the vrf for ping
|
||||
DOC
|
||||
_example => 'VRF1',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
250
debian/smokeping/usr/share/perl5/Smokeping/probes/TelnetJunOSPing.pm
vendored
Normal file
250
debian/smokeping/usr/share/perl5/Smokeping/probes/TelnetJunOSPing.pm
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
package Smokeping::probes::TelnetJunOSPing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::TelnetJunOSPing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::TelnetJunOSPing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Net::Telnet ();
|
||||
use Carp;
|
||||
|
||||
my $e = "=";
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::TelnetJunOSPing - Juniper JunOS Probe for SmokePing
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Integrates Juniper JunOS as a probe into smokeping. Uses the telnet protocol
|
||||
to run a ping from an JunOS device (source) to another device (host).
|
||||
This probe basically uses the "extended ping" of the Juniper JunOS. You have
|
||||
the option to specify which interface the ping is sourced from as well.
|
||||
DOC
|
||||
notes => <<DOC,
|
||||
${e}head2 JunOS configuration
|
||||
|
||||
The JunOS device should have a username/password configured, as well as
|
||||
the ability to connect to the VTY(s).
|
||||
|
||||
Some JunOS devices have a maximum of 5 VTYs available, so be careful not
|
||||
to hit a limit with the 'forks' variable.
|
||||
|
||||
${e}head2 Requirements
|
||||
|
||||
This module requires the Net::Telnet module for perl. This is usually
|
||||
included on most newer OSs which include perl.
|
||||
|
||||
${e}head2 Debugging
|
||||
|
||||
There is some VERY rudimentary debugging code built into this module (it's
|
||||
based on the debugging code written into Net::Telnet). It will log
|
||||
information into three files "TIPreturn", "TIPoutlog", and "TIPdump".
|
||||
These files will be written out into your current working directory (CWD).
|
||||
You can change the names of these files to something with more meaning to
|
||||
you.
|
||||
|
||||
${e}head2 Password authentication
|
||||
|
||||
You should be advised that the authentication method of telnet uses
|
||||
clear text transmissions...meaning that without proper network security
|
||||
measures someone could sniff your username and password off the network.
|
||||
I may attempt to incorporate SSH in a future version of this module, but
|
||||
it is very doubtful. Right now SSH adds a LOT of processing overhead to
|
||||
a router, and isn't incredibly easy to implement in perl.
|
||||
|
||||
Having said this, don't be too scared of telnet. Remember, the
|
||||
original JunOSPing module used RSH, which is even more scary to use from
|
||||
a security perspective.
|
||||
|
||||
${e}head2 Ping packet size
|
||||
|
||||
The FPing manpage has the following to say on the topic of ping packet
|
||||
size:
|
||||
|
||||
Number of bytes of ping data to send. The minimum size (normally 12)
|
||||
allows room for the data that fping needs to do its work (sequence
|
||||
number, timestamp). The reported received data size includes the IP
|
||||
header (normally 20 bytes) and ICMP header (8 bytes), so the minimum
|
||||
total size is 40 bytes. Default is 56, as in ping. Maximum is the
|
||||
theoretical maximum IP datagram size (64K), though most systems limit
|
||||
this to a smaller, system-dependent number.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
S H A N <shanali@yahoo.com>
|
||||
|
||||
based HEAVILY on Smokeping::probes::TelnetIOSPing by
|
||||
|
||||
John A Jackson <geonjay@infoave.net>
|
||||
|
||||
based on Smokeping::probes::JunOSPing by
|
||||
|
||||
Paul J Murphy <paul@murph.org>
|
||||
|
||||
based on Smokeping::probes::FPing by
|
||||
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
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} ) {
|
||||
$self->{pingfactor} = 1000; # Gives us a good-guess default
|
||||
print "### assuming you are using an JunOS reporting in milliseconds\n";
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
return "InfoAve Juniper JunOS - ICMP Echo Pings ($bytes Bytes)";
|
||||
}
|
||||
|
||||
sub pingone ($$){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $source = $target->{vars}{source};
|
||||
my $dest = $target->{vars}{host};
|
||||
my $psource = $target->{vars}{psource};
|
||||
my $port = 23;
|
||||
my @output = ();
|
||||
my $login = $target->{vars}{junosuser};
|
||||
my $pssword = $target->{vars}{junospass};
|
||||
my $bytes = $self->{properties}{packetsize};
|
||||
my $pings = $self->pings($target);
|
||||
|
||||
# do NOT call superclass ... the ping method MUST be overridden
|
||||
my %upd;
|
||||
my @args = ();
|
||||
|
||||
|
||||
my $telnet = Net::Telnet->new(Timeout => 60);
|
||||
# $telnet->errmode("TIPreturn");
|
||||
# $telnet->input_log("TIPinlog");
|
||||
# $telnet->dump_log("TIPdumplog");
|
||||
|
||||
# Open the Connection to the router
|
||||
# open(OUTF,">outfile.IA") || die "Can't open OUTF: $!";
|
||||
# print OUTF "target => $dest\nsource => $source\nuser => $login\n";
|
||||
my $ok = $telnet->open(Host => $source,
|
||||
Port => $port);
|
||||
# print OUTF "Connection is a $ok\n";
|
||||
|
||||
#Authenticate
|
||||
$telnet->waitfor('/(ogin):.*$/');
|
||||
$telnet->print("$login");
|
||||
$telnet->waitfor('/word:.*$/');
|
||||
$telnet->print("$pssword");
|
||||
$telnet->prompt('/[\@\w\-\.]+[>#][ ]*$/');
|
||||
#Do the work
|
||||
$telnet->waitfor('/[\@\w\-\.]+[>#][ ]*$/');
|
||||
$telnet->print("set cli screen-length 0");
|
||||
$telnet->waitfor('/[\@\w\-\.]+[>#][ ]*$/');
|
||||
if ( $psource ) {
|
||||
@output = $telnet->cmd("ping $dest count $pings size $bytes source $psource");
|
||||
} else {
|
||||
@output = $telnet->cmd("ping $dest count $pings size $bytes");
|
||||
}
|
||||
$telnet->print("quit");
|
||||
$telnet->close;
|
||||
# print OUTF "closed Telnet connection\n";
|
||||
|
||||
my @times = ();
|
||||
while (@output) {
|
||||
my $outputline = shift @output;
|
||||
chomp($outputline);
|
||||
# print OUTF "$outputline\n";
|
||||
$outputline =~ /^\d+ bytes from $dest: icmp_seq=\d+ ttl=\d+ time=(\d+\.\d+) ms$/ && push(@times,$1);
|
||||
#print OUTF "$outputline => $1\n";
|
||||
}
|
||||
@times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} @times;
|
||||
# close(OUTF);
|
||||
return @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
packetsize => {
|
||||
_doc => <<DOC,
|
||||
The (optional) packetsize option lets you configure the packetsize for
|
||||
the pings sent.
|
||||
DOC
|
||||
_default => 100,
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: packetsize must be between 12 and 64000"
|
||||
unless $val >= 12 and $val <= 64000;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'junosuser', 'junospass', 'source' ],
|
||||
source => {
|
||||
_doc => <<DOC,
|
||||
The source option specifies the JunOS device to which we telnet. This
|
||||
is an IP address of an JunOS Device that you/your server:
|
||||
1) Have the ability to telnet to
|
||||
2) Have a valid username and password for
|
||||
DOC
|
||||
_example => "192.168.2.1",
|
||||
},
|
||||
psource => {
|
||||
_doc => <<DOC,
|
||||
The (optional) psource option specifies an alternate IP address or
|
||||
Interface from which you wish to source your pings from. Routers
|
||||
can have many many IP addresses, and interfaces. When you ping from a
|
||||
router you have the ability to choose which interface and/or which IP
|
||||
address the ping is sourced from. Specifying an IP/interface does not
|
||||
necessarily specify the interface from which the ping will leave, but
|
||||
will specify which address the packet(s) appear to come from. If this
|
||||
option is left out the JunOS Device will source the packet automatically
|
||||
based on routing and/or metrics. If this doesn't make sense to you
|
||||
then just leave it out.
|
||||
DOC
|
||||
_example => "192.168.2.129",
|
||||
},
|
||||
junosuser => {
|
||||
_doc => <<DOC,
|
||||
The junosuser option allows you to specify a username that has ping
|
||||
capability on the JunOS Device.
|
||||
DOC
|
||||
_example => 'user',
|
||||
},
|
||||
junospass => {
|
||||
_doc => <<DOC,
|
||||
The junospass option allows you to specify the password for the username
|
||||
specified with the option junosuser.
|
||||
DOC
|
||||
_example => 'password',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
335
debian/smokeping/usr/share/perl5/Smokeping/probes/TraceroutePing.pm
vendored
Normal file
335
debian/smokeping/usr/share/perl5/Smokeping/probes/TraceroutePing.pm
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
package Smokeping::probes::TraceroutePing;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::TraceroutePing>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::TraceroutePing>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
# or, alternatively
|
||||
# use base qw(Smokeping::probes::base);
|
||||
use Carp;
|
||||
use IPC::Open3;
|
||||
use Symbol;
|
||||
use Socket qw(:addrinfo);
|
||||
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<'DOC',
|
||||
Smokeping::probes::TraceroutePing - use traceroute to obtain RTT for a router
|
||||
DOC
|
||||
description => <<'DOC',
|
||||
Integrates standard traceroute as a probe into smokeping. The use
|
||||
case for this probe is gateways that do not respond to TCP/UDP/ICMP
|
||||
packets addressed to them, but do return ICMP TTL_EXCEEDED packets for
|
||||
traceroute packets to a host they route to. It is best used in
|
||||
situations where routing for the path is static or nearly so;
|
||||
attempting to use this on networks with changing routing will yield
|
||||
poor results. The best place to use this probe is on first- and
|
||||
last-mile links, which are more likely to have static routing and
|
||||
also more likely to have firewalls that ignore ICMP ECHO_REQUEST.
|
||||
|
||||
The mandatory probe variable B<binary> must have an executable path for
|
||||
traceroute.
|
||||
|
||||
The optional probe variable B<binaryv6> sets an executable path for
|
||||
your IPv6 traceroute. If this is set to the same value as B<binary>,
|
||||
TraceroutePing will use the -6 flag when running traceroute for IPv6
|
||||
addresses. If this variable is not set, TraceroutePing will try to
|
||||
find an functioning IPv6 traceroute. It will first try appending "6"
|
||||
to the path in B<binary>, then try including the "-6" flag in a test
|
||||
command. Note that Linux appears to have a wide variety of IPv6
|
||||
traceroute implementations. My Ubuntu 14.04 machine has
|
||||
/usr/sbin/traceroute6 from iputils, but /usr/bin/traceroute (from
|
||||
Dmitry Butskoy) accepts the -6 flag and is actually a better
|
||||
implementation. You may need to let TraceroutePing autodetect this, or
|
||||
experiment to find the best traceroute.
|
||||
|
||||
The mandatory target variable B<desthost> must name a destination host
|
||||
for the probe. The destination host itself is not of interest and no
|
||||
data is gathered on it, its only purpose is to route traffic past your
|
||||
actual target. Selection of a destination just past your target, with
|
||||
static or strongly preferred routing through your target, will get
|
||||
better data.
|
||||
|
||||
The mandatory target variable B<host> must name the target host for
|
||||
the probe. This is the router that you want to collect RTT data for.
|
||||
This variable must either be the valid reverse-lookup name of the
|
||||
router, or its IP address. Using the IP address is preferable since
|
||||
it allows us to tell traceroute to avoid DNS lookups.
|
||||
|
||||
The target variables B<minttl> and B<maxttl> can be used to describe
|
||||
the range of expected hop counts to B<host>. On longer paths or paths
|
||||
through unresponsive gateways or ending in unresponsive hosts, this
|
||||
reduces the amount of time this probe takes to execute. These default
|
||||
to 1 and 30.
|
||||
|
||||
The target variables B<wait> sets the traceroute probe timeout in
|
||||
seconds. This defaults to 1, instead of the traditionally higher
|
||||
value used by LBL traceroute. Traceroute programs often enforce a
|
||||
lower bound on this value.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
John Hood <cgull@glup.org>,
|
||||
DOC
|
||||
see_also => <<'DOC'
|
||||
L<smokeping_extend>
|
||||
DOC
|
||||
};
|
||||
}
|
||||
|
||||
sub new($$$)
|
||||
{
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
|
||||
$self->do_debug("command: $self->{properties}{binary}, " . $self->{properties}{binary});
|
||||
# Do we need to find an IPv6 traceroute? We can't make it a mandatory probe variable,
|
||||
# there are likely people out there still using IPv4-only OS installs.
|
||||
if ($self->{properties}{binaryv6}) {
|
||||
$self->do_debug("configured v6 command: $self->{properties}{binaryv6}, " .
|
||||
$self->{properties}{binaryv6});
|
||||
} else {
|
||||
my $tail = " -n -q1 -f1 -m1 -w1 ::1 >/dev/null 2>&1";
|
||||
# First try "traceroute -6 ..."
|
||||
system($self->{properties}{binary} . " -6 ${tail}");
|
||||
if ($? == 0) {
|
||||
$self->{properties}{binaryv6} = $self->{properties}{binary};
|
||||
} else {
|
||||
# Then try "traceroute6 ..."
|
||||
system($self->{properties}{binary} . "6 ${tail}");
|
||||
if ($? == 0) {
|
||||
$self->{properties}{binaryv6} = $self->{properties}{binary} . "6";
|
||||
} else {
|
||||
$self->{properties}{binaryv6} = "/bin/false";
|
||||
}
|
||||
}
|
||||
$self->do_debug("discovered v6 command: $self->{properties}{binaryv6}, " .
|
||||
$self->{properties}{binaryv6});
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
return "Traceroute (UDP + TTL) Pings";
|
||||
}
|
||||
|
||||
# Probe-specific variables.
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
_mandatory => [ 'binary' ],
|
||||
binary => {
|
||||
_doc => "The location of your traceroute binary.",
|
||||
_example => '/usr/bin/traceroute',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: traceroute '$val' does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
binaryv6 => {
|
||||
_doc => "The location of your IPv6 traceroute binary.",
|
||||
_example => '/usr/bin/traceroute6',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: IPv6 traceroute '$val' does not point to an executable"
|
||||
unless -f $val and -x _;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
# Target-specific variables.
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
_mandatory => [ 'desthost', 'host' ],
|
||||
desthost => {
|
||||
_doc => "Final destination host for traceroute packets. Does not have to be reachable unless it is also your host.",
|
||||
_example => 'www.example.com',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
host => {
|
||||
_doc => "Host of interest to monitor. Must be either the host's reverse-lookup name, or an IP address.",
|
||||
_example => 'www-net-router.example.com',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
minttl => {
|
||||
_doc => "Minimum TTL. Set to the minimum expected number of hops to host.",
|
||||
_example => '11',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return undef;
|
||||
}
|
||||
},
|
||||
maxttl => {
|
||||
_doc => "Maximum TTL. Set to the maximum expected number of hops to host.",
|
||||
_example => '15',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
wait => {
|
||||
_doc => "Waittime. The timeout value for traceroute's probes, in seconds.",
|
||||
_example => '3',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub pingone ($) {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
# Defaults
|
||||
my $minttl = 1;
|
||||
my $maxttl = 30;
|
||||
my $wait = 1;
|
||||
|
||||
# Fish out args
|
||||
my $binary = $self->{properties}{binary};
|
||||
# my $weight = $target->{vars}{weight}
|
||||
my $count = $self->pings($target); # the number of pings for this target
|
||||
my $desthost = $target->{vars}{desthost};
|
||||
my $host = $target->{vars}{host};
|
||||
$minttl = $target->{vars}{minttl} if $target->{vars}{minttl};
|
||||
$maxttl = $target->{vars}{maxttl} if $target->{vars}{maxttl};
|
||||
$wait = $target->{vars}{wait} if $target->{vars}{wait};
|
||||
|
||||
# Check host and desthost for numericness and IPv6
|
||||
$self->do_debug("Host $host");
|
||||
|
||||
my %hints = ( flags => Socket::AI_NUMERICHOST );
|
||||
my ($err, @res) = getaddrinfo($host, 0, \%hints);
|
||||
my $use_numeric = ! $err;
|
||||
|
||||
($err, @res) = getaddrinfo($host);
|
||||
return if $err;
|
||||
my $hostinfo = $res[0];
|
||||
my $v6 = $hostinfo->{family} eq Socket::AF_INET6;
|
||||
|
||||
$self->do_debug("Desthost $desthost");
|
||||
|
||||
($err, @res) = getaddrinfo($desthost);
|
||||
return if $err;
|
||||
my $destinfo = $res[0];
|
||||
my $destv6 = $destinfo->{family} eq Socket::AF_INET6;
|
||||
|
||||
# Validate them
|
||||
if ($v6 != $destv6) {
|
||||
$self->do_debug("address families don't match, $host $desthost");
|
||||
return;
|
||||
}
|
||||
|
||||
$self->do_debug("validated $host");
|
||||
|
||||
# ping one target
|
||||
my @cmd;
|
||||
if (!$v6) {
|
||||
push @cmd, $self->{properties}{binary};
|
||||
} else {
|
||||
push @cmd, $self->{properties}{binaryv6};
|
||||
my $same_binaries = $self->{properties}{binaryv6} eq $self->{properties}{binary};
|
||||
if ($same_binaries) {
|
||||
push @cmd, "-6";
|
||||
}
|
||||
}
|
||||
push @cmd, (
|
||||
'-w', $wait,
|
||||
'-f', $minttl,
|
||||
'-m', $maxttl,
|
||||
'-q', '1',
|
||||
);
|
||||
|
||||
push(@cmd, "-n") if $use_numeric;
|
||||
push(@cmd, $desthost);
|
||||
|
||||
# Run traceroute for only one iteration in an external loop, to
|
||||
# avoid various parsing problems that can come up with >1 iteration.
|
||||
my @times;
|
||||
for (1..$count) {
|
||||
$self->do_debug("Executing @cmd");
|
||||
my $killed;
|
||||
my $f_stdin = gensym;
|
||||
my $f_stdout = gensym;
|
||||
my $f_stderr = gensym;
|
||||
my $pid = open3($f_stdin, $f_stdout, $f_stderr, @cmd);
|
||||
while (<$f_stdout>){
|
||||
my $line = $_;
|
||||
chomp($line);
|
||||
$self->do_debug("stdout: $line");
|
||||
next unless $line =~ /^\s*\d+\s+\S+\s+[\d\.,]+\s+\S+\s*$/; # only match RTT output
|
||||
|
||||
my @fields = split(/\s+/,$line);
|
||||
shift @fields if $fields[0] eq ''; # discard empty first field
|
||||
$self->do_debug("fields: " . join(', ',@fields));
|
||||
next unless $host eq $fields[1];
|
||||
|
||||
shift @fields if !$use_numeric; # discard hostnames to get fields in the same position
|
||||
|
||||
my $time = $fields[2];
|
||||
# Adjust time units to smokeping's preferred units. One
|
||||
# enhanced LBL implementation has a -u option for microseconds.
|
||||
for ($fields[3]) {
|
||||
/^s(|ec(|ond))$/i && do { next; };
|
||||
/^(m|milli)s(|ec(|ond))$/i && do { $time /= 1000; next; };
|
||||
/^(u|micro)s(|ec(|ond))$/i && do { $time /= 1000000; next; };
|
||||
$time /= 1000; # default
|
||||
};
|
||||
$self->do_debug("time: $time");
|
||||
push @times, $time;
|
||||
|
||||
# now we have a time to our target $host-- there's no
|
||||
# point in waiting for traceroute to finish the trace to
|
||||
# $desthost
|
||||
$killed = kill(15, $pid);
|
||||
last;
|
||||
}
|
||||
while (<$f_stderr>){
|
||||
my $line = $_;
|
||||
chomp($line);
|
||||
$self->do_debug("stderr: $line");
|
||||
}
|
||||
waitpid $pid,0;
|
||||
my $rc = $?;
|
||||
carp join(" ",@cmd) . " returned with exit code $rc. run with debug enabled to get more information" unless ($rc == 0 || $killed);
|
||||
close $f_stdin;
|
||||
close $f_stdout;
|
||||
close $f_stderr;
|
||||
}
|
||||
@times = sort {$a <=> $b} @times;
|
||||
$self->do_debug("Times: " . join(' ', @times));
|
||||
return @times;
|
||||
}
|
||||
# That's all, folks!
|
||||
|
||||
1;
|
||||
171
debian/smokeping/usr/share/perl5/Smokeping/probes/WebProxyFilter.pm
vendored
Normal file
171
debian/smokeping/usr/share/perl5/Smokeping/probes/WebProxyFilter.pm
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
package Smokeping::probes::WebProxyFilter;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::WebProxyFilter>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::WebProxyFilter>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use LWP::UserAgent;
|
||||
use Time::HiRes qw(gettimeofday sleep);
|
||||
use Carp;
|
||||
|
||||
my $DEFAULTINTERVAL = 1;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::WebProxyFilter - tests webproxy filter performance and function.
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
This probe tests if your filtering webproxy is working properly. Drawing from
|
||||
a list of forbidden websites, it tries to establish a connection to
|
||||
each one of them and registers a 'loss' when it succeeds.
|
||||
|
||||
If you want to test availability of a website, use the EchoPingHttp probe.
|
||||
DOC
|
||||
description => <<DOC,
|
||||
The probe uses the LWP::UserAgent module to retrieve a series of webpages. It
|
||||
expects to get the firewalls 'site-prohibited' page. Any other response (or
|
||||
a real loss) gets logged as a loss and can be used to trigger an alarm.
|
||||
|
||||
The probe tries to be nice to the firewall and waits at least X seconds
|
||||
between starting filetransfers, where X is the value of the probe
|
||||
specific `min_interval' variable ($DEFAULTINTERVAL by default).
|
||||
|
||||
Many variables can be specified either in the probe or in the target definition,
|
||||
the target-specific variable will override the prove-specific variable.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Tobias Oetiker <tobi@oetiker.ch> sponsored by Virtela
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
This probe is somewhat unortodox, since it regards the successful retrieval
|
||||
of a banned webpage as a loss.
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub ProbeDesc ($) {
|
||||
my $self = shift;
|
||||
return sprintf("HTTP GETs");
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my $self = $class->SUPER::new(@_);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub pingone {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
my $host = $target->{addr};
|
||||
my $vars = $target->{vars};
|
||||
my $mininterval = $self->{properties}{min_interval};
|
||||
my @times;
|
||||
my $elapsed;
|
||||
my $ua = LWP::UserAgent->new;
|
||||
$ua->agent($vars->{useragent});
|
||||
$ua->timeout($vars->{timeout});
|
||||
$ua->max_size($vars->{max_size});
|
||||
my @targets = ($host, split /\s*,\s*/, $vars->{more_hosts});
|
||||
my $targcount = scalar @targets;
|
||||
my $pingcount = $self->pings($target);
|
||||
my $deny_re = $vars->{deny_re};
|
||||
if ($targcount > $self->pings($target)) {
|
||||
$self->do_log("ERROR There are more host addresses ($targcount) than ping slots ($pingcount), either increase the pings or reduce the targets.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (1..$pingcount) {
|
||||
if (defined $elapsed) {
|
||||
my $timeleft = $mininterval - $elapsed;
|
||||
sleep $timeleft if $timeleft > 0;
|
||||
}
|
||||
my $target = shift @targets;
|
||||
push @targets,$target;
|
||||
my $start = gettimeofday();
|
||||
my $response = $ua->get("http://$target");
|
||||
my $end = gettimeofday();
|
||||
if ($response->is_success){
|
||||
if ($response->content =~ /$deny_re/ism){
|
||||
push @times,($end-$start);
|
||||
} else {
|
||||
my $content = substr($response->content,0,80)." ...";
|
||||
$content =~ s/[\n\r]/ /g;
|
||||
$self->do_log("Warning: Problem with target $host: got unexpected content from $target: $content");
|
||||
}
|
||||
} else {
|
||||
$self->do_log("Warning: Problem with target $host: got this error from $target: ".$response->status_line);
|
||||
}
|
||||
}
|
||||
return sort { $a <=> $b } @times;
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
return $class->_makevars($h, {
|
||||
_mandatory => ['deny_re'],
|
||||
min_interval => {
|
||||
_default => $DEFAULTINTERVAL,
|
||||
_doc => "The minimum interval between each starting GETs in seconds.",
|
||||
_re => '(\d*\.)?\d+',
|
||||
_example => '0.1'
|
||||
},
|
||||
useragent => {
|
||||
_default => "SmokePing/2.x (WebProxyFilter Probe)",
|
||||
_doc => "The web browser we claim to be, just in case the FW is interested"
|
||||
},
|
||||
maxsize => {
|
||||
_default => 2000,
|
||||
_doc => "How much of the webpage should be retrieved."
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
timeout => {
|
||||
_default => 2,
|
||||
_doc => "Timeout in seconds for the test complete.",
|
||||
_re => '\d+',
|
||||
_example => 2,
|
||||
},
|
||||
deny_re => {
|
||||
_doc => "Regular expression, matching the 'deny' response from the firewall",
|
||||
_example => 'Access Prohibited',
|
||||
},
|
||||
more_hosts => {
|
||||
_doc => <<DOC,
|
||||
A comma separated list of banned websites to test in addition to the one
|
||||
specified in the I<host> variable. The websites will be tested one after the
|
||||
other in one round, this means that while normal probes do run the same test
|
||||
several times in a row, this one will alter the webpage with each round.
|
||||
The reason for this is, that even though we try to retrieve remote webpages,
|
||||
the answer will come from the firewall every time, so we kill two birds in
|
||||
one go. First we test the firewalls latency and second we make sure its
|
||||
filter works properly.
|
||||
DOC
|
||||
_re => '[^\s.]+(?:\.[^\s.]+)*(\s*,[^\s.]+(?:\.[^\s.]+)*)*',
|
||||
_example => 'www.playboy.com, www.our-competition.com',
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
455
debian/smokeping/usr/share/perl5/Smokeping/probes/base.pm
vendored
Normal file
455
debian/smokeping/usr/share/perl5/Smokeping/probes/base.pm
vendored
Normal file
@@ -0,0 +1,455 @@
|
||||
package Smokeping::probes::base;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::base>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::base>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use vars qw($VERSION);
|
||||
use Carp;
|
||||
use lib qw(..);
|
||||
use Smokeping;
|
||||
|
||||
$VERSION = 1.0;
|
||||
|
||||
use strict;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::base - Base Class for implementing SmokePing Probes
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
For the time being, please use the L<Smokeping::probes::FPing|Smokeping::probes::FPing> for
|
||||
inspiration when implementing your own probes.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Tobias Oetiker <tobi@oetiker.ch>
|
||||
DOC
|
||||
};
|
||||
}
|
||||
|
||||
sub pod {
|
||||
my $class = shift;
|
||||
my $pod = "";
|
||||
my $podhash = $class->pod_hash;
|
||||
$podhash->{synopsis} = $class->pod_synopsis;
|
||||
$podhash->{variables} = $class->pod_variables;
|
||||
for my $what (qw(name overview synopsis description variables authors notes bugs see_also)) {
|
||||
my $contents = $podhash->{$what};
|
||||
next if not defined $contents or $contents eq "";
|
||||
my $headline = uc $what;
|
||||
$headline =~ s/_/ /; # see_also => SEE ALSO
|
||||
$pod .= "=head1 $headline\n\n";
|
||||
$pod .= $contents;
|
||||
chomp $pod;
|
||||
$pod .= "\n\n";
|
||||
}
|
||||
$pod .= "=cut";
|
||||
return $pod;
|
||||
}
|
||||
|
||||
sub new($$)
|
||||
{
|
||||
my $this = shift;
|
||||
my $class = ref($this) || $this;
|
||||
my $self = { properties => shift, cfg => shift,
|
||||
name => shift,
|
||||
targets => {}, rtts => {}, addrlookup => {}, rounds_count => 0};
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub add($$)
|
||||
{
|
||||
my $self = shift;
|
||||
my $tree = shift;
|
||||
|
||||
$self->{target_count}++; # increment this anyway
|
||||
return if defined $tree->{nomasterpoll} and $tree->{nomasterpoll} eq "yes";
|
||||
$self->{targets}{$tree} = shift;
|
||||
}
|
||||
|
||||
sub ping($)
|
||||
{
|
||||
croak "this must be overridden by the subclass";
|
||||
}
|
||||
|
||||
sub round ($) {
|
||||
return sprintf "%.0f", $_[0];
|
||||
}
|
||||
|
||||
sub ProbeDesc ($) {
|
||||
return "Probe which does not override the ProbeDesc method";
|
||||
}
|
||||
|
||||
sub ProbeUnit ($) {
|
||||
return "Seconds";
|
||||
}
|
||||
|
||||
# this is a read-only variable that should get incremented by
|
||||
# the ping() method
|
||||
sub rounds_count ($) {
|
||||
my $self = shift;
|
||||
return $self->{rounds_count};
|
||||
}
|
||||
|
||||
sub increment_rounds_count ($) {
|
||||
my $self = shift;
|
||||
$self->{rounds_count}++;
|
||||
}
|
||||
|
||||
sub target2dynfile ($$) {
|
||||
# the targets are stored in the $self->{targets}
|
||||
# hash as filenames pointing to the RRD files
|
||||
#
|
||||
# now that we use a (optionally) different dir for the
|
||||
# . adr files, we need to derive the .adr filename
|
||||
# from the RRD filename with a simple substitution
|
||||
|
||||
my $self = shift;
|
||||
my $target = shift; # filename with <datadir> embedded
|
||||
my $dyndir = $self->{cfg}{General}{dyndir};
|
||||
return $target unless defined $dyndir; # nothing to do
|
||||
my $datadir = $self->{cfg}{General}{datadir};
|
||||
$target =~ s/^\Q$datadir\E/$dyndir/;
|
||||
return $target;
|
||||
}
|
||||
|
||||
sub rrdupdate_string($$)
|
||||
{ my $self = shift;
|
||||
my $tree = shift;
|
||||
# print "$tree -> ", join ",", @{$self->{rtts}{$tree}};print "\n";
|
||||
# skip invalid addresses
|
||||
my $pings = $self->_pings($tree);
|
||||
return "U:${pings}:".(join ":", map {"U"} 1..($pings+1))
|
||||
unless defined $self->{rtts}{$tree} and @{$self->{rtts}{$tree}} > 0;
|
||||
my $entries = scalar @{$self->{rtts}{$tree}};
|
||||
my @times = @{$self->{rtts}{$tree}};
|
||||
my $loss = $pings - $entries;
|
||||
my $median = $times[int($entries/2)] || 'U';
|
||||
# shift the data into the middle of the times array
|
||||
my $lowerloss = int($loss/2);
|
||||
my $upperloss = $loss - $lowerloss;
|
||||
@times = ((map {'U'} 1..$lowerloss),@times, (map {'U'} 1..$upperloss));
|
||||
my $age;
|
||||
my $dynbase = $self->target2dynfile($self->{targets}{$tree});
|
||||
if ( -f $dynbase.".adr" ) {
|
||||
$age = time - (stat($dynbase.".adr"))[9];
|
||||
} else {
|
||||
$age = 'U';
|
||||
}
|
||||
if ( $entries == 0 ){
|
||||
$self->do_log("Warning: got zero answers from $tree->{addr}($tree->{probe}) $self->{targets}{$tree}");
|
||||
$age = 'U';
|
||||
$loss = 'U';
|
||||
if ( -f $dynbase.".adr"
|
||||
and not -f $dynbase.".snmp" ){
|
||||
unlink $dynbase.".adr";
|
||||
}
|
||||
} ;
|
||||
return "${age}:${loss}:${median}:".(join ":", @times);
|
||||
}
|
||||
|
||||
sub addresses($)
|
||||
{
|
||||
my $self = shift;
|
||||
my $addresses = [];
|
||||
$self->{addrlookup} = {};
|
||||
foreach my $tree (keys %{$self->{targets}}){
|
||||
my $target = $self->{targets}{$tree};
|
||||
if ($target =~ m|/|) {
|
||||
my $dynbase = $self->target2dynfile($target);
|
||||
if ( open D, "<$dynbase.adr" ) {
|
||||
my $ip;
|
||||
chomp($ip = <D>);
|
||||
close D;
|
||||
|
||||
if ( open D, "<$dynbase.snmp" ) {
|
||||
my $snmp = <D>;
|
||||
chomp($snmp);
|
||||
if ($snmp ne Smokeping::snmpget_ident $ip) {
|
||||
# something fishy snmp properties do not match, skip this address
|
||||
next;
|
||||
}
|
||||
close D;
|
||||
}
|
||||
$target = $ip;
|
||||
} else {
|
||||
# can't read address file skip
|
||||
next;
|
||||
}
|
||||
}
|
||||
$self->{addrlookup}{$target} = ()
|
||||
unless defined $self->{addrlookup}{$target};
|
||||
push @{$self->{addrlookup}{$target}}, $tree;
|
||||
push @{$addresses}, $target;
|
||||
};
|
||||
return $addresses;
|
||||
}
|
||||
|
||||
sub debug {
|
||||
my $self = shift;
|
||||
my $newval = shift;
|
||||
$self->{debug} = $newval if defined $newval;
|
||||
return $self->{debug};
|
||||
}
|
||||
|
||||
sub do_debug {
|
||||
my $self = shift;
|
||||
return unless $self->debug;
|
||||
$self->do_log(@_);
|
||||
}
|
||||
|
||||
sub do_fatal {
|
||||
my $self = shift;
|
||||
$self->do_log("Fatal:", @_);
|
||||
croak(@_);
|
||||
}
|
||||
|
||||
sub do_log {
|
||||
my $self = shift;
|
||||
Smokeping::do_log("$self->{name}:", @_);
|
||||
}
|
||||
|
||||
sub report {
|
||||
my $self = shift;
|
||||
my $count = $self->target_count;
|
||||
my $offset = $self->offset_in_seconds;
|
||||
my $step = $self->step;
|
||||
$self->do_log("probing $count targets with step $step s and offset $offset s.");
|
||||
}
|
||||
|
||||
sub step {
|
||||
my $self = shift;
|
||||
my $rv = $self->{cfg}{Database}{step};
|
||||
unless (defined $self->{cfg}{General}{concurrentprobes}
|
||||
and $self->{cfg}{General}{concurrentprobes} eq 'no') {
|
||||
$rv = $self->{properties}{step} if defined $self->{properties}{step};
|
||||
}
|
||||
return $rv;
|
||||
}
|
||||
|
||||
sub offset {
|
||||
my $self = shift;
|
||||
my $rv = $self->{cfg}{General}{offset};
|
||||
unless (defined $self->{cfg}{General}{concurrentprobes}
|
||||
and $self->{cfg}{General}{concurrentprobes} eq 'no') {
|
||||
$rv = $self->{properties}{offset} if defined $self->{properties}{offset};
|
||||
}
|
||||
return $rv;
|
||||
}
|
||||
|
||||
sub offset_in_seconds {
|
||||
# returns the offset in seconds rather than as a percentage
|
||||
# this is filled in from the initialization in Smokeping::main
|
||||
my $self = shift;
|
||||
my $newval = shift;
|
||||
$self->{offset_in_seconds} = $newval if defined $newval;
|
||||
return $self->{offset_in_seconds};
|
||||
}
|
||||
|
||||
# the "public" method that takes a "target" argument is used by the probes
|
||||
# the "private" method that takes a "tree" argument is used by Smokeping.pm
|
||||
# there's no difference between them here, but we have to provide both
|
||||
|
||||
sub pings {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
# $target is not used; basefork.pm overrides this method to provide a target-specific parameter
|
||||
my $rv = $self->{cfg}{Database}{pings};
|
||||
$rv = $self->{properties}{pings} if defined $self->{properties}{pings};
|
||||
return $rv;
|
||||
}
|
||||
|
||||
|
||||
sub _pings {
|
||||
my $self = shift;
|
||||
my $tree = shift;
|
||||
# $tree is not used; basefork.pm overrides this method to provide a target-specific parameter
|
||||
my $rv = $self->{cfg}{Database}{pings};
|
||||
$rv = $self->{properties}{pings} if defined $self->{properties}{pings};
|
||||
return $rv;
|
||||
}
|
||||
|
||||
sub target_count {
|
||||
my $self = shift;
|
||||
$self->{target_count} = 0 if !defined $self->{target_count};
|
||||
return $self->{target_count};
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
return {
|
||||
step => {
|
||||
_re => '\d+',
|
||||
_example => 300,
|
||||
_doc => <<DOC,
|
||||
Duration of the base interval that this probe should use, if different
|
||||
from the one specified in the 'Database' section. Note that the step in
|
||||
the RRD files is fixed when they are originally generated, and if you
|
||||
change the step parameter afterwards, you'll have to delete the old RRD
|
||||
files or somehow convert them. (This variable is only applicable if
|
||||
the variable 'concurrentprobes' is set in the 'General' section.)
|
||||
DOC
|
||||
},
|
||||
offset => {
|
||||
_re => '(\d+%|random)',
|
||||
_re_error =>
|
||||
"Use offset either in % of operation interval or 'random'",
|
||||
_example => '50%',
|
||||
_doc => <<DOC,
|
||||
If you run many probes concurrently you may want to prevent them from
|
||||
hitting your network all at the same time. Using the probe-specific
|
||||
offset parameter you can change the point in time when each probe will
|
||||
be run. Offset is specified in % of total interval, or alternatively as
|
||||
'random', and the offset from the 'General' section is used if nothing
|
||||
is specified here. Note that this does NOT influence the rrds itself,
|
||||
it is just a matter of when data acquisition is initiated.
|
||||
(This variable is only applicable if the variable 'concurrentprobes' is set
|
||||
in the 'General' section.)
|
||||
DOC
|
||||
},
|
||||
pings => {
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: The pings value must be at least 3."
|
||||
if $val < 3;
|
||||
return undef;
|
||||
},
|
||||
_example => 20,
|
||||
_doc => <<DOC,
|
||||
How many pings should be sent to each target, if different from the global
|
||||
value specified in the Database section. Note that the number of pings in
|
||||
the RRD files is fixed when they are originally generated, and if you
|
||||
change this parameter afterwards, you'll have to delete the old RRD
|
||||
files or somehow convert them.
|
||||
DOC
|
||||
},
|
||||
_mandatory => [],
|
||||
};
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
return {_mandatory => [],
|
||||
'/^influx_.+/' => {
|
||||
_re => '.*',
|
||||
_example => 'influx_location = In the basement',
|
||||
_doc => <<DOC,
|
||||
This is a tag that will be sent to influxdb and has no impact on the probe measurement. The tag name will be sent without the "influx_" prefix, which will be replaced with "tag_" instead. Tags can be used for filtering.
|
||||
DOC
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
# a helper method that combines two var hash references
|
||||
# and joins their '_mandatory' lists.
|
||||
sub _makevars {
|
||||
my ($class, $from, $to) = @_;
|
||||
for (keys %$from) {
|
||||
if ($_ eq '_mandatory') {
|
||||
push @{$to->{_mandatory}}, @{$from->{$_}};
|
||||
next;
|
||||
}
|
||||
$to->{$_} = $from->{$_};
|
||||
}
|
||||
return $to;
|
||||
}
|
||||
|
||||
sub pod_synopsis {
|
||||
my $class = shift;
|
||||
my $classname = ref $class||$class;
|
||||
$classname =~ s/^Smokeping::probes:://;
|
||||
|
||||
my $probevars = $class->probevars;
|
||||
my $targetvars = $class->targetvars;
|
||||
my $pod = <<DOC;
|
||||
*** Probes ***
|
||||
|
||||
+$classname
|
||||
|
||||
DOC
|
||||
$pod .= $class->_pod_synopsis($probevars);
|
||||
my $targetpod = $class->_pod_synopsis($targetvars);
|
||||
$pod .= "\n # The following variables can be overridden in each target section\n$targetpod"
|
||||
if defined $targetpod and $targetpod ne "";
|
||||
$pod .= <<DOC;
|
||||
|
||||
# [...]
|
||||
|
||||
*** Targets ***
|
||||
|
||||
probe = $classname # if this should be the default probe
|
||||
|
||||
# [...]
|
||||
|
||||
+ mytarget
|
||||
# probe = $classname # if the default probe is something else
|
||||
host = my.host
|
||||
DOC
|
||||
$pod .= $targetpod
|
||||
if defined $targetpod and $targetpod ne "";
|
||||
|
||||
return $pod;
|
||||
}
|
||||
|
||||
# synopsis for one hash ref
|
||||
sub _pod_synopsis {
|
||||
my $class = shift;
|
||||
my $vars = shift;
|
||||
my %mandatory;
|
||||
$mandatory{$_} = 1 for (@{$vars->{_mandatory}});
|
||||
my $pod = "";
|
||||
for (sort keys %$vars) {
|
||||
next if /^_mandatory$/;
|
||||
my $val = $vars->{$_}{_example};
|
||||
$val = $vars->{$_}{_default}
|
||||
if exists $vars->{$_}{_default}
|
||||
and not defined $val;
|
||||
$pod .= " $_ = $val";
|
||||
$pod .= " # mandatory" if $mandatory{$_};
|
||||
$pod .= "\n";
|
||||
}
|
||||
return $pod;
|
||||
}
|
||||
|
||||
sub pod_variables {
|
||||
my $class = shift;
|
||||
my $probevars = $class->probevars;
|
||||
my $pod = "Supported probe-specific variables:\n\n";
|
||||
$pod .= $class->_pod_variables($probevars);
|
||||
return $pod;
|
||||
}
|
||||
|
||||
sub _pod_variables {
|
||||
my $class = shift;
|
||||
my $vars = shift;
|
||||
my $pod = "=over\n\n";
|
||||
my %mandatory;
|
||||
$mandatory{$_} = 1 for (@{$vars->{_mandatory}});
|
||||
for (sort keys %$vars) {
|
||||
next if /^_mandatory$/;
|
||||
$pod .= "=item $_\n\n";
|
||||
$pod .= $vars->{$_}{_doc};
|
||||
chomp $pod;
|
||||
$pod .= "\n\n";
|
||||
$pod .= "Example value: " . $vars->{$_}{_example} . "\n\n"
|
||||
if exists $vars->{$_}{_example};
|
||||
$pod .= "Default value: " . $vars->{$_}{_default} . "\n\n"
|
||||
if exists $vars->{$_}{_default};
|
||||
$pod .= "This setting is mandatory.\n\n"
|
||||
if $mandatory{$_};
|
||||
}
|
||||
$pod .= "=back\n\n";
|
||||
return $pod;
|
||||
}
|
||||
1;
|
||||
278
debian/smokeping/usr/share/perl5/Smokeping/probes/basefork.pm
vendored
Normal file
278
debian/smokeping/usr/share/perl5/Smokeping/probes/basefork.pm
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
package Smokeping::probes::basefork;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::basefork>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::basefork>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basevars);
|
||||
use Symbol;
|
||||
use Carp;
|
||||
use IO::Select;
|
||||
use POSIX; # for ceil() and floor()
|
||||
use Config; # for signal names
|
||||
|
||||
my $DEFAULTFORKS = 5;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::basefork - Yet Another Base Class for implementing SmokePing Probes
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Like Smokeping::probes::basevars, but supports the probe-specific property `forks'
|
||||
to determine how many processes should be run concurrently. The
|
||||
targets are pinged one at a time, and the number of pings sent can vary
|
||||
between targets.
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Not all pinger programs support testing multiple hosts in a single go like
|
||||
fping(1). If the measurement takes long enough, there may be not enough time
|
||||
perform all the tests in the time available. For example, if the test takes
|
||||
30 seconds, measuring ten hosts already fills up the SmokePing default
|
||||
five minute step.
|
||||
|
||||
Thus, it may be necessary to do some of the tests concurrently. This module
|
||||
defines the B<ping> method that forks the requested number of concurrent
|
||||
processes and calls the B<pingone> method that derived classes must provide.
|
||||
|
||||
The B<pingone> method is called with one argument: a hash containing
|
||||
the target that is to be measured. The contents of the hash are
|
||||
described in I<Smokeping::probes::basevars>(3pm).
|
||||
|
||||
The number of concurrent processes is determined by the probe-specific
|
||||
variable `forks' and is $DEFAULTFORKS by default. If there are more
|
||||
targets than this value, another round of forks is done after the first
|
||||
processes are finished. This continues until all the targets have been
|
||||
tested.
|
||||
|
||||
The timeout in which each child has to finish is set to 5 seconds
|
||||
multiplied by the maximum number of 'pings' of the targets. You can set
|
||||
the base timeout differently if you want to, using the timeout property
|
||||
of the probe in the master config file (this again will be multiplied
|
||||
by the maximum number of pings). The probe itself can also provide
|
||||
another default value if desired by modifying the _default value of
|
||||
the timeout variable.
|
||||
|
||||
If the child isn't finished when the timeout occurs, it
|
||||
will be killed along with any processes it has started.
|
||||
|
||||
The number of pings sent can be specified in the target-specific variable
|
||||
'pings'.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::basevars>, L<Smokeping::probes::EchoPing>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
my %signo;
|
||||
my @signame;
|
||||
|
||||
{
|
||||
# from perlipc man page
|
||||
my $i = 0;
|
||||
defined $Config{sig_name} || die "No sigs?";
|
||||
foreach my $name (split(' ', $Config{sig_name})) {
|
||||
$signo{$name} = $i;
|
||||
$signame[$i] = $name;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
die("Missing TERM signal?") unless exists $signo{TERM};
|
||||
die("Missing KILL signal?") unless exists $signo{KILL};
|
||||
|
||||
sub pingone {
|
||||
croak "pingone: this must be overridden by the subclass";
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
my $h = $class->SUPER::probevars;
|
||||
delete $h->{pings};
|
||||
return $class->_makevars($h, {
|
||||
forks => {
|
||||
_re => '\d+',
|
||||
_example => 5,
|
||||
_doc => "Run this many concurrent processes at maximum",
|
||||
_default => $DEFAULTFORKS,
|
||||
},
|
||||
timeout => {
|
||||
_re => '\d+',
|
||||
_example => 15,
|
||||
_default => 5,
|
||||
_doc => "How long a single 'ping' takes at maximum",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
pings => {
|
||||
_re => '\d+',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
return "ERROR: The pings value must be at least 3."
|
||||
if $val < 3;
|
||||
return undef;
|
||||
},
|
||||
_example => 5,
|
||||
_doc => <<DOC,
|
||||
How many pings should be sent to each target, if different from the global
|
||||
value specified in the Database section. Note that the number of pings in
|
||||
the RRD files is fixed when they are originally generated, and if you
|
||||
change this parameter afterwards, you'll have to delete the old RRD
|
||||
files or somehow convert them.
|
||||
DOC
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sub ping {
|
||||
my $self = shift;
|
||||
|
||||
# increment the internal 'rounds' counter
|
||||
$self->increment_rounds_count;
|
||||
|
||||
my @targets = @{$self->targets};
|
||||
return unless @targets;
|
||||
|
||||
my $forks = $self->{properties}{forks};
|
||||
|
||||
my $maxpings = 0;
|
||||
my $maxtimeout = $self->{properties}{timeout};
|
||||
for (@targets) {
|
||||
my $p = $self->pings($_);
|
||||
$maxpings = $p if $p > $maxpings;
|
||||
# some probes have a target-specific timeout variable
|
||||
# dig out the maximum timeout
|
||||
my $t = $_->{vars}{timeout};
|
||||
$maxtimeout = $t if $t > $maxtimeout;
|
||||
}
|
||||
|
||||
# we add 1 so that the probes doing their own timeout handling
|
||||
# have time to do it even in the worst case
|
||||
my $timeout = $maxpings * $maxtimeout + 1;
|
||||
|
||||
$self->{rtts}={};
|
||||
$self->do_debug("forks $forks, timeout for each target $timeout");
|
||||
|
||||
while (@targets) {
|
||||
my %targetlookup;
|
||||
my %pidlookup;
|
||||
my $s = IO::Select->new();
|
||||
my $starttime = time();
|
||||
for (1..$forks) {
|
||||
last unless @targets;
|
||||
my $t = pop @targets;
|
||||
my $pid;
|
||||
my $handle = gensym;
|
||||
my $sleep_count = 0;
|
||||
do {
|
||||
$pid = open($handle, "-|");
|
||||
|
||||
unless (defined $pid) {
|
||||
$self->do_log("cannot fork: $!");
|
||||
$self->fatal("bailing out")
|
||||
if $sleep_count++ > 6;
|
||||
sleep 10;
|
||||
}
|
||||
} until defined $pid;
|
||||
if ($pid) { #parent
|
||||
$s->add($handle);
|
||||
$targetlookup{$handle} = $t;
|
||||
$pidlookup{$handle} = $pid;
|
||||
} else { #child
|
||||
# we detach from the parent's process group
|
||||
setpgrp(0, $$);
|
||||
|
||||
# re-initialize the RNG for each subprocess
|
||||
srand(time()+$$);
|
||||
|
||||
my @times = $self->pingone($t);
|
||||
print join(" ", @times), "\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
my $timeleft = $timeout - (time() - $starttime);
|
||||
|
||||
while ($s->handles and $timeleft > 0) {
|
||||
for my $ready ($s->can_read($timeleft)) {
|
||||
$s->remove($ready);
|
||||
my $response = <$ready>;
|
||||
close $ready;
|
||||
|
||||
chomp $response;
|
||||
my @times = split(/ /, $response);
|
||||
my $target = $targetlookup{$ready};
|
||||
my $tree = $target->{tree};
|
||||
$self->{rtts}{$tree} = \@times;
|
||||
|
||||
$self->do_debug("$target->{addr}: got $response");
|
||||
}
|
||||
$timeleft = $timeout - (time() - $starttime);
|
||||
}
|
||||
my @left = $s->handles;
|
||||
for my $handle (@left) {
|
||||
$self->do_log("$targetlookup{$handle}{addr}: timeout ($timeout s) reached, killing the probe.");
|
||||
|
||||
# we kill the child's process group (negative signal)
|
||||
# this should finish off the actual pinger process as well
|
||||
|
||||
my $pid = $pidlookup{$handle};
|
||||
kill -$signo{TERM}, $pid;
|
||||
sleep 1;
|
||||
kill -$signo{KILL}, $pid;
|
||||
|
||||
close $handle;
|
||||
$s->remove($handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# the "private" method that takes a "tree" argument is used by Smokeping.pm
|
||||
sub _pings {
|
||||
my $self = shift;
|
||||
my $tree = shift;
|
||||
my $vars = $self->vars($tree);
|
||||
return $vars->{pings} if defined $vars->{pings};
|
||||
return $self->SUPER::pings();
|
||||
}
|
||||
|
||||
# the "public" method that takes a "target" argument is used by the probes
|
||||
sub pings {
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
return $self->SUPER::pings() unless ref $target;
|
||||
return $self->_pings($target->{tree});
|
||||
}
|
||||
|
||||
sub ProbeDesc {
|
||||
return "Probe that can fork and doesn't override the ProbeDesc method";
|
||||
}
|
||||
|
||||
sub pod_variables {
|
||||
my $class = shift;
|
||||
my $pod = $class->SUPER::pod_variables;
|
||||
my $targetvars = $class->targetvars;
|
||||
$pod .= "Supported target-specific variables:\n\n";
|
||||
$pod .= $class->_pod_variables($targetvars);
|
||||
return $pod;
|
||||
}
|
||||
|
||||
1;
|
||||
105
debian/smokeping/usr/share/perl5/Smokeping/probes/basevars.pm
vendored
Normal file
105
debian/smokeping/usr/share/perl5/Smokeping/probes/basevars.pm
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package Smokeping::probes::basevars;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::basevars>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::basevars>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use Smokeping::probes::base;
|
||||
use base qw(Smokeping::probes::base);
|
||||
|
||||
my $e = "=";
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::basevars - Another Base Class for implementing SmokePing Probes
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Like L<Smokeping::probes::base|Smokeping::probes::base>, but supports host-specific variables for the probe.
|
||||
DOC
|
||||
description => <<DOC,
|
||||
Provides the method `targets' that returns a list of hashes.
|
||||
The hashes contain the entries:
|
||||
|
||||
${e}over
|
||||
|
||||
${e}item addr
|
||||
|
||||
The address of the target.
|
||||
|
||||
${e}item vars
|
||||
|
||||
A hash containing variables defined in the corresponding
|
||||
config section.
|
||||
|
||||
${e}item tree
|
||||
|
||||
The unique index that `probe::base' uses for targets.
|
||||
|
||||
There's also the method 'vars' that returns the above mentioned
|
||||
hash corresponding to the 'tree' index parameter.
|
||||
|
||||
${e}back
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
bugs => <<DOC,
|
||||
Uses `Smokeping::probes::base' internals too much to be a derived class, but
|
||||
I didn't want to touch the base class directly.
|
||||
DOC
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::base>, L<Smokeping::probes::EchoPing>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub add($$)
|
||||
{
|
||||
my $self = shift;
|
||||
my $tree = shift;
|
||||
|
||||
$self->{target_count}++;
|
||||
$self->{targets}{$tree} = shift;
|
||||
$self->{vars}{$tree} = { %{$self->{properties}}, %$tree };
|
||||
}
|
||||
|
||||
sub targets {
|
||||
my $self = shift;
|
||||
my $addr = $self->addresses;
|
||||
my @targets;
|
||||
|
||||
# copy the addrlookup lists to safely pop
|
||||
my %copy;
|
||||
|
||||
for (@$addr) {
|
||||
@{$copy{$_}} = @{$self->{addrlookup}{$_}} unless exists $copy{$_};
|
||||
my $tree = pop @{$copy{$_}};
|
||||
my $vars = $self->{vars}{$tree};
|
||||
next if defined $vars->{nomasterpoll} and $vars->{nomasterpoll} eq "yes";
|
||||
push @targets, { addr => $_, vars => $vars, tree => $tree };
|
||||
}
|
||||
return \@targets;
|
||||
}
|
||||
|
||||
sub vars {
|
||||
my $self = shift;
|
||||
my $tree = shift;
|
||||
return $self->{vars}{$tree};
|
||||
}
|
||||
|
||||
sub ProbeDesc {
|
||||
return "Probe that supports variables and doesn't override the ProbeDesc method";
|
||||
}
|
||||
|
||||
return 1;
|
||||
148
debian/smokeping/usr/share/perl5/Smokeping/probes/passwordchecker.pm
vendored
Normal file
148
debian/smokeping/usr/share/perl5/Smokeping/probes/passwordchecker.pm
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package Smokeping::probes::passwordchecker;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::passwordchecker>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::passwordchecker>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use Smokeping::probes::basefork;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
use Carp;
|
||||
|
||||
my $e = "=";
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::passwordchecker - A Base Class for implementing SmokePing Probes
|
||||
DOC
|
||||
overview => <<DOC,
|
||||
Like Smokeping::probes::basefork, but supports a probe-specific configuration file
|
||||
for storing passwords and a method for accessing them.
|
||||
DOC
|
||||
|
||||
description => <<DOC,
|
||||
${e}head2 synopsis with more detail
|
||||
|
||||
SmokePing main configuration file:
|
||||
|
||||
*** Probes ***
|
||||
+ MyPasswordChecker
|
||||
# location of the file containing usernames and passwords
|
||||
passwordfile = /usr/share/smokeping/etc/passwords
|
||||
|
||||
The specified password file:
|
||||
|
||||
# host:username:password
|
||||
host1:joe:hardlyasecret
|
||||
# comments and whitespace lines are allowed
|
||||
|
||||
host2:sue:notasecreteither
|
||||
|
||||
${e}head2 Actual description
|
||||
|
||||
In implementing authentication probes, it might not be desirable to store
|
||||
the necessary cleartext passwords in the SmokePing main configuration
|
||||
file, since the latter must be readable both by the SmokePing daemon
|
||||
performing the probes and the CGI that displays the results. If the
|
||||
passwords are stored in a different file, this file can be made readable
|
||||
by only the user the daemon runs as. This way we can be sure that nobody
|
||||
can trick the CGI into displaying the passwords on the Web.
|
||||
|
||||
This module reads the passwords in at startup from the file specified
|
||||
in the probe-specific variable `passwordfile'. The passwords can later
|
||||
be accessed and modified by the B<password> method, that needs the corresponding
|
||||
host and username as arguments.
|
||||
|
||||
${e}head2 Password file format
|
||||
|
||||
The password file format is simply one line for each triplet of host,
|
||||
username and password, separated from each other by colons (:).
|
||||
|
||||
Comment lines, starting with the `#' sign, are ignored, as well as
|
||||
empty lines.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>
|
||||
DOC
|
||||
|
||||
bugs => <<DOC,
|
||||
The need for storing cleartext passwords can be considered a bug in itself.
|
||||
DOC
|
||||
|
||||
see_also => <<DOC,
|
||||
L<Smokeping::probes::basefork>, L<Smokeping::probes::Radius>, L<Smokeping::probes::LDAP>
|
||||
DOC
|
||||
}
|
||||
}
|
||||
|
||||
sub ProbeDesc {
|
||||
return "probe that can fork, knows about passwords and doesn't override the ProbeDesc method";
|
||||
}
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
passwordfile => {
|
||||
_doc => "Location of the file containing usernames and passwords.",
|
||||
_example => '/some/place/secret',
|
||||
_sub => sub {
|
||||
my $val = shift;
|
||||
-r $val or $ENV{SERVER_SOFTWARE} or return "ERROR: password file $val is not readable.";
|
||||
return undef;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
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}) {
|
||||
|
||||
if (defined $self->{properties}{passwordfile}) {
|
||||
my @stat = stat($self->{properties}{passwordfile});
|
||||
my $mode = $stat[2];
|
||||
carp("Warning: password file $self->{properties}{passwordfile} is world-readable\n")
|
||||
if defined $mode and $mode & 04;
|
||||
|
||||
open(P, "<$self->{properties}{passwordfile}")
|
||||
or croak("Error opening specified password file $self->{properties}{passwordfile}: $!");
|
||||
while (<P>) {
|
||||
chomp;
|
||||
next unless /\S/;
|
||||
next if /^\s*#/;
|
||||
my ($host, $username, $password) = split(/:/);
|
||||
carp("Line $. in $self->{properties}{passwordfile} is invalid"), next unless defined $host and defined $username and defined $password;
|
||||
$self->password($host, $username, $password);
|
||||
}
|
||||
close P;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub password {
|
||||
my $self = shift;
|
||||
my $host = shift;
|
||||
my $username = shift;
|
||||
my $newval = shift;
|
||||
$self->{password}{$host}{$username} = $newval if defined $newval;
|
||||
return $self->{password}{$host}{$username};
|
||||
}
|
||||
|
||||
1;
|
||||
134
debian/smokeping/usr/share/perl5/Smokeping/probes/skel.pm
vendored
Normal file
134
debian/smokeping/usr/share/perl5/Smokeping/probes/skel.pm
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package Smokeping::probes::skel;
|
||||
|
||||
=head1 301 Moved Permanently
|
||||
|
||||
This is a Smokeping probe module. Please use the command
|
||||
|
||||
C<smokeping -man Smokeping::probes::skel>
|
||||
|
||||
to view the documentation or the command
|
||||
|
||||
C<smokeping -makepod Smokeping::probes::skel>
|
||||
|
||||
to generate the POD document.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base qw(Smokeping::probes::basefork);
|
||||
# or, alternatively
|
||||
# use base qw(Smokeping::probes::base);
|
||||
use Carp;
|
||||
|
||||
sub pod_hash {
|
||||
return {
|
||||
name => <<DOC,
|
||||
Smokeping::probes::skel - a skeleton for Smokeping Probes
|
||||
DOC
|
||||
description => <<DOC,
|
||||
This is a non-functional module that is intended to act as a
|
||||
basis for creation of new probes. See the L<smokeping_extend>
|
||||
document for more information.
|
||||
DOC
|
||||
authors => <<'DOC',
|
||||
Niko Tyni <ntyni@iki.fi>,
|
||||
DOC
|
||||
see_also => <<DOC
|
||||
L<smokeping_extend>
|
||||
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} ) {
|
||||
# if you have to test the program output
|
||||
# or something like that, do it here
|
||||
# and bail out if necessary
|
||||
};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
# This is where you should declare your probe-specific variables.
|
||||
# The example shows the common case of checking the availability of
|
||||
# the specified binary.
|
||||
|
||||
sub probevars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::probevars, {
|
||||
#_mandatory => [ 'binary' ],
|
||||
#binary => {
|
||||
# _doc => "The location of your pingpong binary.",
|
||||
# _example => '/usr/bin/pingpong',
|
||||
# _sub => sub {
|
||||
# my $val = shift;
|
||||
# return "ERROR: pingpong 'binary' does not point to an executable"
|
||||
# unless -f $val and -x _;
|
||||
# return undef;
|
||||
# },
|
||||
#},
|
||||
});
|
||||
}
|
||||
|
||||
# Here's the place for target-specific variables
|
||||
|
||||
sub targetvars {
|
||||
my $class = shift;
|
||||
return $class->_makevars($class->SUPER::targetvars, {
|
||||
#weight => { _doc => "The weight of the pingpong ball in grams",
|
||||
# _example => 15
|
||||
#},
|
||||
});
|
||||
}
|
||||
|
||||
sub ProbeDesc($){
|
||||
my $self = shift;
|
||||
return "pingpong points";
|
||||
}
|
||||
|
||||
# this is where the actual stuff happens
|
||||
# you can access the probe-specific variables
|
||||
# via the $self->{properties} hash and the
|
||||
# target-specific variables via $target->{vars}
|
||||
|
||||
# If you based your class on 'Smokeping::probes::base',
|
||||
# you'd have to provide a "ping" method instead
|
||||
# of "pingone"
|
||||
|
||||
sub pingone ($){
|
||||
my $self = shift;
|
||||
my $target = shift;
|
||||
|
||||
# my $binary = $self->{properties}{binary};
|
||||
# my $weight = $target->{vars}{weight}
|
||||
# my $count = $self->pings($target); # the number of pings for this targets
|
||||
|
||||
# ping one target
|
||||
|
||||
# execute a command and parse its output
|
||||
# you should return a sorted array of the measured latency times
|
||||
# it could go something like this:
|
||||
|
||||
my @times;
|
||||
|
||||
#for (1..$count) {
|
||||
# open(P, "$cmd 2>&1 |") or croak("fork: $!");
|
||||
# while (<P>) {
|
||||
# /time: (\d+\.\d+)/ and push @times, $1;
|
||||
# }
|
||||
# close P;
|
||||
#}
|
||||
|
||||
|
||||
return @times;
|
||||
}
|
||||
|
||||
# That's all, folks!
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user