File Coverage

blib/lib/Net/Connection/Match.pm
Criterion Covered Total %
statement 80 91 87.9
branch 24 38 63.1
condition 6 12 50.0
subroutine 9 9 100.0
pod 2 2 100.0
total 121 152 79.6


line stmt bran cond sub pod time code
1             package Net::Connection::Match;
2              
3 2     2   272098 use 5.006;
  2         42  
4 2     2   13 use strict;
  2         5  
  2         55  
5 2     2   11 use warnings;
  2         4  
  2         98  
6 2     2   13 use base 'Error::Helper';
  2         4  
  2         1199  
7              
8             =head1 NAME
9              
10             Net::Connection::Match - Runs a stack of checks to match Net::Connection objects.
11              
12             =head1 VERSION
13              
14             Version 0.5.0
15              
16             =cut
17              
18             our $VERSION = '0.5.0';
19              
20              
21             =head1 SYNOPSIS
22              
23             use Net::Connection::Match;
24             use Net::Connection;
25            
26             my $connection_args={
27             foreign_host=>'10.0.0.1',
28             foreign_port=>'22',
29             local_host=>'10.0.0.2',
30             local_port=>'12322',
31             proto=>'tcp4',
32             state=>'LISTEN',
33             };
34             my $conn=Net::Connection->new( $connection_args );
35            
36             my %args=(
37             checks=>[
38             {
39             type=>'Ports',
40             invert=>0,
41             args=>{
42             ports=>[
43             '22',
44             ],
45             lports=>[
46             '53',
47             ],
48             fports=>[
49             '12345',
50             ],
51             }
52             },
53             {
54             type=>'Protos',
55             invert=>0,
56             args=>{
57             protos=>[
58             'tcp4',
59             ],
60             }
61             }
62             ]
63             );
64            
65             my $checker;
66             eval{
67             $checker=Net::Connection::Match->new( \%args );
68             } or die "New failed with...".$@;
69            
70             if ( $check->match( $conn ) ){
71             print "It matched!\n";
72             }
73              
74             =head1 METHODS
75              
76             =head2 new
77              
78             This initializes a new check object.
79              
80             It takes one value and thht is a hash ref with the key checks.
81             This is a array of hashes. If the array is empty, it will default
82             to using the All test.
83              
84             If new fails, it will die.
85              
86             =head3 checks hash keys
87              
88             =head4 type
89              
90             This is the name of the check relative to 'Net::Connection::Match::'.
91              
92             So 'Net::Connection::Match::PTR' would become 'PTR'.
93              
94             =head4 args
95              
96             This is a hash or args to pash to the check. These are passed to the new
97             method of the check module.
98              
99             =head4 invert
100              
101             This is either boolean on if the check should be inverted or not.
102              
103             my $mce;
104             eval{
105             $ncm=Net::Connection::Match->new( $args );
106             };
107              
108             =cut
109              
110             sub new{
111 3     3 1 976 my %args;
112 3 100       11 if(defined($_[1])){
113 2         4 %args= %{$_[1]};
  2         9  
114             };
115              
116             # Provides some basic checks.
117             # Could make these all one if, but this provides more
118             # granularity for some one using it.
119 3 100       11 if ( ! defined( $args{checks} ) ){
120 1         11 die ('No check key specified in the argument hash');
121             }
122 2 50       4 if ( ref( @{ $args{checks} } ) eq 'ARRAY' ){
  2         7  
123 0         0 die ('The checks key is not a array');
124             }
125             # Will never match anything.
126 2 50       7 if ( ! defined $args{checks}[0] ){
127 0         0 $args{checks}[0] = {
128             type => 'All',
129             invert => 0,
130             args => {}
131             };
132              
133             }
134 2 50       3 if ( ref( %{ $args{checks}[0] } ) eq 'HASH' ){
  2         8  
135 0         0 die ('The first item in the checks array is not a hash');
136             }
137              
138 2         15 my $self = {
139             perror=>undef,
140             error=>undef,
141             errorString=>"",
142             testing=>0,
143             errorExtra=>{
144             flags=>{
145             1=>'failedCheckInit',
146             2=>'notNCobj',
147             }
148             },
149             checks=>[],
150             };
151 2         5 bless $self;
152              
153             # Loads up each check or dies if it fails to.
154 2         4 my $check_int=0;
155 2         7 while( defined( $args{checks}[$check_int] ) ){
156 3         11 my %new_check=(
157             type=>undef,
158             args=>undef,
159             invert=>undef,
160             );
161              
162             # make sure we have a check type
163 3 50       8 if ( defined($args{checks}[$check_int]{'type'}) ){
164 3         8 $new_check{type}=$args{checks}[$check_int]{'type'};
165             }else{
166 0         0 die('No type defined for check '.$check_int);
167             }
168              
169             # does a quick check on the tpye name
170 3         6 my $type_test=$new_check{type};
171 3         21 $type_test=~s/[A-Za-z0-9]//g;
172 3         5 $type_test=~s/\:\://g;
173 3 50       13 if ( $type_test !~ /^$/ ){
174 0         0 die 'The type "'.$new_check{type}.'" for check '.$check_int.' is not a valid check name';
175             }
176              
177             # makes sure we have a args object and that it is a hash
178 3 50 33     20 if (
179             ( defined($args{checks}[$check_int]{'args'}) ) &&
180             ( ref( $args{checks}[$check_int]{'args'} ) eq 'HASH' )
181             ){
182 3         20 $new_check{args}=$args{checks}[$check_int]{'args'};
183             }else{
184 0         0 die('No type defined for check '.$check_int.' or it is not a HASH');
185             }
186              
187             # makes sure we have a args object and that it is a hash
188 3 50 33     47 if (
    50 33        
189             ( defined($args{checks}[$check_int]{'invert'}) ) &&
190             ( ref( \$args{checks}[$check_int]{'invert'} ) ne 'SCALAR' )
191             ){
192 0         0 die('Invert defined for check '.$check_int.' but it is not a SCALAR');
193             }elsif(
194             ( defined($args{checks}[$check_int]{'invert'}) ) &&
195             ( ref( \$args{checks}[$check_int]{'invert'} ) eq 'SCALAR' )
196             ){
197 3         7 $new_check{invert}=$args{checks}[$check_int]{'invert'};
198             }
199              
200 3         6 my $check;
201             my $eval_string='use Net::Connection::Match::'.$new_check{type}.';'.
202 3         12 '$check=Net::Connection::Match::'.$new_check{type}.'->new( $new_check{args} );';
203 3     1   253 eval( $eval_string );
  1     1   511  
  1     1   4  
  1         38  
  1         9  
  1         12  
  1         45  
  1         485  
  1         3  
  1         37  
204              
205 3 50       11 if (!defined( $check )){
206 0         0 die 'Failed to init the check for '.$check_int.' as it returned undef... '.$@;
207             }
208              
209 3         8 $new_check{check}=$check;
210              
211 3         5 push(@{ $self->{checks} }, \%new_check );
  3         23  
212              
213 3         11 $check_int++;
214             }
215              
216 2 50       8 if ( $args{testing} ){
217 2         5 $self->{testing}=1;
218             }
219              
220 2         12 return $self;
221             }
222              
223             =head2 match
224              
225             Checks if a single Net::Connection object matches the stack.
226              
227             One object is argument is taken and that is the Net::Connection to check.
228              
229             The return value is a boolean.
230              
231             if ( $ncm->match( $conn ) ){
232             print "It matched.\n";
233             }
234              
235             =cut
236              
237             sub match{
238 5     5 1 2955 my $self=$_[0];
239 5         8 my $conn=$_[1];
240              
241 5 50       30 if( ! $self->errorblank ){
242 0         0 return undef;
243             }
244              
245 5 100 100     68 if (
246             ( ! defined( $conn ) ) ||
247             ( ref( $conn ) ne 'Net::Connection' )
248             ){
249 2         5 $self->{error}=2;
250 2         4 $self->{errorString}='Either the connection is undefined or is not a Net::Connection object';
251 2 50       5 if ( ! $self->{testing} ){
252 0         0 $self->warn;
253             }
254 2         6 return undef;
255             }
256              
257             # Stores the number of hits
258 3         6 my $hits=0;
259 3         6 my $required=0;
260 3         5 foreach my $check ( @{ $self->{checks} } ){
  3         8  
261 4         7 my $hit;
262 4         7 eval{
263 4         13 $hit=$check->{check}->match($conn);
264             };
265              
266             # If $hits is undef, then one of the checks errored and we skip processing the results.
267             # Should only be 0 or 1.
268 4 50       10 if ( defined( $hit ) ){
269             # invert if needed
270 4 50       21 if ( $check->{invert} ){
271 0         0 $hit = $hit ^ 1;
272             }
273              
274             # increment the hits count if we hit
275 4 100       8 if ( $hit ){
276 3         6 $hits++;
277             }
278             }
279              
280 4         7 $required++;
281             }
282              
283             # if these are the same, then we have a match
284 3 100       10 if ( $required eq $hits ){
285 2         6 return 1;
286             }
287              
288             # If we get here, it is not a match
289 1         3 return 0;
290             }
291              
292             =head1 ERROR HANDLING / FLAGS
293              
294             Error handling is provided by L.
295              
296             =head2 2 / notNCobj
297              
298             Not a Net::Connection object. Either is is not defined
299             or what is being passed is not a Net::Connection object.
300              
301             =head1 AUTHOR
302              
303             Zane C. Bowers-Hadley, C<< >>
304              
305             =head1 BUGS
306              
307             Please report any bugs or feature requests to C, or through
308             the web interface at L. I will be notified, and then you'll
309             automatically be notified of progress on your bug as I make changes.
310              
311              
312              
313              
314             =head1 SUPPORT
315              
316             You can find documentation for this module with the perldoc command.
317              
318             perldoc Net::Connection::Match
319              
320              
321             You can also look for information at:
322              
323             =over 4
324              
325             =item * RT: CPAN's request tracker (report bugs here)
326              
327             L
328              
329             =item * AnnoCPAN: Annotated CPAN documentation
330              
331             L
332              
333             =item * CPAN Ratings
334              
335             L
336              
337             =item * Search CPAN
338              
339             L
340              
341             =item * Git Repo
342              
343             L
344              
345             =back
346              
347              
348             =head1 ACKNOWLEDGEMENTS
349              
350              
351             =head1 LICENSE AND COPYRIGHT
352              
353             Copyright 2019 Zane C. Bowers-Hadley.
354              
355             This program is free software; you can redistribute it and/or modify it
356             under the terms of the the Artistic License (2.0). You may obtain a
357             copy of the full license at:
358              
359             L
360              
361             Any use, modification, and distribution of the Standard or Modified
362             Versions is governed by this Artistic License. By using, modifying or
363             distributing the Package, you accept this license. Do not use, modify,
364             or distribute the Package, if you do not accept this license.
365              
366             If your Modified Version has been derived from a Modified Version made
367             by someone other than you, you are nevertheless required to ensure that
368             your Modified Version complies with the requirements of this license.
369              
370             This license does not grant you the right to use any trademark, service
371             mark, tradename, or logo of the Copyright Holder.
372              
373             This license includes the non-exclusive, worldwide, free-of-charge
374             patent license to make, have made, use, offer to sell, sell, import and
375             otherwise transfer the Package with respect to any patent claims
376             licensable by the Copyright Holder that are necessarily infringed by the
377             Package. If you institute patent litigation (including a cross-claim or
378             counterclaim) against any party alleging that the Package constitutes
379             direct or contributory patent infringement, then this Artistic License
380             to you shall terminate on the date that such litigation is filed.
381              
382             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
383             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
384             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
385             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
386             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
387             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
388             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
389             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
390              
391              
392             =cut
393              
394             1; # End of Net::Connection::Match