File Coverage

blib/lib/POE/Component/Client/NRPE.pm
Criterion Covered Total %
statement 153 171 89.4
branch 35 52 67.3
condition 17 31 54.8
subroutine 19 19 100.0
pod 1 1 100.0
total 225 274 82.1


line stmt bran cond sub pod time code
1             package POE::Component::Client::NRPE;
2             {
3             $POE::Component::Client::NRPE::VERSION = '0.20';
4             }
5              
6             #ABSTRACT: A POE Component that implements check_nrpe functionality
7              
8 9     9   319524 use strict;
  9         20  
  9         352  
9 9     9   44 use warnings;
  9         20  
  9         280  
10 9     9   9776 use POE qw(Wheel::SocketFactory Filter::Stream Wheel::ReadWrite);
  9         632618  
  9         65  
11 9     9   2177172 use Net::SSLeay;
  9         104719  
  9         2024  
12 9     9   11013 use POE::Component::SSLify qw( Client_SSLify );
  9         107018  
  9         663  
13 9     9   89 use Carp;
  9         20  
  9         657  
14 9     9   52 use Socket;
  9         21  
  9         6783  
15 9     9   8490 use integer;
  9         97  
  9         61  
16              
17             sub check_nrpe {
18 9     9 1 23291 my $package = shift;
19 9         79 my %params = @_;
20 9         116 $params{lc $_} = delete $params{$_} for keys %params;
21 9 50       54 croak "$package requires a 'host' argument\n"
22             unless $params{host};
23 9 50       44 croak "$package requires an 'event' argument\n"
24             unless $params{event};
25 9 100       65 $params{port} = 5666 unless defined $params{port};
26 9 50       56 $params{command} = '_NRPE_CHECK' unless $params{command};
27 9 50       41 $params{command} = join( '!', $params{command}, $params{args} ) if defined $params{args};
28 9 100 66     77 $params{version} = 2 unless $params{version} and $params{version} eq '1';
29 9 100 66     131 $params{usessl} = 1 unless defined $params{usessl} and $params{usessl} eq '0';
30 9 100 66     90 $params{timeout} = 10 unless defined $params{timeout} and $params{timeout} =~ /^\d+$/;
31 9         37 my $options = delete $params{options};
32 9         36 my $self = bless \%params, $package;
33 9 50       136 $self->{session_id} = POE::Session->create(
34             object_states => [
35             $self => [ qw(_start _connect _sock_up _sock_err _sock_in _sock_down _send_response _timeout) ],
36             ],
37             heap => $self,
38             ( ref($options) eq 'HASH' ? ( options => $options ) : () ),
39             )->ID();
40 9         1037 return $self;
41             }
42              
43             sub _start {
44 9     9   2088 my ($kernel,$sender,$self) = @_[KERNEL,SENDER,OBJECT];
45 9         54 $self->{session_id} = $_[SESSION]->ID();
46 9         117 $self->{filter} = POE::Filter::Stream->new();
47 9 50 33     127 if ( $kernel == $sender and !$self->{session} ) {
48 0         0 croak "Not called from another POE session and 'session' wasn't set\n";
49             }
50 9         24 my $sender_id;
51 9 50       36 if ( $self->{session} ) {
52 0 0       0 if ( my $ref = $kernel->alias_resolve( $self->{session} ) ) {
53 0         0 $sender_id = $ref->ID();
54             }
55             else {
56 0         0 croak "Could not resolve 'session' to a valid POE session\n";
57             }
58             }
59             else {
60 9         35 $sender_id = $sender->ID();
61             }
62 9         67 $kernel->refcount_increment( $sender_id, __PACKAGE__ );
63 9         251 $self->{sender_id} = $sender_id;
64 9         56 $kernel->yield( '_connect' );
65 9         702 return;
66             }
67              
68             sub _connect {
69 9     9   9591 my ($kernel,$self) = @_[KERNEL,OBJECT];
70 9         103 $self->{sockfactory} = POE::Wheel::SocketFactory->new(
71             SocketProtocol => 'tcp',
72             RemoteAddress => $self->{host},
73             RemotePort => $self->{port},
74             SuccessEvent => '_sock_up',
75             FailureEvent => '_sock_err',
76             );
77 9         8965 $kernel->delay( '_timeout', $self->{timeout} );
78 9         973 return;
79             }
80              
81             sub _timeout {
82 2     2   10009529 my ($kernel,$self) = @_[KERNEL,OBJECT];
83 2         10 delete $self->{sockfactory};
84 2         28 delete $self->{socket};
85 2         936 $kernel->yield( '_send_response', 'timeout' );
86 2         168 return;
87             }
88              
89             sub _sock_err {
90 2     2   950 my ($kernel,$self) = @_[KERNEL,OBJECT];
91 2         64 $kernel->delay( '_timeout' );
92 2         181 delete $self->{sockfactory};
93 2         66 $kernel->yield( '_send_response', 'sockerr', @_[ARG0..ARG2] );
94 2         111 return;
95             }
96              
97             sub _sock_up {
98 7     7   8004 my ($kernel,$self,$socket) = @_[KERNEL,OBJECT,ARG0];
99 7         211 $kernel->delay( '_timeout' );
100 7         3244 delete $self->{sockfactory};
101             # Only version 2 supports SSL
102 7 50 66     1087 if ( $self->{version} == 2 and $self->{usessl} ) {
103 0         0 my $ctx = Net::SSLeay::CTX_tlsv1_new();
104 0         0 Net::SSLeay::CTX_set_cipher_list( $ctx, 'ADH');
105 0         0 eval { $socket = Client_SSLify( $socket, undef, undef, $ctx ); };
  0         0  
106 0 0       0 warn "Failed to SSLify the socket: $@\n" if $@;
107             }
108 7         219 $self->{socket} = new POE::Wheel::ReadWrite
109             ( Handle => $socket,
110             Filter => $self->{filter},
111             InputEvent => '_sock_in',
112             ErrorEvent => '_sock_down',
113             );
114 7         4148 my $packet;
115 7 100       33 if ( $self->{version} == 1 ) {
116 1         9 $packet = pack "NNNNa[1024]", 1, 1, 0, length( $self->{command} ), $self->{command};
117             }
118             else {
119 6         43 $packet = _gen_packet_ver2( $self->{command} );
120             }
121 7         77 $self->{socket}->put( $packet );
122 7         706 $kernel->delay( '_timeout', $self->{timeout} );
123 7         841 return;
124             }
125              
126             sub _sock_down {
127 1     1   3374 my ($kernel,$self) = @_[KERNEL,OBJECT];
128 1         5 delete $self->{socket};
129 1         217 $kernel->delay( '_timeout' );
130 1 50       110 $kernel->yield( '_send_response', 'nodata' ) unless $self->{_data_returned};
131 1         70 return;
132             }
133              
134             sub _sock_in {
135 4     4   10269 my ($kernel,$self,$input) = @_[KERNEL,OBJECT,ARG0];
136 4         7 my ($result,$data);
137             SWITCH: {
138 4 100       7 if ( $self->{version} == 1 ) {
  4         25  
139 1         2 my $length = length $input;
140 1 50       6 if ( $length != 1040 ) {
141 0         0 $result = 3;
142 0         0 $data = sprintf "CHECK_NRPE: Received %d bytes (%d expected)", $length, 1040;
143 0         0 last SWITCH;
144             }
145 1         7 my @args = unpack "NNNNa*", $input;
146 1 50 33     22 if ( $args[0] ne '2' or $args[1] ne '1' or $args[2] !~ /^[0123]$/ ) {
      33        
147 0         0 $result = 3;
148 0         0 $data = 'CHECK_NRPE: Packet failed sanity checking';
149 0         0 last SWITCH;
150             }
151 1         14 $args[4] =~ s/\x00*$//g;
152 1         3 $result = $args[2];
153 1   50     6 $data = $args[4] || 'CHECK_NRPE: No output returned from NRPE daemon.';
154             }
155             else {
156 3         9 my $length = length $input;
157 3 100       14 if ( $length != 1036 ) {
158 1         1 $result = 3;
159 1         6 $data = sprintf "CHECK_NRPE: Received %d bytes (%d expected)", $length, 1036;
160 1         3 last SWITCH;
161             }
162 2         14 my @args = unpack "nnNnZ*", $input;
163 2 50 66     29 if ( $args[0] ne '2' or $args[1] ne '2' or $args[3] !~ /^[0123]$/ ) {
      66        
164 1         2 $result = 3;
165 1         2 $data = 'CHECK_NRPE: Packet failed sanity checking';
166 1         5 last SWITCH;
167             }
168 1         11 $args[4] =~ s/\x00*$//g;
169 1         2 $result = $args[3];
170 1   50     5 $data = $args[4] || 'CHECK_NRPE: No output returned from NRPE daemon.';
171             }
172             }
173 4         14 $self->{_data_returned} = [ $result, $data ];
174 4         20 delete $self->{socket};
175 4         794 $kernel->yield( '_send_response', 'gotdata', $result, $data );
176 4         218 return;
177             }
178              
179             sub _send_response {
180 9     9   3382 my ($kernel,$self,$type) = @_[KERNEL,OBJECT,ARG0];
181 9         27 my $response = { };
182 9         101 $response->{$_} = $self->{$_} for qw(version host command context);
183             SWITCH: {
184 9 100       20 if ( $type eq 'gotdata' ) {
  9         58  
185 4         13 $response->{result} = $_[ARG1];
186 4         10 $response->{data} = $_[ARG2];
187 4         11 last SWITCH;
188             }
189 5 100       35 if ( $type eq 'nodata' ) {
190 1         3 $response->{result} = 3;
191 1         3 $response->{data} = 'CHECK NRPE: Error receiving data from daemon.';
192 1         4 last SWITCH;
193             }
194 4 100       17 if ( $type eq 'sockerr' ) {
195 2         5 $response->{result} = 3;
196 2         14 $response->{data} = 'CHECK NRPE: socket error: ' . join(' ', @_[ARG1..$#_]);
197 2         4 last SWITCH;
198             }
199 2 50       10 if ( $type eq 'timeout' ) {
200 2 100       16 $response->{result} = ( $self->{unknown} ? 3 : 2 );
201 2         20 $response->{data} = sprintf("CHECK_NRPE: Socket timeout after %d seconds.", $self->{timeout} );
202 2         7 last SWITCH;
203             }
204             }
205 9         244 $kernel->post( $self->{sender_id}, $self->{event}, $response );
206 9         829 $kernel->refcount_decrement( $self->{sender_id}, __PACKAGE__ );
207 9         395 $kernel->alarm_remove_all();
208 9         600 return;
209             }
210              
211             # These functions are derived from http://www.stic-online.de/stic/html/nrpe-generic.html
212             # Copyright (C) 2006, 2007 STIC GmbH, http://www.stic-online.de
213             # Licensed under GPLv2
214              
215             sub _gen_packet_ver2 {
216 6     6   13 my $data = shift;
217 6         56 for ( my $i = length ( $data ); $i < 1024; $i++ ) {
218 6078         10343 $data .= "\x00";
219             }
220 6         15 $data .= "SR";
221 6         31 my $res = pack "n", 2324;
222 6         15 my $packet = "\x00\x02\x00\x01";
223 6         54 my $tail = $res . $data;
224 6         40 my $crc = ~_crc32( $packet . "\x00\x00\x00\x00" . $tail );
225 6         74 $packet .= pack ( "N", $crc ) . $tail;
226 6         38 return $packet;
227             }
228              
229             sub _crc32 {
230 8     8   6342 my $crc;
231             my $len;
232 0         0 my $i;
233 0         0 my $index;
234 0         0 my @args;
235 8         16 my ($arg) = @_;
236 8         292 my @crc_table =(
237             0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
238             0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
239             0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
240             0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
241             0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
242             0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
243             0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
244             0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
245             0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
246             0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
247             0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
248             0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
249             0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
250             0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
251             0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
252             0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
253             0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
254             0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
255             0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
256             0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
257             0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
258             0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
259             0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
260             0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
261             0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
262             0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
263             0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
264             0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
265             0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
266             0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
267             0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
268             0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
269             0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
270             0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
271             0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
272             0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
273             0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
274             0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
275             0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
276             0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
277             0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
278             0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
279             0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
280             0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
281             0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
282             0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
283             0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
284             0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
285             0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
286             0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
287             0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
288             0x2d02ef8d
289             );
290              
291 8         18 $crc = 0xffffffff;
292 8         13 $len = length($arg);
293 8         1186 @args = unpack "c*", $arg;
294 8         228 for ($i = 0; $i < $len; $i++) {
295 8288         8107 $index = ($crc ^ $args[$i]) & 0xff;
296 8288         15324 $crc = $crc_table[$index] ^ (($crc >> 8) & 0x00ffffff);
297             }
298 8         223 return $crc;
299             }
300              
301             'POE it';
302              
303             __END__