summaryrefslogtreecommitdiffstats
path: root/lib/probes/SSH.pm
blob: f91a8d0beb77b7a2e8eb80e4e369ea7388c95de3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package probes::SSH;

=head1 301 Moved Permanently

This is a Smokeping probe module. Please use the command 

C<smokeping -man probes::SSH>

to view the documentation or the command

C<smokeping -makepod probes::SSH>

to generate the POD document.

=cut

use strict;
use base qw(probes::basefork);
use IPC::Open3;
use Symbol;
use Carp;
use POSIX;

sub pod_hash {
	return {
		name => <<DOC,
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.
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 rsa localhost";
        my $return = `$call 2>&1`;
        if ($return =~ m/$ssh_re/s){
            $self->{pingfactor} = 10;
            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 rsa $host";
    my @times;

    # 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 @times1 = POSIX::times;
	my $pid = open3($inh,$outh,$errh, $query);
	while (<$outh>) {
	    if (/$ssh_re/i) {
		last;
	    }
	}
	waitpid $pid,0;
	close $errh;
	close $inh;
	close $outh;
    	my @times2 = POSIX::times;
	push @times, $times2[0]-$times1[0];
    }
    @times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep {$_ ne "-"} @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;
			},
		},
	})
}

1;