File Coverage

blib/lib/Net/ACL.pm
Criterion Covered Total %
statement 110 129 85.2
branch 46 58 79.3
condition 47 78 60.2
subroutine 14 16 87.5
pod 9 10 90.0
total 226 291 77.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             # $Id: ACL.pm,v 1.17 2003/06/06 18:45:02 unimlo Exp $
4              
5             package Net::ACL;
6              
7 4     4   31427 use strict;
  4         8  
  4         169  
8 4     4   23 use vars qw( $VERSION @ISA );
  4         6  
  4         313  
9              
10             ## Inheritance and Versioning ##
11              
12             @ISA = qw( Exporter );
13             $VERSION = '0.07';
14              
15             ## Module Imports ##
16              
17 4     4   22 use Carp;
  4         7  
  4         399  
18 4     4   21 use Net::ACL::Rule qw( :action );
  4         9  
  4         629  
19 4     4   26 use Scalar::Util qw( weaken blessed );
  4         7  
  4         6516  
20              
21             ## Global Private Variables ##
22              
23             my %knownlists;
24              
25             ## Public Class Methods ##
26              
27             sub new
28             {
29 24   50 24 1 1326 my $proto = shift || __PACKAGE__;
30 24   33     85 my $class = ref $proto || $proto;
31              
32 24 50       88 my $this = ref $proto ? $proto : bless( {}, $class );
33              
34 24         100 $this->{_name} = undef;
35 24         41 $this->{_type} = undef;
36 24         54 $this->{_rules} = [];
37              
38 24         77 while ( defined(my $arg = shift) )
39             {
40 12         17 my $value = shift;
41 12 100       64 if ( $arg =~ /name/i )
    100          
    50          
42             {
43 4         13 $this->{_name} = $value;
44             }
45             elsif ( $arg =~ /type/i )
46             {
47 4         15 $this->{_type} = $value;
48             }
49             elsif ( $arg =~ /rule/i )
50             {
51 4 50       15 croak "Rule option can not be a SCALAR" unless ref $value;
52 4 100 66     50 if ((blessed $value) && $value->isa('Net::ACL::Rule'))
    50          
    50          
53             {
54 2         3 push(@{$this->{_rules}},$value);
  2         11  
55             }
56             elsif (ref $value eq 'ARRAY')
57             {
58 0         0 push(@{$this->{_rules}},@{$value});
  0         0  
  0         0  
59             }
60             elsif (ref $value eq 'HASH')
61             {
62 2         2 push(@{$this->{_rules}},@{$value}{sort { $a <=> $b } keys %{$value}});
  2         5  
  2         10  
  7         14  
  2         9  
63             }
64             else
65             {
66 0         0 croak "Unknown rule option value type";
67             };
68             }
69             else
70             {
71 0         0 croak "Unrecognized argument $arg";
72             };
73             };
74              
75 24 50 33     105 croak 'Two access-lists with same (type,name) identification are not allowed!'
      66        
76             if defined $this->{_name} && defined $knownlists{$this->{_type} || $class}->{$this->{_name}};
77 24         108 weaken($knownlists{_hash}->{$this} = $this);
78 24 100 33     78 weaken($knownlists{$this->{_type} || $class}->{$this->{_name}} = $this)
79             if defined $this->{_name};
80              
81 24         82 return $this;
82             }
83              
84             sub renew
85             {
86 16     16 1 863 my $proto = shift;
87 16   33     85 my $class = ref $proto || $proto;
88 16         70 my ($name,$type) = (undef,$class);
89              
90 16         53 while ( defined(my $arg = shift) )
91             {
92 30         43 my $value = shift;
93 30 100       133 if ( $arg =~ /name/i )
    100          
94             {
95 15         57 $name = $value;
96             }
97             elsif ( $arg =~ /type/i )
98             {
99 14         49 $type = $value;
100             }
101             else
102             {
103 1         5 return $knownlists{_hash}->{$arg};
104             };
105             };
106 15         59 return $knownlists{$type}->{$name};
107             }
108              
109             sub clone
110             {
111 3     3 1 764 my $proto = shift;
112 3   66     16 my $class = ref $proto || $proto;
113 3 100       10 $proto = shift unless ref $proto;
114              
115 3         4 my $clone;
116 3         8 $clone->{_name} = undef; # Not the same name!
117 3         9 $clone->{_type} = $proto->{_type}; # Still same type!
118              
119 3         13 $clone->{_rules} = [ map { $_->clone; } @{$proto->{_rules}} ];
  7         27  
  3         8  
120              
121 3         8 bless($clone, $class);
122              
123 3         23 weaken($knownlists{_hash}->{$clone} = $clone);
124              
125 3         10 return $clone;
126             }
127              
128             sub knownlists
129             {
130 0     0 0 0 my $proto = shift;
131 0   0     0 my $class = ref $proto || $proto;
132 0         0 my %res;
133 0         0 foreach my $key (keys %knownlists)
134             {
135 0         0 $res{$key} = [ keys %{$knownlists{$key}} ];
  0         0  
136             };
137 0         0 return \%res;
138             }
139              
140             sub DESTROY
141             {
142 27     27   12646 my $this = shift;
143 27         73 $this->name(undef);
144 27         68 $this->type(undef);
145 27         930 delete $knownlists{_hash}->{$this};
146             }
147              
148             ## Public Object Methods ##
149              
150             sub name
151             {
152 188     188 1 1781 my $this = shift;
153 188         253 my $class = ref $this;
154              
155 188 100       376 if (@_)
156             {
157 74         92 my $newname = shift;
158              
159 74 100 100     669 return $this->{_name} # Don't do anything if name not changed!
      100        
      100        
160             unless (defined $newname || defined $this->{_name})
161             && ! (defined $newname && defined $this->{_name} && $newname eq $this->{_name});
162              
163 60 50 0     288 croak 'Two access-lists with same (type,name) = (' .
      66        
      66        
164             ($this->{_type} || $class) . ',' . $newname . ') identification are not allowed!'
165             if defined $newname
166             && defined $knownlists{$this->{_type} || $class}->{$newname};
167              
168             # Change name!
169 60 100 66     255 delete $knownlists{$this->{_type} || $class}->{$this->{_name}} if defined $this->{_name};
170 60         90 $this->{_name} = $newname;
171 60 100 66     291 weaken($knownlists{$this->{_type} || $class}->{$this->{_name}} = $this)
172             if defined $this->{_name};
173             };
174              
175 174         730 return $this->{_name};
176             }
177              
178             sub type
179             {
180 127     127 1 182 my $this = shift;
181 127         165 my $class = ref $this;
182              
183 127 100       259 if (@_)
184             {
185 48         63 my $newtype = shift;
186 48 100 100     539 return $this->{_type} # Don't do anything if type hasn't changed!
      66        
      66        
187             unless (defined $newtype || defined $this->{_type})
188             && ! (defined $newtype && defined $this->{_type} && $newtype eq $this->{_type});
189              
190 46 50 0     221 croak 'Two access-lists with same (type,name) = (' .
      66        
      66        
191             ($this->{_type} || $class) . ',' . $this->{_name} . ') identification are not allowed!'
192             if defined $this->{_name}
193             && $knownlists{$newtype || $class}->{$this->{_name}};
194 46 100 66     174 delete $knownlists{$this->{_type} || $class}->{$this->{_name}}
195             if defined $this->{_name};
196 46         73 $this->{_type} = $newtype;
197 46 100 66     189 weaken($knownlists{$this->{_type} || $class}->{$this->{_name}} = $this)
198             if defined $this->{_name};
199             };
200              
201 125         387 return $this->{_type};
202             }
203              
204             sub add_rule
205             {
206 29     29 1 39 my $this = shift;
207 29         34 push(@{$this->{_rules}},@_);
  29         65  
208 29   100     35 $this->{_rules} = [ sort { ($a->seq || 0) <=> ($b->seq || 0) } @{$this->{_rules}} ];
  10   100     49  
  29         116  
209             }
210              
211             sub remove_rule
212             {
213 0     0 1 0 my $this = shift;
214 0         0 my @arg = @_;
215 0         0 @{$this->{_rules}} = grep {
216 0 0       0 foreach my $arg (@arg) { $_ = undef if $arg == $_; };
  0         0  
  0         0  
217 0         0 } @{$this->{_rules}};
218             }
219              
220             sub match
221             {
222 29     29 1 398 my $this = shift;
223 29         55 my @data = @_;
224 29 100       37 return ACL_PERMIT unless scalar @{$this->{_rules}}; # No rules!
  29         101  
225 28         43 foreach my $rule (@{$this->{_rules}})
  28         64  
226             {
227 37 50       125 next if $rule->action == ACL_CONTINUE;
228 37 100       124 return $rule->action if $rule->match(@data);
229             };
230 9         32 return ACL_DENY; # No match - implicit deny!
231             }
232              
233             sub query
234             {
235 11     11 1 20 my $this = shift;
236 11         25 my @data = @_;
237 11 50       14 return (ACL_PERMIT,undef) unless scalar @{$this->{_rules}}; # No rules! Implicit permit
  11         43  
238 11         16 foreach my $rule (@{$this->{_rules}})
  11         29  
239             {
240 30         31 my $rc;
241 30         112 ($rc,@data) = $rule->query(@data);
242 30 100       95 return ($rc,@data) unless $rc == ACL_CONTINUE;
243             };
244 4         38 return (ACL_DENY,undef); # No match - implicit deny!
245             }
246              
247             ## POD ##
248              
249             =pod
250              
251             =head1 NAME
252              
253             Net::ACL - Class representing a generic access-list/route-map
254              
255             =head1 SYNOPSIS
256              
257             use Net::ACL;
258             use Net::ACL::Rule qw( :action :rc );
259              
260             # Constructor
261             $list = new Net::ACL(
262             Name => 'MyACL',
263             Type => 'prefix-list',
264             Rule => new Net::ACL::Rule( .. )
265             );
266              
267             # Fetch existing object by name
268             $list = renew Net::ACL(
269             Name => 'MyACL'
270             Type => 'prefix-list'
271             );
272             $list = renew Net::ACL("$list");
273              
274             # Object Copy
275             $clone = $list->clone();
276              
277             # Class methods
278             $type_names_hr = Net::ACL->knownlists();
279              
280             # Accessor Methods
281             $list->add_rule($rule);
282             $list->remove_rule($rule);
283             $name = $list->name($name);
284             $type = $list->type($type);
285             $rc = $list->match(@data);
286             ($rc,@data) = $list->query(@data);
287              
288             =head1 DESCRIPTION
289              
290             This module represents a generic access-list and route-map. It uses the
291             L object to represent the rules.
292              
293             =head1 CONSTRUCTOR
294              
295             =over 4
296              
297             =item new() - create a new Net::ACL object
298              
299             $list = new Net::ACL(
300             Name => 'MyACL',
301             Type => 'prefix-list',
302             Rule => new Net::ACL::Rule( .. )
303             );
304              
305             This is the constructor for Net::ACL objects. It returns a
306             reference to the newly created object. The following named parameters may
307             be passed to the constructor.
308              
309             =over 4
310              
311             =item Name
312              
313             The name parameter is optional and is only used to identify a list by the
314             renew() constructor.
315              
316             =item Type
317              
318             The type parameter is optional and defaults to the class name. It is used
319             have different namespaces for the Name parameter. It is intended to have
320             values like 'ip-accesslist', 'prefix-list', 'as-path-filter' and 'route-map'.
321             This way the same name or number of an access-list could be reused in each
322             class.
323              
324             =item Rule
325              
326             The rule parameter could be present one or more times. Each one can have
327             multiple types:
328              
329             =over 4
330              
331             =item Net::ACL::Rule
332              
333             A Net::ACL::Rule object.
334              
335             =item ARRAY
336              
337             An array reference of Net::ACL::Rule objects.
338              
339             =item HASH
340              
341             A hash reference with Net::ACL:Rule objects as values. Keys are
342             currently ignored, but might later be used as sequance numbers or labels.
343              
344             =back
345              
346             =back
347              
348             =item renew() - fetch an existing Net::ACL object
349              
350             $list = renew Net::ACL(
351             Name => 'MyACL'
352             Type => 'prefix-list'
353             );
354             $list = renew Net::ACL("$list");
355              
356             The renew constructor localizes an existing ACL object from either
357             Name, (Name,Type)-pair or the object in string context (e.g.
358             C). The Name and Type arguments
359             have similar meaning as for the new() constructor.
360              
361             =back
362              
363             =head1 OBJECT COPY
364              
365             =over 4
366              
367             =item clone() - clone a Net::ACL object
368              
369             $clone = $list->clone();
370              
371             This method creates an exact copy of the Net::ACL object and all
372             the rules. The clone will not have a name unless one is assigned explicitly
373             later.
374              
375             =back
376              
377             =head1 ACCESSOR METHODS
378              
379             =over 4
380              
381             =item name()
382              
383             =item type()
384              
385             The name() and type() methods return the access-list name and type fields
386             respectively. If called with an argument they change the value to that of the
387             argument.
388              
389             =item match()
390              
391             The match method implements the basics of a standard router access-list
392             matching.
393              
394             It gets any arbitrary number of arguments. The arguments are passed
395             to the match() method of each of the Net::ACL::Rule rules
396             except any object which have the action() field set to C.
397             When a match() method returns C, the action() of that
398             entry is returned.
399              
400             =item query()
401              
402             The query method implements the basics of a route-map execution.
403              
404             It calls the Net::ACL::Rule rules query() method
405             one by one as long as they return C.
406              
407             The function returns the result code (C or C)
408             and the, possibly modified, arguments of the function.
409              
410             =item add_rule()
411              
412             =item remove_rule()
413              
414             The add() and remove() rule methods can add and remove rules after object
415             construction.
416              
417             =back
418              
419             =head1 SEE ALSO
420              
421             Net::ACL::Rule, Net::ACL::File, Net::ACL::Bootstrap
422              
423             =head1 AUTHOR
424              
425             Martin Lorensen
426              
427             =cut
428              
429             ## End Package Net::ACL ##
430            
431             1;