File Coverage

blib/lib/Farly/ASA/Annotator.pm
Criterion Covered Total %
statement 107 113 94.6
branch 30 48 62.5
condition n/a
subroutine 26 28 92.8
pod 0 16 0.0
total 163 205 79.5


line stmt bran cond sub pod time code
1             package Farly::ASA::Annotator;
2            
3 9     9   1511 use 5.008008;
  9         37  
  9         367  
4 9     9   55 use strict;
  9         21  
  9         294  
5 9     9   188 use warnings;
  9         19  
  9         287  
6 9     9   55 use Carp;
  9         22  
  9         763  
7 9     9   55 use Scalar::Util qw(blessed);
  9         21  
  9         838  
8 9     9   53 use Log::Any qw($log);
  9         19  
  9         85  
9 9     9   6288 use Farly::ASA::PortFormatter;
  9         139  
  9         294  
10 9     9   5437 use Farly::ASA::ProtocolFormatter;
  9         30  
  9         302  
11 9     9   5357 use Farly::ASA::ICMPFormatter;
  9         25  
  9         22280  
12            
13             our $VERSION = '0.26';
14             our $AUTOLOAD;
15            
16             #each token type maps to a class
17             our $Token_Class_Map = {
18             'STRING' => 'Farly::Value::String',
19             'DIGIT' => 'Farly::Value::Integer',
20             'NAME' => 'Farly::Value::String', #method replaces name with IP
21             'NAME_ID' => 'Farly::Value::String', #this is just the name string
22             'IF_REF' => 'Farly::Object::Ref',
23             'OBJECT_REF' => 'Farly::Object::Ref',
24             'GROUP_REF' => 'Farly::Object::Ref',
25             'RULE_REF' => 'Farly::Object::Ref',
26             'GROUP_TYPE' => 'Farly::Value::String',
27             'OBJECT_ENTRY' => 'Farly::Value::String',
28             'OBJECT_TYPE' => 'Farly::Value::String',
29             'ANY' => 'Farly::IPv4::Network', #method ANY = '0.0.0.0 0.0.0.0'
30             'IPADDRESS' => 'Farly::IPv4::Address',
31             'MASK' => 'Farly::IPv4::Address',
32             'IPNETWORK' => 'Farly::IPv4::Network',
33             'IPRANGE' => 'Farly::IPv4::Range',
34             'NAMED_NET' => 'Farly::Value::String', #method replaces name with IP
35             'PROTOCOL' => 'Farly::Transport::Protocol',
36             'GROUP_PROTOCOL' => 'Farly::Value::String', #not ::Protocol because of 'tcp-udp'
37             'ICMP_TYPE' => 'Farly::IPv4::ICMPType', #method maps string to int
38             'PORT_ID' => 'Farly::Transport::Port', #method maps string to int
39             'PORT_RANGE' => 'Farly::Transport::PortRange', #method maps string to int
40             'PORT_GT' => 'Farly::Transport::PortGT', #method maps string to int
41             'PORT_LT' => 'Farly::Transport::PortLT', #method maps string to int
42             'ACTIONS' => 'Farly::Value::String',
43             'ACL_TYPES' => 'Farly::Value::String',
44             'REMARKS' => 'Farly::Value::String',
45             'ACL_DIRECTION' => 'Farly::Value::String',
46             'ACL_GLOBAL' => 'Farly::Value::String',
47             'STATE' => 'Farly::Value::String',
48             'ACL_STATUS' => 'Farly::Value::String',
49             'LOG_LEVEL' => 'Farly::Value::String',
50             'DEFAULT_ROUTE' => 'Farly::IPv4::Network', #method DEFAULT_ROUTE sets '0.0.0.0 0.0.0.0'
51             'TUNNELED' => 'Farly::Value::String'
52             };
53            
54             # 'ENTRY' is like a namespace in which an ID must be unique
55             # A _REF refers to a Farly::Object by ENTRY and ID
56             our $Entry_Map = {
57             'IF_REF' => 'INTERFACE',
58             'OBJECT_REF' => 'OBJECT',
59             'GROUP_REF' => 'GROUP',
60             'RULE_REF' => 'RULE',
61             };
62            
63             sub new {
64 7     7 0 56 my ($class) = @_;
65            
66 7         88 my $self = {
67             NAMES => {}, #name to address 'symbol table'
68             PORT_FMT => Farly::ASA::PortFormatter->new(),
69             PROTOCOL_FMT => Farly::ASA::ProtocolFormatter->new(),
70             ICMP_FMT => Farly::ASA::ICMPFormatter->new()
71             };
72 7         27 bless $self, $class;
73            
74 7         96 $log->info("$self new");
75            
76 7         39 return $self;
77             }
78            
79             sub port_formatter {
80 120     120 0 855 return $_[0]->{PORT_FMT};
81             }
82            
83             sub protocol_formatter {
84 321     321 0 1554 return $_[0]->{PROTOCOL_FMT};
85             }
86            
87             sub icmp_formatter {
88 40     40 0 218 return $_[0]->{ICMP_FMT};
89             }
90            
91             sub visit {
92 330     330 0 648 my ( $self, $node ) = @_;
93            
94             # set s of explored vertices
95 330         546 my %seen;
96            
97             #stack is all neighbors of s
98             my @stack;
99 330         650 push @stack, $node;
100            
101             #my $key;
102            
103 330         1054 while (@stack) {
104            
105 4308         5570 $node = pop @stack;
106            
107 4308 50       15544 next if ( $seen{$node}++ );
108            
109             #visit this node if its a token
110 4308 100       9251 if ( exists( $node->{'__VALUE__'} ) ) {
111 1663         2267 my $method = ref($node);
112 1663         7608 $self->$method($node);
113 1663         4735 next;
114             }
115            
116             # add name info the the names "symbol table"
117 2645 100       14127 if ( $node->isa('named_ip') ) {
118 12         62 $self->named_ip($node);
119             }
120            
121             # continue walking the parse tree
122 2645         6923 foreach my $key ( keys %$node ) {
123            
124 7976 100       13979 next if ( $key eq 'EOL' );
125            
126 7568         9852 my $next = $node->{$key};
127            
128 7568 100       22499 if ( blessed($next) ) {
129            
130 3978         9547 push @stack, $next;
131             }
132             }
133             }
134 330         1781 return 1;
135             }
136            
137             sub named_ip {
138 12     12 0 33 my ( $self, $node ) = @_;
139            
140 12 50       62 my $name = $node->{name}->{NAME_ID}->{__VALUE__}
141             or confess "$self error: name not found for ", ref($node);
142            
143 12 50       50 my $ip = $node->{IPADDRESS}->{__VALUE__}
144             or confess "$self error: IP address not found for ", ref($node);
145            
146 12         268 $log->debug("name = $name : ip = $ip");
147            
148 12         70 $self->{NAMES}->{$name} = $ip;
149             }
150            
151             sub NAME {
152 26     26 0 70 my ( $self, $node ) = @_;
153            
154 26 50       131 my $name = $node->{'__VALUE__'}
155             or confess "$self error: __VALUE__ not found for name";
156            
157 26 50       152 my $ip = $self->{NAMES}->{$name}
158             or confess "$self error: IP address not found for name $name";
159            
160 26         190 $node->{'__VALUE__'} = Farly::IPv4::Address->new($ip);
161             }
162            
163             sub NAMED_NET {
164 6     6 0 18 my ( $self, $node ) = @_;
165            
166 6 50       34 my $named_net = $node->{'__VALUE__'}
167             or confess "$self error: __VALUE__ not found for name";
168            
169 6         31 my ( $name, $mask ) = split( /\s+/, $named_net );
170            
171 6 50       43 my $ip = $self->{NAMES}->{$name}
172             or confess "$self error: IP address not found for name $name";
173            
174 6         65 $node->{'__VALUE__'} = Farly::IPv4::Network->new("$ip $mask");
175             }
176            
177             sub ANY {
178 72     72 0 169 my ( $self, $node ) = @_;
179 72         523 $node->{'__VALUE__'} = Farly::IPv4::Network->new("0.0.0.0 0.0.0.0");
180             }
181            
182             sub DEFAULT_ROUTE {
183 5     5 0 13 my ( $self, $node ) = @_;
184 5         38 $node->{'__VALUE__'} = Farly::IPv4::Network->new("0.0.0.0 0.0.0.0");
185             }
186            
187             sub ICMP_TYPE {
188 20     20 0 51 my ( $self, $node ) = @_;
189            
190 20         60 my $icmp_type = $node->{'__VALUE__'};
191            
192 20 50       81 $node->{'__VALUE__'} = defined( $self->icmp_formatter()->as_integer($icmp_type) )
193             ? Farly::IPv4::ICMPType->new( $self->icmp_formatter()->as_integer($icmp_type) )
194             : Farly::IPv4::ICMPType->new($icmp_type);
195             }
196            
197             sub PROTOCOL {
198 168     168 0 446 my ( $self, $node ) = @_;
199            
200 168         336 my $protocol = $node->{'__VALUE__'};
201            
202 168 100       555 $node->{'__VALUE__'} = defined( $self->protocol_formatter()->as_integer($protocol) )
203             ? Farly::Transport::Protocol->new( $self->protocol_formatter()->as_integer($protocol) )
204             : Farly::Transport::Protocol->new($protocol);
205             }
206            
207             sub PORT_ID {
208 65     65 0 159 my ( $self, $node ) = @_;
209            
210 65         165 my $port = $node->{'__VALUE__'};
211            
212 65 100       259 $node->{'__VALUE__'} = defined( $self->port_formatter()->as_integer($port) )
213             ? Farly::Transport::Port->new( $self->port_formatter()->as_integer($port) )
214             : Farly::Transport::Port->new($port);
215             }
216            
217             sub PORT_RANGE {
218 15     15 0 41 my ( $self, $node ) = @_;
219            
220 15         48 my $port_range = $node->{'__VALUE__'};
221            
222 15         71 my ( $low, $high ) = split( /\s+/, $port_range );
223            
224 15 50       73 if ( defined $self->port_formatter()->as_integer($low) ) {
225 0         0 $low = $self->port_formatter()->as_integer($low);
226             }
227            
228 15 50       52 if ( defined $self->port_formatter()->as_integer($high) ) {
229 0         0 $high = $self->port_formatter()->as_integer($high);
230             }
231            
232 15         191 $node->{'__VALUE__'} = Farly::Transport::PortRange->new("$low $high");
233             }
234            
235             sub PORT_GT {
236 15     15 0 40 my ( $self, $node ) = @_;
237            
238 15         45 my $port = $node->{'__VALUE__'};
239            
240 15 50       60 $node->{'__VALUE__'} = defined( $self->port_formatter()->as_integer($port) )
241             ? Farly::Transport::PortGT->new( $self->port_formatter()->as_integer($port) )
242             : Farly::Transport::PortGT->new($port);
243             }
244            
245             sub PORT_LT {
246 0     0 0 0 my ( $self, $node ) = @_;
247            
248 0         0 my $port = $node->{'__VALUE__'};
249            
250 0 0       0 $node->{'__VALUE__'} = defined( $self->port_formatter()->as_integer($port) )
251             ? Farly::Transport::PortLT->new( $self->port_formatter()->as_integer($port) )
252             : Farly::Transport::PortLT->new($port);
253             }
254            
255             sub _new_ObjectRef {
256 107     107   235 my ( $self, $token_class, $value ) = @_;
257            
258 107 50       413 my $entry = $Entry_Map->{$token_class}
259             or confess "No token type to ENTRY mapping for token $token_class\n";
260            
261 107         635 my $ce = Farly::Object::Ref->new();
262            
263 107         447 $ce->set( 'ENTRY', Farly::Value::String->new($entry) );
264 107         397 $ce->set( 'ID', Farly::Value::String->new($value) );
265            
266 107         457 return $ce;
267             }
268            
269             sub AUTOLOAD {
270 1271     1271   1662 my ( $self, $node ) = @_;
271            
272 1271 50       2847 my $type = ref($self)
273             or confess "$self is not an object";
274            
275 1271 50       2535 confess "tree node for $type required"
276             unless defined($node);
277            
278 1271 50       2856 confess "value not found in node ", ref($node)
279             unless defined( $node->{'__VALUE__'} );
280            
281 1271         1714 my $token_class = ref($node);
282            
283 1271 50       3813 my $class = $Token_Class_Map->{$token_class}
284             or confess "$self error: class not found for $token_class\n";
285            
286 1271         1365 my $object;
287            
288 1271         1933 my $value = $node->{'__VALUE__'};
289            
290 1271 100       2482 if ( $class eq 'Farly::Object::Ref' ) {
291             #need to set 'ENTRY' and 'ID' properties
292 107         448 $object = $self->_new_ObjectRef( $token_class, $value );
293             }
294             else {
295             #create the object right away
296 1164         4926 $object = $class->new($value);
297             }
298            
299 1271         3266 $node->{'__VALUE__'} = $object;
300             }
301            
302 0     0     sub DESTROY { }
303            
304             1;
305             __END__