File Coverage

blib/lib/Net/Prober/ssh.pm
Criterion Covered Total %
statement 34 40 85.0
branch 4 10 40.0
condition 1 3 33.3
subroutine 8 8 100.0
pod 0 2 0.0
total 47 63 74.6


line stmt bran cond sub pod time code
1             package Net::Prober::ssh;
2             $Net::Prober::ssh::VERSION = '0.16';
3 1     1   2 use strict;
  1         1  
  1         23  
4 1     1   2 use warnings;
  1         2  
  1         22  
5 1     1   3 use base 'Net::Prober::Probe::TCP';
  1         1  
  1         345  
6              
7 1     1   4 use Carp ();
  1         1  
  1         370  
8              
9             sub defaults {
10 2     2 0 2 my ($self) = @_;
11              
12 2         5 my $defaults = $self->SUPER::defaults();
13 2         3 $defaults->{port} = 22;
14              
15 2         3 return $defaults;
16             }
17              
18             sub probe {
19 1     1 0 1 my ($self, $args) = @_;
20              
21 1         5 my ($host, $port, $timeout, $username, $password) =
22             $self->parse_args($args, qw(host port timeout username password));
23              
24 1         5 my $t0 = $self->time_now();
25              
26 1         7 my $sock = $self->open_socket($args);
27 1 50       278418 if (! $sock) {
28 0         0 return $self->probe_failed(
29             reason => qq{Couldn't connect to SSH server $host:$port},
30             );
31             }
32              
33 1         6 chomp (my $ssh_banner = $self->_get_reply($sock));
34              
35 1 50       22 if (! $ssh_banner) {
36 0         0 return $self->probe_failed(
37             reason => qq{Couldn't get SSH banner from $host:$port}
38             );
39             }
40              
41             # SSH-protoversion-softwareversion SP comments CR LF
42 1 50       32 if ($ssh_banner !~ qr{^SSH-
43             (? [^\-]+) -
44             (? [^\s]+) \s?
45             (? .*)? $}x) {
46 0         0 return $self->probe_failed(
47             reason => qq{Non-RFC compliant SSH banner from $host:$port? ($ssh_banner)},
48             );
49             }
50              
51             my %ssh_info = (
52             protoversion => $+{protoversion},
53             softwareversion => $+{softwareversion},
54             comments => $+{comments},
55 1         35 banner => $ssh_banner,
56             );
57              
58             # We can't try to login if we haven't got credentials
59 1 50 33     20 if ($username && $password) {
60 0         0 $self->_send_command($sock, $username . "\n" . $password . "\n");
61 0 0       0 if (! $self->_get_reply($sock)) {
62 0         0 return $self->probe_failed(
63             reason => qq{Couldn't login to ssh $host:$port with user $username},
64             );
65             }
66             }
67              
68             # Say goodbye
69 1         6 $self->_send_command($sock, 'exit');
70              
71 1         118 return $self->probe_ok(%ssh_info);
72             }
73              
74             sub _send_command {
75 1     1   3 my ($self, $sock, $text_input) = @_;
76 1         14 return $sock->send($text_input);
77             }
78              
79             sub _get_reply {
80 1     1   2 my ($self, $sock) = @_;
81 1         10 $sock->recv(my $reply, 1024);
82 1         160176 $reply =~ s{\s+$}{};
83 1         8 return $reply;
84             }
85              
86             1;
87              
88             __END__