File Coverage

blib/lib/Farly/ASA/Parser.pm
Criterion Covered Total %
statement 35 35 100.0
branch 2 4 50.0
condition n/a
subroutine 10 10 100.0
pod 0 2 0.0
total 47 51 92.1


line stmt bran cond sub pod time code
1             package Farly::ASA::Parser;
2            
3 11     11   17036 use 5.008008;
  11         36  
  11         396  
4 11     11   54 use strict;
  11         18  
  11         283  
5 11     11   52 use warnings;
  11         20  
  11         281  
6 11     11   52 use Carp;
  11         32  
  11         681  
7 11     11   2345 use Log::Any qw($log);
  11         2087  
  11         71  
8 11     11   20797 use Parse::RecDescent;
  11         533177  
  11         112  
9            
10             our $VERSION = '0.26';
11            
12             $::RD_ERRORS = 1; # Make sure the parser dies when it encounters an error
13            
14             #$::RD_WARN = 1; # Enable warnings. This will warn on unused rules &c.
15             #$::RD_HINT = 1; # Give out hints to help fix problems.
16             #$::RD_TRACE = 1;
17            
18             sub new {
19 8     8 0 148 my ($class) = @_;
20            
21 8         32 my $self = { PARSER => undef, };
22 8         22 bless $self, $class;
23            
24 8         79 $log->info("$self NEW");
25            
26 8         51 $self->_init();
27            
28 8         84 return $self;
29             }
30            
31             sub _init {
32 8     8   21 my ($self) = @_;
33            
34 8         60 $self->{PARSER} = Parse::RecDescent->new( $self->_grammar() );
35            
36 8         5883356 $log->info( "$self new Parser " . $self->{PARSER} );
37             }
38            
39             sub parse {
40 358     358 0 27379 my ( $self, $string ) = @_;
41            
42 358 50       1094 defined($string) or confess "blank line received";
43            
44             #STDERR should go to a log file
45 358         3111 my $tree = $self->{PARSER}->startrule($string);
46            
47             #throw an error if the parse fails
48 358 50       2330864 defined($tree) or confess "unrecognized line\n";
49            
50 358         1621 return $tree;
51             }
52            
53             sub _grammar {
54 8     8   19 my ($self) = @_;
55            
56 8         26 my $grammar = q{
57            
58            
59             startrule :
60             object_group EOL
61             | access_list EOL
62             | named_ip EOL
63             | interface EOL
64             | object EOL
65             | access_group EOL
66             | hostname EOL
67             | route EOL
68             |
69            
70             hostname :
71             'hostname' STRING
72            
73             #
74             # names
75             #
76            
77             named_ip :
78             'name' IPADDRESS name
79            
80             name :
81             NAME_ID name_comment
82             | NAME_ID
83            
84             name_comment :
85             'description' REMARKS
86            
87             #
88             # interfaces
89             #
90            
91             interface :
92             'interface' STRING interface_options
93            
94             interface_options :
95             if_name
96             | sec_level
97             | if_addr
98             | EOL
99            
100             if_name :
101             'nameif' STRING interface_options
102            
103             sec_level :
104             'security-level' DIGIT interface_options
105            
106             if_addr :
107             'ip address' if_ip interface_options
108            
109             if_ip :
110             IPADDRESS if_mask
111             | NAME if_mask
112            
113             if_mask :
114             MASK if_standby
115             | MASK
116            
117             if_standby :
118             'standby' IPADDRESS
119             | 'standby' NAME
120            
121             #
122             # objects
123             #
124            
125             object :
126             'object' OBJECT_ENTRY object_id
127            
128             object_id :
129             STRING object_address
130             | STRING object_service
131            
132             object_address :
133             'host' IPADDRESS
134             {
135             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'HOST'}, 'OBJECT_TYPE' );
136             bless {%item}, $item[0];
137             }
138             |
139             'range' IPRANGE
140             {
141             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'RANGE'}, 'OBJECT_TYPE' );
142             bless {%item}, $item[0];
143             }
144             |
145             'subnet' IPNETWORK
146             {
147             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'NETWORK'}, 'OBJECT_TYPE' );
148             bless {%item}, $item[0];
149             }
150            
151             object_service :
152             'service' object_service_protocol
153             {
154             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'SERVICE'}, 'OBJECT_TYPE' );
155             bless {%item}, $item[0];
156             }
157            
158             object_service_protocol :
159             PROTOCOL object_service_src
160             | PROTOCOL object_service_dst
161             | PROTOCOL object_icmp
162             | PROTOCOL
163            
164             object_service_src :
165             'source' port object_service_dst
166             | 'source' port
167            
168             object_service_dst :
169             'destination' port
170            
171             object_icmp :
172             ICMP_TYPE
173            
174             #
175             # object-group
176             #
177            
178             object_group :
179             'object-group' GROUP_TYPE og_id
180            
181             og_id :
182             STRING og_object
183             | STRING og_protocol
184            
185             og_protocol :
186             GROUP_PROTOCOL og_object
187            
188             og_object :
189             og_network_object
190             | og_port_object
191             | og_group_object
192             | og_protocol_object
193             | og_description
194             | og_icmp_object
195             | og_service_object
196            
197             og_network_object :
198             'network-object' address
199             {
200             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'NETWORK'}, 'OBJECT_TYPE' );
201             bless {%item}, $item[0];
202             }
203            
204             og_port_object :
205             'port-object' port
206             {
207             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'PORT'}, 'OBJECT_TYPE' );
208             bless {%item}, $item[0];
209             }
210            
211             og_group_object :
212             'group-object' GROUP_REF
213             {
214             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'GROUP'}, 'OBJECT_TYPE' );
215             bless {%item}, $item[0];
216             }
217            
218             og_protocol_object :
219             'protocol-object' PROTOCOL
220             {
221             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'PROTOCOL'}, 'OBJECT_TYPE' );
222             bless {%item}, $item[0];
223             }
224            
225             og_description :
226             'description' REMARKS
227             {
228             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'COMMENT'}, 'OBJECT_TYPE' );
229             bless {%item}, $item[0];
230             }
231            
232             og_icmp_object :
233             'icmp-object' ICMP_TYPE
234             {
235             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'ICMP_TYPE'}, 'OBJECT_TYPE' );
236             bless {%item}, $item[0];
237             }
238            
239             og_service_object :
240             'service-object' og_so_protocol
241             {
242             $item{'OBJECT_TYPE'} = bless( {'__VALUE__' => 'SERVICE'}, 'OBJECT_TYPE' );
243             bless {%item}, $item[0];
244             }
245            
246             og_so_protocol :
247             PROTOCOL og_so_dst_port
248             | PROTOCOL og_so_src_port
249             | PROTOCOL object_icmp
250             | PROTOCOL
251            
252             og_so_src_port :
253             'source' port og_so_dst_port
254             | 'source' port
255            
256             og_so_dst_port :
257             'destination' port
258             | port
259            
260             #
261             # access-lists
262             #
263            
264             access_list :
265             'access-list' acl_id
266            
267             acl_id :
268             STRING acl_line
269             | STRING acl_type
270             | STRING acl_action
271            
272             acl_line :
273             'line' DIGIT acl_type
274             | 'line' DIGIT acl_action
275            
276             acl_type :
277             ACL_TYPES acl_action
278             | acl_remark
279            
280             acl_remark :
281             'remark' REMARKS
282            
283             acl_action :
284             ACTIONS acl_protocol
285            
286             #
287             # protocol options
288             #
289            
290             acl_protocol :
291             PROTOCOL acl_src_ip
292             | 'OG_PROTOCOL' GROUP_REF acl_src_ip
293             | 'OG_SERVICE' GROUP_REF acl_src_ip
294             | 'object' OBJECT_REF acl_src_ip
295            
296             #
297             # access-list source IP addresses
298             #
299            
300             acl_src_ip :
301             address acl_dst_ip
302             | address acl_src_port
303            
304             #
305             # access-list source ports
306             #
307            
308             acl_src_port :
309             port acl_dst_ip
310            
311             #
312             # access-list destination IP address
313             #
314            
315             acl_dst_ip :
316             address acl_dst_port
317             | address acl_options
318            
319             #
320             # access-list destination ports
321             #
322            
323             acl_dst_port :
324             port acl_options
325             | acl_icmp_type acl_options
326            
327             #
328             # icmp_types
329             #
330            
331             acl_icmp_type :
332             'OG_ICMP-TYPE' GROUP_REF
333             | ICMP_TYPE
334            
335             #
336             # access-list options
337             #
338            
339             acl_options :
340             acl_logging
341             | acl_time_range
342             | acl_inactive
343             | EOL
344             |
345            
346             acl_logging :
347             'log' acl_log_level
348             | 'log' acl_time_range
349             {
350             $item{'LOG_LEVEL'} = bless( {'__VALUE__' => '6'}, 'LOG_LEVEL' );
351             bless {%item}, 'acl_log_level';
352             }
353             | 'log' acl_inactive
354             {
355             $item{'LOG_LEVEL'} = bless( {'__VALUE__' => '6'}, 'LOG_LEVEL' );
356             bless {%item}, 'acl_log_level';
357             }
358             | 'log'
359             {
360             $item{'LOG_LEVEL'} = bless( {'__VALUE__' => '6'}, 'LOG_LEVEL' );
361             bless {%item}, 'acl_log_level';
362             }
363            
364             acl_log_level :
365             LOG_LEVEL acl_log_interval
366             | LOG_LEVEL acl_time_range
367             | LOG_LEVEL acl_inactive
368             | LOG_LEVEL
369            
370             acl_log_interval :
371             'interval' DIGIT acl_time_range
372             | 'interval' DIGIT acl_inactive
373             | 'interval' DIGIT
374            
375             acl_time_range :
376             'time-range' STRING acl_inactive
377             | 'time-range' STRING
378            
379             acl_inactive :
380             ACL_STATUS
381            
382             #
383             # access_group
384             #
385            
386             access_group :
387             'access-group' ag_id
388            
389             ag_id :
390             RULE_REF ag_direction
391             | RULE_REF ag_global
392            
393             ag_global :
394             ACL_GLOBAL
395            
396             ag_direction :
397             ACL_DIRECTION ag_interface
398            
399             ag_interface :
400             'interface' IF_REF
401            
402             #
403             # routes
404             #
405            
406             route :
407             'route' route_interface
408            
409             route_interface :
410             IF_REF route_dst
411            
412             route_dst :
413             IPNETWORK route_nexthop
414             | NAMED_NET route_nexthop
415             | DEFAULT_ROUTE route_nexthop
416            
417             route_nexthop :
418             IPADDRESS route_options
419            
420             route_options :
421             route_cost
422             | route_track
423             | route_tunneled
424             | EOL
425             |
426            
427             route_cost :
428             DIGIT route_options
429            
430             route_track :
431             'track' DIGIT route_options
432            
433             route_tunneled :
434             TUNNELED
435            
436             #
437             # IP address types
438             #
439             # "object" should be fine here because "object" can not
440             # be used to specify ports
441             #
442            
443             address :
444             'host' IPADDRESS
445             | 'host' NAME
446             | IPNETWORK
447             | NAMED_NET
448             | ANY
449             | 'object' OBJECT_REF
450             | 'interface' IF_REF
451             | 'OG_NETWORK' GROUP_REF
452            
453             #
454             # port types
455             #
456            
457             port :
458             port_eq
459             | port_range
460             | 'OG_SERVICE' GROUP_REF
461             | port_gt
462             | port_lt
463             | port_neq
464            
465             port_eq :
466             'eq' PORT_ID
467            
468             port_range :
469             'range' PORT_RANGE
470            
471             port_gt :
472             'gt' PORT_GT
473            
474             port_lt :
475             'lt' PORT_LT
476            
477             port_neq :
478             'neq'
479            
480             #
481             # Token Definitions
482             #
483            
484             STRING :
485             /\S+/
486            
487             DIGIT :
488             /\d+/
489            
490             # converted to an IP address
491             NAME :
492             /((^|\s[a-zA-Z])(\.|[0-9a-zA-Z_-]+)+)/
493            
494             # not converted to an IP address
495             NAME_ID :
496             /((^|\s[a-zA-Z])(\.|[0-9a-zA-Z_-]+)+)/
497            
498             IF_REF :
499             /\S+/
500            
501             OBJECT_REF :
502             /\S+/
503            
504             GROUP_REF :
505             /\S+/
506            
507             RULE_REF :
508             /\S+/
509            
510             GROUP_TYPE :
511             'service' | 'icmp-type' | 'network' | 'protocol'
512            
513             OBJECT_ENTRY :
514             'network'
515             | 'service'
516            
517             ANY :
518             'any'
519            
520             DEFAULT_ROUTE :
521             /0(\s+)0/
522            
523             IPADDRESS :
524             /((\d{1,3})((\.)(\d{1,3})){3})/
525            
526             MASK :
527             /(255|254|252|248|240|224|192|128|0)((\.)(255|254|252|248|240|224|192|128|0)){3}/
528            
529             IPNETWORK :
530             /((\d{1,3})((\.)(\d{1,3})){3})\s+((255|254|252|248|240|224|192|128|0)((\.)(255|254|252|248|240|224|192|128|0)){3})/
531            
532             IPRANGE :
533             /((\d{1,3})((\.)(\d{1,3})){3})\s+((\d{1,3})((\.)(\d{1,3})){3})/
534            
535             NAMED_NET :
536             /((^|\s[a-zA-Z])(\.|[0-9a-zA-Z_-]+)+)\s+((255|254|252|248|240|224|192|128|0)((\.)(255|254|252|248|240|224|192|128|0)){3})/
537            
538             PROTOCOL :
539             /\d+/ | 'ah' | 'eigrp' | 'esp' | 'gre' | 'icmp' | 'icmp6' | 'igmp'
540             | 'igrp' | 'ipinip' | 'ipsec' | 'ip' | 'nos' | 'ospf' | 'pcp'
541             | 'pim' | 'pptp' | 'snp' | 'tcp' | 'udp'
542            
543             GROUP_PROTOCOL :
544             'tcp-udp' | 'tcp' | 'udp'
545            
546             ICMP_TYPE :
547             /\d+/ | 'alternate-address' | 'conversion-error' | 'echo-reply' | 'echo'
548             | 'information-reply' | 'information-request' | 'mask-reply' | 'mask-request'
549             | 'mobile-redirect' | 'parameter-problem' | 'redirect' | 'router-advertisement'
550             | 'router-solicitation' | 'source-quench' | 'time-exceeded' | 'timestamp-reply'
551             | 'timestamp-request' | 'traceroute' | 'unreachable'
552            
553             PORT_ID :
554             /\S+/
555            
556             PORT_GT :
557             /\S+/
558            
559             PORT_LT :
560             /\S+/
561            
562             PORT_RANGE :
563             /\S+\s+\S+/
564            
565             ACTIONS :
566             'permit'
567             | 'deny'
568            
569             ACL_TYPES :
570             'extended'
571            
572             REMARKS :
573             /.*$/
574            
575             ACL_DIRECTION :
576             'in'
577             | 'out'
578            
579             ACL_GLOBAL :
580             'global'
581            
582             ACL_STATUS :
583             'inactive'
584            
585             STATE :
586             'enable'
587             | 'disable'
588            
589             TUNNELED :
590             'tunneled'
591            
592             LOG_LEVEL :
593             /\d+/ | 'emergencies' | 'alerts' | 'critical' | 'errors'
594             | 'warnings' | 'notifications' | 'informational' | 'debugging'
595             | 'disable'
596            
597             EOL :
598             /$/
599            
600             #
601             # Imaginary Tokens
602             #
603             # OBJECT_TYPE
604             #
605            
606             };
607            
608 8         81 return $grammar;
609             }
610            
611             1;
612             __END__