File Coverage

blib/lib/Net/ACL/Rule.pm
Criterion Covered Total %
statement 92 107 85.9
branch 33 50 66.0
condition 4 9 44.4
subroutine 24 28 85.7
pod 12 18 66.6
total 165 212 77.8


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             # $Id: Rule.pm,v 1.19 2003/06/06 18:45:02 unimlo Exp $
4              
5             package Net::ACL::Rule;
6              
7 9     9   181232 use strict;
  9         20  
  9         365  
8 9     9   823 use Exporter;
  9         19  
  9         441  
9 9         1044 use vars qw(
10             $VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS
11 9     9   668 @ACL_RC @ACL_ACTION );
  9         18  
12              
13             ## Inheritance and Versioning ##
14              
15             @ISA = qw( Exporter );
16             $VERSION = '0.07';
17              
18             ## Module Imports ##
19              
20 9     9   656 use Carp;
  9         17  
  9         652  
21 8     8   47 use Scalar::Util qw( blessed );
  8         17  
  8         13917  
22              
23             ## Accesslist Return Codes Constants ##
24              
25 108     108 0 2008 sub ACL_NOMATCH { 0; };
26 81     81 0 1469 sub ACL_MATCH { 1; };
27              
28             ## Accesslist Action Codes Constants ##
29              
30 40     40 0 676 sub ACL_DENY { 2; };
31 122     122 0 1559 sub ACL_PERMIT { 3; };
32 88     88 0 958 sub ACL_CONTINUE { 4; };
33              
34             ## Export Tag Definitions ##
35              
36             @ACL_RC = qw( ACL_MATCH ACL_NOMATCH );
37             @ACL_ACTION = qw( ACL_PERMIT ACL_DENY ACL_CONTINUE );
38             @EXPORT = ();
39             @EXPORT_OK = ( @ACL_RC, @ACL_ACTION );
40             %EXPORT_TAGS = (
41             rc => [ @ACL_RC ],
42             action => [ @ACL_ACTION ],
43             ALL => [ @EXPORT, @EXPORT_OK ]
44             );
45              
46             ## Public Class Methods ##
47              
48             sub new
49             {
50 36     36 1 690 my $proto = shift;
51 36   33     188 my $class = ref $proto || $proto;
52              
53 36         78 my $this = {
54             _action => ACL_PERMIT,
55             _match => [],
56             _set => [],
57             _seq => undef
58             };
59              
60 36         119 bless($this, $class);
61              
62 36         105 while ( defined(my $arg = shift) )
63             {
64 46         59 my $value = shift;
65 46 100       187 if ( $arg =~ /action/i )
    100          
    100          
    50          
66             {
67 35 100       119 $value = ACL_PERMIT if $value =~ /permit/i;
68 35 100       97 $value = ACL_DENY if $value =~ /deny/i;
69 35         185 $this->{_action} = $value;
70             }
71             elsif ( $arg =~ /seq/i )
72             {
73 4         17 $this->{_seq} = $value;
74             }
75             elsif ( $arg =~ /match/i )
76             {
77 6         19 $this->_handlerules('Match','_match',$value);
78             }
79             elsif ( $arg =~ /set/i )
80             {
81 1         4 $this->_handlerules('Set','_set',$value);
82             }
83             else
84             {
85 0         0 croak "Unrecognized argument $arg";
86             };
87             };
88              
89 36         103 return $this;
90             }
91              
92             sub clone
93             {
94 7     7 1 54 my $proto = shift;
95 7   33     20 my $class = ref $proto || $proto;
96 7 50       26 $proto = shift unless ref $proto;
97              
98 7         7 my $clone;
99              
100 7         32 $clone->{_action} = $proto->{_action};
101 7         13 $clone->{_seq} = $proto->{_seq};
102              
103 7         13 foreach my $key (qw(_set _match ))
104             {
105             # $clone->{$key} = [ map { $_->clone; } @{$proto->{$key}} ]; # Can't clone!
106 14         17 $clone->{$key} = [ @{$proto->{$key}} ];
  14         42  
107             }
108              
109 7         43 return ( bless($clone, $class) );
110             }
111              
112             ## Public Object Methods ##
113              
114             sub seq
115             {
116 24     24 0 28 my $this = shift;
117 24 50       58 $this->{_seq} = @_ ? shift : $this->{_seq};
118 24         137 return $this->{_seq};
119             }
120              
121             sub action
122             {
123 56     56 1 84 my $this = shift;
124 56 50       155 $this->{_action} = @_ ? shift : $this->{_action};
125 56         231 return $this->{_action};
126             }
127              
128             sub action_str
129             {
130 28     28 1 38 my $this = shift;
131 28 0       62 $this->{_action} = @_ ? (shift =~ /permit/i ? ACL_PERMIT : ACL_DENY) : $this->{_action};
    50          
132 28 100       59 return (($this->{_action} == ACL_PERMIT) ? 'permit' : 'deny');
133             }
134              
135             sub match
136             {
137 37     37 1 52 my $this = shift;
138 37         100 return $this->_match(@_); # To allow replacement of match which doesn't effect query()
139             }
140              
141             sub set
142             {
143 10     10 1 13 my $this = shift;
144 10         17 foreach my $subrule (@{$this->{_set}})
  10         56  
145             {
146 3         15 @_ = $subrule->set(@_);
147             };
148 10         61 return @_;
149             }
150              
151             sub query
152             {
153 30     30 1 42 my $this = shift;
154 30 100       65 return (ACL_CONTINUE,@_) unless $this->_match(@_);
155 10 50       25 return ($this->{_action},($this->{_action} == ACL_DENY) ? undef : $this->set(@_));
156             }
157              
158             sub add_match
159             {
160 35     35 1 115 shift->_add('_match',@_);
161             }
162              
163             sub remove_match
164             {
165 0     0 1 0 shift->_remove('_match',@_);
166             };
167              
168             sub add_set
169             {
170 0     0 1 0 shift->_add('_set',@_);
171             }
172              
173             sub remove_set
174             {
175 0     0 1 0 shift->_remove('_set',@_);
176             };
177              
178             sub autoconstruction
179             {
180 40     40 1 94 my ($this,$type,$class,$arg,@value) = @_;
181 40 50       90 $class = 'Net::ACL::' . $type . '::' . $arg unless defined $class;
182 40 100       256 unless ($class->isa('Net::ACL::'.$type))
183             {
184 6     2   500 eval "use $class;";
  2         1521  
  2         7  
  2         82  
185 6 50       31 croak "Unknown $type rule key $arg - No class $class found (Value: @value)." if ($@ =~ /Can't locate/);
186 6 50       16 croak $@ if ($@);
187 6 50       65 croak "$class is not a Net::ACL::$type class"
188             unless $class->isa('Net::ACL::'.$type)
189             };
190 40         156 return $class->new(@value);
191             }
192              
193             ## Private Object Methods ##
194              
195             sub _match
196             {
197 67     67   91 my $this = shift;
198 67         75 foreach my $subrule (@{$this->{_match}})
  67         151  
199             {
200 66 100       199 return ACL_NOMATCH unless $subrule->match(@_);
201             };
202 29         65 return ACL_MATCH;
203             }
204              
205             sub _add
206             {
207 42     42   52 my $this = shift;
208 42         53 my $key = shift;
209 42         47 push(@{$this->{$key}},@_);
  42         167  
210             }
211              
212             sub _remove
213             {
214 0     0   0 my $this = shift;
215 0         0 my $key = shift;
216 0         0 my @arg = @_;
217 0         0 @{$this->{$key}} = grep {
218 0 0       0 foreach my $arg (@arg) { $_ = undef if $arg == $_; };
  0         0  
  0         0  
219 0         0 } @{$this->{$key}};
220             }
221              
222             sub _handlerules
223             {
224 7     7   15 my ($this,$type,$key,$value) = @_;
225 7 50       22 croak "$type option can not be a SCALAR" unless ref $value;
226 7 100 66     69 if ((blessed $value) && $value->isa('Net::ACL::' . $type))
    50          
    50          
227             {
228 2         8 $this->_add($key,$value);
229             }
230             elsif (ref $value eq 'ARRAY')
231             {
232 0         0 $this->_add($key,@{$value});
  0         0  
233             }
234             elsif (ref $value eq 'HASH')
235             {
236 5         6 foreach my $arg (keys %{$value})
  5         16  
237             {
238 5         11 my $subclass = 'Net::ACL::' . $type . '::' . $arg;
239 5         15 $this->_add($key,$this->autoconstruction($type,$subclass,$arg,$value->{$arg}));
240             };
241             }
242             else
243             {
244 0         0 croak "Unknown $type option value type";
245             };
246             }
247              
248             ## POD ##
249              
250             =pod
251              
252             =head1 NAME
253              
254             Net::ACL::Rule - Class representing a generic access-list/route-map entry
255              
256             =head1 SYNOPSIS
257              
258             use Net::ACL::Rule qw( :action :rc );
259              
260             # Constructor
261             $entry = new Net::ACL::Rule(
262             Action => ACL_PERMIT
263             Match => {
264             IP => '127.0.0.0/8'
265             }
266             Set => {
267             IP => '127.0.0.1'
268             },
269             Seq => 10
270             );
271              
272             # Object Copy
273             $clone = $entry->clone();
274              
275             # Accessor Methods
276             $action = $entry->action($action);
277             $action_str = $entry->action($action_str);
278              
279             $entry->add_match($matchrule);
280             $entry->remove_match($matchrule);
281             $entry->add_set($setrule);
282             $entry->remove_set($setrule);
283              
284             $rc = $entry->match(@data);
285             @data = $entry->set(@data);
286              
287             ($rc,@data) = $entry->query(@data);
288              
289             $subrule = $entry->autoconstruction($type,$class,$arg,@values);
290              
291             =head1 DESCRIPTION
292              
293             This module represents a single generic access-list and route-map entry. It is
294             used by the L object. It can match any data against a
295             list of L objects, and if all are matched, it
296             can have a list of L objects modify the data.
297              
298             =head1 CONSTRUCTOR
299              
300             =over 4
301              
302             =item new() - create a new Net::ACL::Rule object
303              
304             $entry = new Net::ACL::Rule(
305             Action => ACL_PERMIT
306             Match => {
307             IP => '127.0.0.0/8'
308             }
309             Set => {
310             IP => '127.0.0.1'
311             }
312             );
313              
314             This is the constructor for Net::ACL::Rule objects. It returns a
315             reference to the newly created object. The following named parameters may
316             be passed to the constructor.
317              
318             =over 4
319              
320             =item Action
321              
322             The action parameter could be either of the constants exported using "action"
323             (See EXPORTS) or just a string matching permit or deny. ACL_PERMIT accepts
324             the data, ACL_DENY drops the data, while ACL_CONTINUE is used to indicate that
325             this entry might change the data, but does not decide whether the data should
326             be accepted or droped.
327              
328             =item Match
329              
330             The match parameter can have multiple forms, and my exists zero, one or more
331             times. The following forms are allowed:
332              
333             =over 4
334              
335             =item Match object - A Net::ACL::Match object (or ancestor)
336              
337             =item List - A list of Net::ACL::Match objects (or ancestors)
338              
339             =item Hash - A hash reference. The constructor will for each key/value-pair
340             call the autoconstructor() method and add the returned objects to the
341             rule-set.
342              
343             =back
344              
345             =item Set
346              
347             The set parameter are in syntax just like the C parameter, except
348             it uses Net::ACL::Set objects.
349              
350             =back
351              
352             =back
353              
354             =head1 OBJECT COPY
355              
356             =over 4
357              
358             =item clone() - clone a Net::ACL::Rule object
359              
360             $clone = $entry->clone();
361              
362             This method creates an exact copy of the Net::ACL::Rule object,
363             with set, match and action attributes.
364              
365             =back
366              
367             =head1 ACCESSOR METHODS
368              
369             =over 4
370              
371             =item action()
372              
373             This method returns the entry's action value. If called with an argument,
374             the action value is changed to that argument.
375              
376             =item action_str()
377              
378             This method returns the entry's action string as either C or C.
379             If called with an argument, the action value are changed to ACL_PERMIT if
380             the argument matches /permit/i - otherwise ACL_DENY.
381              
382             =item add_match()
383              
384             =item remove_match()
385              
386             =item add_set()
387              
388             =item remove_set()
389              
390             The methods add and remove match and set rules. Each argument should be a
391             match or set rule object. New rules are added in the end of the rule set.
392              
393             =item match()
394              
395             The match method gets any arbitrary number of arguments. The arguments are passed
396             to the match() method of each of the Net::ACL::Match objects,
397             given at construction time - see new(). If all Match objects did
398             match, the method returns ACL_MATCH. Otherwise ACL_MATCH.
399              
400             =item set()
401              
402             The set method gets any arbitrary number of arguments. The arguments are passed
403             to the first of the Net::ACL::Set objects set() method. The
404             result of this function is then used to call the next. This is repeated for
405             all Set objects given at construction time - see new().
406             Finally the result of the last call is returned.
407              
408             =item query()
409              
410             The query method first attempt to match it's arguments with the match()
411             method. If this fails, it returns ACL_CONTINUE. Otherwise it uses
412             the set() method to potentially alter the arguments before they are returned
413             with C given on construction prefixed.
414              
415             =item autoconstruction()
416              
417             This method is used on construction to construct rules based on
418             key/value-pairs in a Rule argument hash reference.
419              
420             The first argument is the type (C or C). The second is the class
421             name (see below). The third is the key name from the construction hash. The
422             forth and any remaining arguments are used as parameters to the constructor.
423              
424             The return value will be the result of:
425              
426             $class->new(@values);
427              
428             The class is by the constructor set as C
429              
430             B: Do to this; the keys of the hash are case-sensitive!
431              
432             By replacing this function in a sub-class, it is possible to modify the class
433             and/or key-value pairs and hence make more complex constructions from simple
434             key-value pairs, or have more user-friendly key values (e.g. make them
435             case-insensitive).
436              
437             =back
438              
439             =head1 EXPORTS
440              
441             The module exports the following symbols according to the rules and
442             conventions of the Exporter module.
443              
444             =over 4
445              
446             =item :rc
447              
448             ACL_MATCH, ACL_NOMATCH
449              
450             =item :action
451              
452             ACL_PERMIT, ACL_DENY, ACL_CONTINUE
453              
454             =back
455              
456             =head1 SEE ALSO
457              
458             Net::ACL, Net::ACL::Set, Net::ACL::Match
459              
460             =head1 AUTHOR
461              
462             Martin Lorensen
463              
464             =cut
465              
466             ## End Package Net::ACL::Rule ##
467            
468             1;