File Coverage

blib/lib/POE/Component/Server/NSCA.pm
Criterion Covered Total %
statement 293 342 85.6
branch 31 74 41.8
condition 4 10 40.0
subroutine 66 69 95.6
pod 6 6 100.0
total 400 501 79.8


line stmt bran cond sub pod time code
1             package POE::Component::Server::NSCA;
2             $POE::Component::Server::NSCA::VERSION = '0.12';
3             #ABSTRACT: a POE Component that implements NSCA daemon functionality
4              
5 3     3   326633 use strict;
  3         33  
  3         94  
6 3     3   15 use warnings;
  3         7  
  3         82  
7 3     3   1829 use Socket;
  3         11790  
  3         1347  
8 3     3   29 use Carp;
  3         7  
  3         153  
9 3     3   1764 use Net::Netmask;
  3         630614  
  3         443  
10 3     3   2351 use Math::Random;
  3         20002  
  3         418  
11 3     3   1718 use POE qw(Wheel::SocketFactory Wheel::ReadWrite Filter::Block);
  3         97767  
  3         22  
12              
13 3     3   259866 use constant MAX_INPUT_BUFFER => 2048 ; # /* max size of most buffers we use */
  3         10  
  3         211  
14 3     3   19 use constant MAX_HOST_ADDRESS_LENGTH => 256 ; # /* max size of a host address */
  3         10  
  3         158  
15 3     3   18 use constant MAX_HOSTNAME_LENGTH => 64 ;
  3         7  
  3         134  
16 3     3   16 use constant MAX_DESCRIPTION_LENGTH => 128;
  3         9  
  3         131  
17 3     3   19 use constant OLD_PLUGINOUTPUT_LENGTH => 512;
  3         6  
  3         170  
18 3     3   26 use constant MAX_PLUGINOUTPUT_LENGTH => 4096;
  3         6  
  3         142  
19 3     3   21 use constant MAX_PASSWORD_LENGTH => 512;
  3         6  
  3         122  
20 3     3   17 use constant TRANSMITTED_IV_SIZE => 128;
  3         6  
  3         132  
21 3     3   17 use constant SIZEOF_U_INT32_T => 4;
  3         6  
  3         272  
22 3     3   21 use constant SIZEOF_INT16_T => 2;
  3         6  
  3         236  
23 3     3   20 use constant SIZEOF_INIT_PACKET => TRANSMITTED_IV_SIZE + SIZEOF_U_INT32_T;
  3         6  
  3         138  
24              
25 3     3   18 use constant PROBABLY_ALIGNMENT_ISSUE => 4;
  3         7  
  3         219  
26              
27 3     3   22 use constant SIZEOF_DATA_PACKET => SIZEOF_INT16_T + SIZEOF_U_INT32_T + SIZEOF_U_INT32_T + SIZEOF_INT16_T + MAX_HOSTNAME_LENGTH + MAX_DESCRIPTION_LENGTH + MAX_PLUGINOUTPUT_LENGTH + PROBABLY_ALIGNMENT_ISSUE;
  3         6  
  3         202  
28 3     3   19 use constant SIZEOF_OLD_PACKET => SIZEOF_INT16_T + SIZEOF_U_INT32_T + SIZEOF_U_INT32_T + SIZEOF_INT16_T + MAX_HOSTNAME_LENGTH + MAX_DESCRIPTION_LENGTH + OLD_PLUGINOUTPUT_LENGTH + PROBABLY_ALIGNMENT_ISSUE;
  3         6  
  3         159  
29              
30 3     3   17 use constant ENCRYPT_NONE => 0 ; # /* no encryption */
  3         7  
  3         227  
31 3     3   21 use constant ENCRYPT_XOR => 1 ; # /* not really encrypted, just obfuscated */
  3         6  
  3         191  
32 3     3   23 use constant ENCRYPT_DES => 2 ; # /* DES */
  3         5  
  3         138  
33 3     3   18 use constant ENCRYPT_3DES => 3 ; # /* 3DES or Triple DES */
  3         28  
  3         189  
34 3     3   21 use constant ENCRYPT_CAST128 => 4 ; # /* CAST-128 */
  3         8  
  3         164  
35 3     3   20 use constant ENCRYPT_CAST256 => 5 ; # /* CAST-256 */
  3         6  
  3         167  
36 3     3   20 use constant ENCRYPT_XTEA => 6 ; # /* xTEA */
  3         43  
  3         178  
37 3     3   20 use constant ENCRYPT_3WAY => 7 ; # /* 3-WAY */
  3         6  
  3         146  
38 3     3   20 use constant ENCRYPT_BLOWFISH => 8 ; # /* SKIPJACK */
  3         6  
  3         137  
39 3     3   21 use constant ENCRYPT_TWOFISH => 9 ; # /* TWOFISH */
  3         7  
  3         166  
40 3     3   20 use constant ENCRYPT_LOKI97 => 10 ; # /* LOKI97 */
  3         8  
  3         161  
41 3     3   19 use constant ENCRYPT_RC2 => 11 ; # /* RC2 */
  3         12  
  3         188  
42 3     3   20 use constant ENCRYPT_ARCFOUR => 12 ; # /* RC4 */
  3         8  
  3         182  
43 3     3   20 use constant ENCRYPT_RC6 => 13 ; # /* RC6 */ ; # /* UNUSED */
  3         7  
  3         158  
44 3     3   17 use constant ENCRYPT_RIJNDAEL128 => 14 ; # /* RIJNDAEL-128 */
  3         6  
  3         163  
45 3     3   21 use constant ENCRYPT_RIJNDAEL192 => 15 ; # /* RIJNDAEL-192 */
  3         6  
  3         126  
46 3     3   17 use constant ENCRYPT_RIJNDAEL256 => 16 ; # /* RIJNDAEL-256 */
  3         8  
  3         169  
47 3     3   18 use constant ENCRYPT_MARS => 17 ; # /* MARS */ ; # /* UNUSED */
  3         6  
  3         166  
48 3     3   20 use constant ENCRYPT_PANAMA => 18 ; # /* PANAMA */ ; # /* UNUSED */
  3         6  
  3         142  
49 3     3   21 use constant ENCRYPT_WAKE => 19 ; # /* WAKE */
  3         5  
  3         182  
50 3     3   20 use constant ENCRYPT_SERPENT => 20 ; # /* SERPENT */
  3         7  
  3         136  
51 3     3   17 use constant ENCRYPT_IDEA => 21 ; # /* IDEA */ ; # /* UNUSED */
  3         6  
  3         149  
52 3     3   27 use constant ENCRYPT_ENIGMA => 22 ; # /* ENIGMA (Unix crypt) */
  3         27  
  3         171  
53 3     3   19 use constant ENCRYPT_GOST => 23 ; # /* GOST */
  3         5  
  3         141  
54 3     3   16 use constant ENCRYPT_SAFER64 => 24 ; # /* SAFER-sk64 */
  3         5  
  3         192  
55 3     3   20 use constant ENCRYPT_SAFER128 => 25 ; # /* SAFER-sk128 */
  3         10  
  3         174  
56 3     3   21 use constant ENCRYPT_SAFERPLUS => 26 ; # /* SAFER+ */
  3         6  
  3         9510  
57              
58             my $HAVE_MCRYPT = 0;
59             eval {
60             require Mcrypt;
61             $HAVE_MCRYPT++;
62             };
63              
64             # Lookups for loading.
65             my %mcrypts = ( ENCRYPT_NONE, "none",
66             ENCRYPT_XOR, "xor",
67             ENCRYPT_DES, "DES",
68             ENCRYPT_3DES, "3DES",
69             ENCRYPT_CAST128, "CAST_128",
70             ENCRYPT_CAST256, "CAST-256",
71             ENCRYPT_XTEA, "XTEA",
72             ENCRYPT_3WAY, "THREEWAY",
73             ENCRYPT_BLOWFISH, "BLOWFISH",
74             ENCRYPT_TWOFISH, "TWOFISH",
75             ENCRYPT_LOKI97, "LOKI97",
76             ENCRYPT_RC2, "RC2",
77             ENCRYPT_ARCFOUR, "ARCFOUR",
78             ENCRYPT_RC6, "RC6",
79             ENCRYPT_RIJNDAEL128, "RIJNDAEL_128",
80             ENCRYPT_RIJNDAEL192, "RIJNDAEL_192",
81             ENCRYPT_RIJNDAEL256, "RIJNDAEL_256",
82             ENCRYPT_MARS, "MARS",
83             ENCRYPT_PANAMA, "PANAMA",
84             ENCRYPT_WAKE, "WAKE",
85             ENCRYPT_SERPENT, "SERPENT",
86             ENCRYPT_IDEA, "IDEA",
87             ENCRYPT_ENIGMA, "ENGIMA",
88             ENCRYPT_GOST, "GOST",
89             ENCRYPT_SAFER64, "SAFER_SK64",
90             ENCRYPT_SAFER128, "SAFER_SK128",
91             ENCRYPT_SAFERPLUS, "SAFERPLUS",
92             );
93              
94             sub spawn {
95 3     3 1 393 my $package = shift;
96 3         27 my %opts = @_;
97 3         35 $opts{lc $_} = delete $opts{$_} for keys %opts;
98             croak "$package requires a 'password' argument\n"
99 3 50       19 unless defined $opts{password};
100             croak "$package requires an 'encryption' argument\n"
101 3 50       13 unless defined $opts{encryption};
102             croak "'encryption' argument must be a valid numeric\n"
103 3 50       16 unless defined $mcrypts{ $opts{encryption} };
104 3         9 my $options = delete $opts{options};
105 3   50     38 my $access = delete $opts{access} || [ Net::Netmask->new('any') ];
106 3 50       368 $access = [ ] unless ref $access eq 'ARRAY';
107 3         12 foreach my $acl ( @$access ) {
108 3 50       35 next unless $acl->isa('Net::Netmask');
109 3         8 push @{ $opts{access} }, $acl;
  3         16  
110             }
111 3         10 my $self = bless \%opts, $package;
112 3 100       51 $self->{session_id} = POE::Session->create(
113             object_states => [
114             $self => { shutdown => '_shutdown',
115             },
116             $self => [qw(
117             _start
118             _accept_client
119             _accept_failed
120             _conn_input
121             _conn_error
122             _conn_alarm
123             register
124             unregister
125             )],
126             ],
127             heap => $self,
128             ( ref($options) eq 'HASH' ? ( options => $options ) : () ),
129             )->ID();
130 3         640 return $self;
131             }
132              
133             sub shutdown {
134 3     3 1 6961 my $self = shift;
135 3         21 $poe_kernel->post( $self->{session_id}, 'shutdown' );
136             }
137              
138             sub session_id {
139 2     2 1 94 return $_[0]->{session_id};
140             }
141              
142             sub getsockname {
143 3 50   3 1 2733 return unless $_[0]->{listener};
144 3         16 return $_[0]->{listener}->getsockname();
145             }
146              
147             sub _length_encoder {
148 3     3   102 my $stuff = shift;
149 3         8 return;
150             }
151              
152             sub _length_decoder {
153 4     4   27560 my $stuff = shift;
154 4         9 my $expected;
155              
156 4 100       24 if (length($$stuff) <= 0) {
    50          
    0          
157             # not sure what the expected package size will be
158 2         6 return;
159             } elsif (length($$stuff) % SIZEOF_OLD_PACKET == 0) {
160             # buffer size divisible by old packet size
161 2         9 return SIZEOF_OLD_PACKET;
162             } elsif (length($$stuff) % SIZEOF_DATA_PACKET == 0) {
163             # buffer size divisible by the new packet size
164 0         0 return SIZEOF_DATA_PACKET;
165             } else {
166             # buffer size not divisible, let it fill a little more
167 0         0 return;
168             }
169             }
170              
171             sub _start {
172 3     3   1300 my ($kernel,$self,$sender) = @_[KERNEL,OBJECT,SENDER];
173 3         18 $self->{session_id} = $_[SESSION]->ID();
174 3 50       24 if ( $self->{alias} ) {
175 0         0 $kernel->alias_set( $self->{alias} );
176             }
177             else {
178 3         16 $kernel->refcount_increment( $self->{session_id} => __PACKAGE__ );
179             }
180 3         173 $self->{filter} = POE::Filter::Block->new(LengthCodec => [ \&_length_encoder, \&_length_decoder ]);
181             $self->{listener} = POE::Wheel::SocketFactory->new(
182             ( defined $self->{address} ? ( BindAddress => $self->{address} ) : () ),
183 3 50       298 ( defined $self->{port} ? ( BindPort => $self->{port} ) : ( BindPort => 5667 ) ),
    50          
184             SuccessEvent => '_accept_client',
185             FailureEvent => '_accept_failed',
186             SocketDomain => AF_INET, # Sets the socket() domain
187             SocketType => SOCK_STREAM, # Sets the socket() type
188             SocketProtocol => 'tcp', # Sets the socket() protocol
189             Reuse => 'on', # Lets the port be reused
190             );
191 3         1980 return;
192             }
193              
194             sub register {
195 2     2 1 210 my ($kernel,$self,$sender) = @_[KERNEL,OBJECT,SENDER];
196 2         7 my $sender_id = $sender->ID();
197 2         12 my %args;
198 2 50       9 if ( ref $_[ARG0] eq 'HASH' ) {
    0          
199 2         4 %args = %{ $_[ARG0] };
  2         11  
200             }
201             elsif ( ref $_[ARG0] eq 'ARRAY' ) {
202 0         0 %args = @{ $_[ARG0] };
  0         0  
203             }
204             else {
205 0         0 %args = @_[ARG0..$#_];
206             }
207 2         15 $args{lc $_} = delete $args{$_} for keys %args;
208 2 50       21 unless ( $args{event} ) {
209 0         0 warn "No 'event' argument supplied\n";
210 0         0 return;
211             }
212 2 50       9 if ( defined $self->{sessions}->{ $sender_id } ) {
213 0         0 $self->{sessions}->{ $sender_id } = \%args;
214             }
215             else {
216 2         7 $self->{sessions}->{ $sender_id } = \%args;
217 2         9 $kernel->refcount_increment( $sender_id, __PACKAGE__ );
218             }
219 2         81 return;
220             }
221              
222             sub unregister {
223 0     0 1 0 my ($kernel,$self,$sender) = @_[KERNEL,OBJECT,SENDER];
224 0         0 my $sender_id = $sender->ID();
225 0         0 my %args;
226 0 0       0 if ( ref $_[ARG0] eq 'HASH' ) {
    0          
227 0         0 %args = %{ $_[ARG0] };
  0         0  
228             }
229             elsif ( ref $_[ARG0] eq 'ARRAY' ) {
230 0         0 %args = @{ $_[ARG0] };
  0         0  
231             }
232             else {
233 0         0 %args = @_[ARG0..$#_];
234             }
235 0         0 $args{lc $_} = delete $args{$_} for keys %args;
236 0         0 my $data = delete $self->{sessions}->{ $sender_id };
237 0 0       0 $kernel->refcount_decrement( $sender_id, __PACKAGE__ ) if $data;
238 0         0 return;
239             }
240              
241             sub _shutdown {
242 3     3   936 my ($kernel,$self) = @_[KERNEL,OBJECT];
243 3         21 delete $self->{listener};
244 3         655 delete $self->{clients};
245 3         10 $kernel->refcount_decrement( $_, __PACKAGE__ ) for keys %{ $self->{sessions} };
  3         23  
246 3         117 $kernel->alarm_remove_all();
247 3         145 $kernel->alias_remove( $_ ) for $kernel->alias_list();
248 3 50       132 $kernel->refcount_decrement( $self->{session_id} => __PACKAGE__ ) unless $self->{alias};
249 3         158 return;
250             }
251              
252             sub _accept_failed {
253 0     0   0 my ($kernel,$self,$operation,$errnum,$errstr,$wheel_id) = @_[KERNEL,OBJECT,ARG0..ARG3];
254 0         0 warn "Listener: $wheel_id generated $operation error $errnum: $errstr\n";
255 0         0 delete $self->{listener};
256 0         0 $kernel->yield( '_shutdown' );
257 0         0 return;
258             }
259              
260             sub _accept_client {
261 3     3   6119 my ($kernel,$self,$socket,$peeraddr,$peerport) = @_[KERNEL,OBJECT,ARG0..ARG2];
262 3         57 my $sockaddr = inet_ntoa( ( unpack_sockaddr_in ( CORE::getsockname $socket ) )[1] );
263 3         38 my $sockport = ( unpack_sockaddr_in ( CORE::getsockname $socket ) )[0];
264 3         19 $peeraddr = inet_ntoa( $peeraddr );
265              
266 3 50       8 return unless grep { $_->match( $peeraddr ) } @{ $self->{access} };
  3         20  
  3         14  
267              
268             my $wheel = POE::Wheel::ReadWrite->new(
269             Handle => $socket,
270             Filter => $self->{filter},
271 3         399 InputEvent => '_conn_input',
272             ErrorEvent => '_conn_error',
273             FlushedEvent => '_conn_flushed',
274             );
275              
276 3 50       1293 return unless $wheel;
277              
278 3         14 my $id = $wheel->ID();
279 3         15 my $time = time();
280 3         21 my $iv = join '', random_uniform_integer(128,0,9);
281 3         788 my $init_packet = $iv . pack 'N', $time;
282 3         33 $self->{clients}->{ $id } =
283             {
284             wheel => $wheel,
285             peeraddr => $peeraddr,
286             peerport => $peerport,
287             sockaddr => $sockaddr,
288             sockport => $sockport,
289             ts => $time,
290             iv => $iv,
291             };
292 3   50     34 $self->{clients}->{ $id }->{alarm} = $kernel->delay_set( '_conn_alarm', $self->{time_out} || 60, $id );
293 3         288 $wheel->put( $init_packet );
294 3         272 return;
295             }
296              
297             sub _conn_exists {
298 5     5   17 my ($self,$wheel_id) = @_;
299 5 50 33     47 return 0 unless $wheel_id and defined $self->{clients}->{ $wheel_id };
300 5         22 return 1;
301             }
302              
303             sub _conn_error {
304 2     2   1395 my ($self,$errstr,$id) = @_[OBJECT,ARG2,ARG3];
305 2 50       11 return unless $self->_conn_exists( $id );
306 2         13 delete $self->{clients}->{ $id };
307 2         513 return;
308             }
309              
310             sub _conn_alarm {
311 1     1   10008922 my ($kernel,$self,$id) = @_[KERNEL,OBJECT,ARG0];
312 1 50       7 return unless $self->_conn_exists( $id );
313 1         18 delete $self->{clients}->{ $id };
314 1         552 return;
315             }
316              
317             sub _conn_input {
318 2     2   143 my ($kernel,$self,$packet,$id) = @_[KERNEL,OBJECT,ARG0,ARG1];
319 2 50       8 return unless $self->_conn_exists( $id );
320 2         6 my $client = $self->{clients}->{ $id };
321 2         12 $kernel->alarm_remove( delete $client->{alarm} );
322 2         234 my $data_packet_length = length($packet);
323 2         10 my $input = _decrypt( $packet, $self->{encryption}, $client->{iv}, $self->{password}, $data_packet_length );
324 2 50       10 return unless $input; # something wrong with the decryption
325 2         13 my $version = unpack 'n', substr $input, 0, 4;
326 2 0 33     8 return unless $version == 3 or $client->{version_already_checked}; # Wrong version received
327 2         6 $client->{version_already_checked} = 1;
328 2         10 my $crc32 = unpack 'N', substr $input, 4, 4;
329 2         6 my $ts = unpack 'N', substr $input, 8, 4;
330 2         7 my $rc = unpack 'n', substr $input, 12, 2;
331 2         6 my $firstbit = substr $input, 0, 4;
332 2         16 my $secondbit = substr $input, 8;
333 2         13 my $checksum = _calculate_crc32( $firstbit . pack('N', 0) . $secondbit );
334 2         19 my @data = unpack 'a[64]a[128]a[512]', substr $input, 14;
335 2         35 s/\000.*$// for @data;
336 2         32 my $result = {
337             version => $version,
338             crc32 => $crc32,
339             checksum => $checksum,
340             return_code => $rc,
341             timestamp => $ts,
342             };
343 2         17 $result->{$_} = shift @data for qw(host_name svc_description plugin_output);
344 2         17 $result->{$_} = $client->{$_} for qw(peeraddr peerport sockaddr sockport ts iv);
345             $kernel->post( $_, $self->{sessions}->{$_}->{event}, $result, $self->{sessions}->{$_}->{context} )
346 2         5 for keys %{ $self->{sessions} };
  2         36  
347 2         237 return;
348             }
349              
350             #/* calculates the CRC 32 value for a buffer */
351             sub _calculate_crc32 {
352 2     2   6 my $string = shift;
353              
354 2         19 my $crc32_table = _generate_crc32_table();
355 2         10 my $crc = 0xFFFFFFFF;
356              
357 2         153 foreach my $tchar (split(//, $string)) {
358 1440         2019 my $char = ord($tchar);
359 1440         2501 $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc32_table->[($crc ^ $char) & 0xFF];
360             }
361              
362 2         78 return ($crc ^ 0xFFFFFFFF);
363             }
364              
365             #/* build the crc table - must be called before calculating the crc value */
366             sub _generate_crc32_table {
367 2     2   5 my $crc32_table = [];
368 2         5 my $poly = 0xEDB88320;
369              
370 2         11 for (my $i = 0; $i < 256; $i++){
371 512         716 my $crc = $i;
372 512         919 for (my $j = 8; $j > 0; $j--) {
373 4096 100       6417 if ($crc & 1) {
374 2048         3778 $crc = ($crc >> 1) ^ $poly;
375             }
376             else {
377 2048         3729 $crc = ($crc >> 1);
378             }
379             }
380 512         987 $crc32_table->[$i] = $crc;
381             }
382 2         8 return $crc32_table;
383             }
384              
385             # central switchboard for encryption methods.
386             sub _decrypt {
387 2     2   7 my ($data_packet_string, $encryption_method, $iv_salt, $password, $data_packet_length) = @_;
388              
389 2         4 my $crypted;
390 2 100       8 if ($encryption_method == ENCRYPT_NONE) {
    50          
391 1         2 $crypted = $data_packet_string;
392             }
393             elsif ($encryption_method == ENCRYPT_XOR) {
394 1         3 $crypted = _decrypt_xor($data_packet_string, $iv_salt, $password, $data_packet_length);
395             }
396             else {
397 0         0 $crypted = _decrypt_mcrypt( $data_packet_string, $encryption_method, $iv_salt, $password );
398             }
399 2         8 return $crypted;
400             }
401              
402             sub _decrypt_xor {
403 1     1   4 my ($data_packet_string, $iv_salt, $password, $data_packet_length) = @_;
404              
405 1         104 my @out = split(//, $data_packet_string);
406 1         17 my @salt_iv = split(//, $iv_salt);
407 1         14 my @salt_pw = split(//, $password);
408              
409 1         4 my $y = 0;
410 1         2 my $x = 0;
411              
412             #/* rotate over IV we received from the server... */
413 1         4 while ($y < $data_packet_length) {
414             #/* keep rotating over IV */
415 720         1298 $out[$y] = $out[$y] ^ $salt_iv[$x % scalar(@salt_iv)];
416              
417 720         1007 $y++;
418 720         1306 $x++;
419             }
420              
421 1 50       6 if (scalar(@salt_pw) > 0) {
422             #/* rotate over password... */
423 1         2 $y=0;
424 1         3 $x=0;
425 1         3 while ($y < $data_packet_length){
426             #/* keep rotating over password */
427 720         1167 $out[$y] = $out[$y] ^ $salt_pw[$x % scalar(@salt_pw)];
428              
429 720         1010 $y++;
430 720         1239 $x++;
431             }
432             }
433 1         72 return join '', @out;
434             }
435              
436             sub _decrypt_mcrypt {
437 0     0     my ( $data_packet_string, $encryption_method, $iv_salt, $password ) = @_;
438 0           my $crypted;
439 0           my $evalok = 0;
440 0 0         if( $HAVE_MCRYPT ){
441             # Initialise the routine
442 0 0         if( defined( $mcrypts{$encryption_method} ) ){
443             # Load the routine.
444 0           my $routine = $mcrypts{$encryption_method};
445 0           eval {
446             # This sometimes dies with 'mcrypt is not of type MCRYPT'.
447 0           my $td = Mcrypt->new( algorithm => &{\&{"Mcrypt::".$routine}}(), mode => Mcrypt::CFB(), verbose => 0 );
  0            
  0            
448 0           my $key = $password;
449 0           my $iv = substr $iv_salt, 0, $td->{IV_SIZE};
450 0 0         if( defined( $td ) ){
451 0           $td->init($key, $iv);
452 0           for (my $i = 0; $i < length( $data_packet_string ); $i++ ) {
453 0           $crypted .= $td->decrypt( substr $data_packet_string, 0+$i, 1 );
454             }
455 0           $td->end();
456             }
457 0           $evalok++;
458             };
459 0 0         warn "$@\n" if $@;
460             }
461             } else {
462 0           warn "Mcrypt module missing\n";
463             }
464 0           return $crypted;
465             }
466              
467             'Hon beiriant goes at hun ar ddeg';
468              
469             __END__