line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Device::Network::ConfigParser::CheckPoint::Gaia; |
2
|
|
|
|
|
|
|
# ABSTRACT: Parse CheckPoint Configuration |
3
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
1676
|
use 5.006; |
|
1
|
|
|
|
|
5
|
|
5
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
27
|
|
6
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
29
|
|
7
|
1
|
|
|
1
|
|
351
|
use Modern::Perl; |
|
1
|
|
|
|
|
8203
|
|
|
1
|
|
|
|
|
8
|
|
8
|
1
|
|
|
1
|
|
1159
|
use Parse::RecDescent; |
|
1
|
|
|
|
|
32457
|
|
|
1
|
|
|
|
|
10
|
|
9
|
1
|
|
|
1
|
|
549
|
use Data::Dumper; |
|
1
|
|
|
|
|
6325
|
|
|
1
|
|
|
|
|
82
|
|
10
|
1
|
|
|
1
|
|
487
|
use JSON; |
|
1
|
|
|
|
|
7243
|
|
|
1
|
|
|
|
|
8
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
160
|
use Exporter qw{import}; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1006
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our @EXPORT_OK = qw{get_parser get_output_drivers parse_config post_process}; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub get_parser { |
18
|
1
|
|
|
1
|
1
|
607
|
return new Parse::RecDescent(q{ |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
startrule: config_line(s) { $item[1] } |
21
|
|
|
|
|
|
|
config_line: |
22
|
|
|
|
|
|
|
aaa { $item[1] } | |
23
|
|
|
|
|
|
|
arp { $item[1] } | |
24
|
|
|
|
|
|
|
bonding { $item[1] } | |
25
|
|
|
|
|
|
|
clienv { $item[1] } | |
26
|
|
|
|
|
|
|
core_dump { $item[1] } | |
27
|
|
|
|
|
|
|
dns { $item[1] } | |
28
|
|
|
|
|
|
|
domainname { $item[1] } | |
29
|
|
|
|
|
|
|
format { $item[1] } | |
30
|
|
|
|
|
|
|
hostname { $item[1] } | |
31
|
|
|
|
|
|
|
inactivity_timeout { $item[1] } | |
32
|
|
|
|
|
|
|
interface { $item[1] } | |
33
|
|
|
|
|
|
|
ipv6 { $item[1] } | |
34
|
|
|
|
|
|
|
ipv6_state { $item[1] } | |
35
|
|
|
|
|
|
|
management { $item[1] } | |
36
|
|
|
|
|
|
|
management { $item[1] } | |
37
|
|
|
|
|
|
|
max_path_splits { $item[1] } | |
38
|
|
|
|
|
|
|
message { $item[1] } | |
39
|
|
|
|
|
|
|
net_access { $item[1] } | |
40
|
|
|
|
|
|
|
ntp { $item[1] } | |
41
|
|
|
|
|
|
|
ospf { $item[1] } | |
42
|
|
|
|
|
|
|
password_controls { $item[1] } | |
43
|
|
|
|
|
|
|
pbr { $item[1] } | |
44
|
|
|
|
|
|
|
rip { $item[1] } | |
45
|
|
|
|
|
|
|
snmp { $item[1] } | |
46
|
|
|
|
|
|
|
static_route { $item[1] } | |
47
|
|
|
|
|
|
|
timezone { $item[1] } | |
48
|
|
|
|
|
|
|
tracefile { $item[1] } | |
49
|
|
|
|
|
|
|
user { $item[1] } | |
50
|
|
|
|
|
|
|
vrrp { $item[1] } | |
51
|
|
|
|
|
|
|
web { $item[1] } | |
52
|
|
|
|
|
|
|
not_config { $item[1] } |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
aaa: 'set aaa' m{\N+} { { type => $item[0], config => "yes" } } |
55
|
|
|
|
|
|
|
arp: 'set arp' m{\N+} { { type => $item[0], config => "yes" } } |
56
|
|
|
|
|
|
|
bonding: 'set bonding' m{\N+} { { type => $item[0], config => "yes" } } |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
clienv: 'set clienv' config_lock { { type => $item[0], config => { @{ $item[2] } } } } |
59
|
|
|
|
|
|
|
config_lock: 'config-lock' m{on|off} { [$item[0], $item[2]] } |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
core_dump: 'set core-dump' m{\N+} { { type => $item[0], config => "yes" } } |
63
|
|
|
|
|
|
|
dns: 'set dns' m{\N+} { { type => $item[0], config => "yes" } } |
64
|
|
|
|
|
|
|
domainname: 'set domainname' m{\N+} { { type => $item[0], config => "yes" } } |
65
|
|
|
|
|
|
|
format: 'set format' m{\N+} { { type => $item[0], config => "yes" } } |
66
|
|
|
|
|
|
|
hostname: 'set hostname' m{\N+} { { type => $item[0], config => "yes" } } |
67
|
|
|
|
|
|
|
inactivity_timeout: 'set inactivity-timeout' m{\N+} { { type => $item[0], config => "yes" } } |
68
|
|
|
|
|
|
|
ipv6: 'set ipv6' m{\N+} { { type => $item[0], config => "yes" } } |
69
|
|
|
|
|
|
|
ipv6_state: 'set ipv6-state' m{\N+} { { type => $item[0], config => "yes" } } |
70
|
|
|
|
|
|
|
management: 'set management' m{\N+} { { type => $item[0], config => "yes" } } |
71
|
|
|
|
|
|
|
max_path_splits: 'set max-path-splits'm{\N+} { { type => $item[0], config => "yes" } } |
72
|
|
|
|
|
|
|
message: 'set message' m{\N+} { { type => $item[0], config => "yes" } } |
73
|
|
|
|
|
|
|
net_access: 'set net-access' m{\N+} { { type => $item[0], config => "yes" } } |
74
|
|
|
|
|
|
|
ntp: 'set ntp' m{\N+} { { type => $item[0], config => "yes" } } |
75
|
|
|
|
|
|
|
ospf: 'set ospf' m{\N+} { { type => $item[0], config => "yes" } } |
76
|
|
|
|
|
|
|
password_controls: 'set password-controls' m{\N+} { { type => $item[0], config => "yes" } } |
77
|
|
|
|
|
|
|
pbr: 'set pbr' m{\N+} { { type => $item[0], config => "yes" } } |
78
|
|
|
|
|
|
|
rip: 'set rip' m{\N+} { { type => $item[0], config => "yes" } } |
79
|
|
|
|
|
|
|
snmp: 'set snmp' m{\N+} { { type => $item[0], config => "yes" } } |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
static_route: 'set static-route' destination (nexthop | comment) { { type => $item[0], config => { @{ $item[2] }, @{ $item[3]->[1] } } } } |
82
|
|
|
|
|
|
|
destination: m{((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{2})|default)} { [$item[0], $item[1]] } |
83
|
|
|
|
|
|
|
nexthop: 'nexthop' (nexthop_blackhole | nexthop_reject | nexthop_address | nexthop_interface) { [@{$item[2]->[1]}] } |
84
|
|
|
|
|
|
|
nexthop_blackhole: 'blackhole' { ['nexthop_type', $item[1]] } |
85
|
|
|
|
|
|
|
nexthop_reject: 'reject' { ['nexthop_type', $item[1]] } |
86
|
|
|
|
|
|
|
nexthop_address: 'gateway address' ipv4 m{on|off} { [nexthop_type => 'address', nexthop => $item[2]->[1], status => $item[3]] } |
87
|
|
|
|
|
|
|
nexthop_interface: 'gateway logical' interface_name m{on|off} { [nexthop_type => 'interface', nexthop => $item[2]->[1], status => $item[3]] } |
88
|
|
|
|
|
|
|
comment: 'comment' m{"[\w\s]+"} { [$item[0], $item[2]] } |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
timezone: 'set timezone' m{\N+} { { type => $item[0], config => "yes" } } |
93
|
|
|
|
|
|
|
tracefile: 'set tracefile' m{\N+} { { type => $item[0], config => "yes" } } |
94
|
|
|
|
|
|
|
user: 'set user' m{\N+} { { type => $item[0], config => "yes" } } |
95
|
|
|
|
|
|
|
vrrp: 'set vrrp' m{\N+} { { type => $item[0], config => "yes" } } |
96
|
|
|
|
|
|
|
web: 'set web' m{\N+} { { type => $item[0], config => "yes" } } |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
interface: |
100
|
|
|
|
|
|
|
'set interface' interface_name (ipv4_address_mask | vlan | state | comment | mtu | auto_negotiation | link_speed) |
101
|
|
|
|
|
|
|
{ { type => $item[0], config => { name => $item[2]->[1], %{ $item[3]->[1] } } } } |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
ipv4_address_mask: ipv4_address ipv4_mask { $return = { @{$item[1]}, @{$item[2]}} } |
104
|
|
|
|
|
|
|
ipv4_address: 'ipv4-address' ipv4 { [$item[0], $item[2]->[1]] } |
105
|
|
|
|
|
|
|
ipv4_mask: 'mask-length' m{\d+} { [$item[0], $item[2]] } |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
vlan: 'vlan' m{\d+} { $return = { $item[0], $item[2] } } |
108
|
|
|
|
|
|
|
state: 'state' m{\S+} { $return = { $item[0], $item[2] } } |
109
|
|
|
|
|
|
|
comment: 'comments' m{"[\w\s]+"} { $return = { $item[0], $item[2] } } |
110
|
|
|
|
|
|
|
mtu: 'mtu' m{\d+} { $return = { $item[0], $item[2] } } |
111
|
|
|
|
|
|
|
auto_negotiation: 'auto-negotiation' m{\S+} { $return = { $item[0], $item[2] } } |
112
|
|
|
|
|
|
|
link_speed: 'link-speed' m{\S+} { $return = { $item[0], $item[2] } } |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Utility definitions |
115
|
|
|
|
|
|
|
ipv4: m{\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}} |
116
|
|
|
|
|
|
|
interface_name: m{\S+} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
not_config: m{\N+} |
119
|
|
|
|
|
|
|
{ { type => $item[0], config => $item[1] } } |
120
|
|
|
|
|
|
|
}); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub parse_config { |
126
|
13
|
|
|
13
|
1
|
387587
|
my ($parser, $config_contents) = @_; |
127
|
|
|
|
|
|
|
|
128
|
13
|
|
|
|
|
140
|
my $parse_tree = $parser->startrule($config_contents); |
129
|
|
|
|
|
|
|
|
130
|
13
|
|
|
|
|
243926
|
return $parse_tree; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub get_output_drivers { |
136
|
|
|
|
|
|
|
return { |
137
|
0
|
|
|
0
|
1
|
0
|
csv => \&csv_output_driver, |
138
|
|
|
|
|
|
|
json => \&json_output_driver, |
139
|
|
|
|
|
|
|
}; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub post_process { |
144
|
13
|
|
|
13
|
1
|
114
|
my ($parsed_config) = @_; |
145
|
13
|
|
|
|
|
47
|
my %aggregation = (); |
146
|
13
|
|
|
|
|
30
|
my %post_processed_config; |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# For each 'type' of config, (e.g. interface config), the aggregator key we're using to aggregate the separate |
149
|
|
|
|
|
|
|
# config lines together into a single hash. |
150
|
13
|
|
|
|
|
83
|
my $aggregator_keys_for = { |
151
|
|
|
|
|
|
|
interface => q{$config_entry->{config}->{name}}, |
152
|
|
|
|
|
|
|
static_route => q{$config_entry->{config}->{destination}}, |
153
|
|
|
|
|
|
|
}; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Go through each config entry (which was originally each line of config. If there's an aggregate key defined, |
156
|
|
|
|
|
|
|
# aggregate on the 'type' and then this 'key'. |
157
|
|
|
|
|
|
|
# |
158
|
|
|
|
|
|
|
# If not, then just push it to the post processed hash. |
159
|
13
|
|
|
|
|
33
|
for my $config_entry (@{ $parsed_config }) { |
|
13
|
|
|
|
|
53
|
|
160
|
18
|
50
|
|
|
|
97
|
if (exists $aggregator_keys_for->{ $config_entry->{type} }) { |
161
|
18
|
|
|
|
|
1849
|
my $aggregate_key = eval $aggregator_keys_for->{ $config_entry->{type} }; |
162
|
18
|
|
|
|
|
112
|
@{ $aggregation{ $config_entry->{type} }{ $aggregate_key } }{ keys %{ $config_entry->{config} } } = values %{ $config_entry->{config} }; |
|
18
|
|
|
|
|
141
|
|
|
18
|
|
|
|
|
60
|
|
|
18
|
|
|
|
|
83
|
|
163
|
|
|
|
|
|
|
} else { |
164
|
0
|
|
|
|
|
0
|
push @{ $post_processed_config{ $config_entry->{type} } }, $config_entry->{config}; |
|
0
|
|
|
|
|
0
|
|
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# It's of the form $aggregation{type}{key} = { #interface into }; but the key is implicitly part of the hash it points to. |
169
|
|
|
|
|
|
|
# Turn the hash of hash of hashes into a hash of array of hashes ( $aggregation{type} = [ { #interface info } ]; |
170
|
13
|
|
|
|
|
47
|
for my $config_type (keys %aggregation) { |
171
|
13
|
|
|
|
|
27
|
$aggregation{ $config_type } = [ values %{ $aggregation{ $config_type } } ]; |
|
13
|
|
|
|
|
69
|
|
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
13
|
|
|
|
|
50
|
@post_processed_config{ keys %aggregation } = values %aggregation; |
175
|
|
|
|
|
|
|
|
176
|
13
|
|
|
|
|
66
|
return \%post_processed_config; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub csv_output_driver { |
182
|
0
|
|
|
0
|
1
|
|
my ($fh, $filename, $parsed_config) = @_; |
183
|
0
|
|
|
|
|
|
my $csv_type_driver = { |
184
|
|
|
|
|
|
|
interface => \&_csv_interface_driver, |
185
|
|
|
|
|
|
|
static_route => \&_csv_static_route_driver, |
186
|
|
|
|
|
|
|
not_config => \&_csv_not_config_driver, |
187
|
|
|
|
|
|
|
}; |
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
say "=" x 16 . "BEGIN FILE $filename" . "=" x 16; |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
TYPE: |
192
|
0
|
|
|
|
|
|
for my $type (keys %{ $parsed_config }) { |
|
0
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
say "-" x 8 . "BEGIN TYPE $type" . "-" x 8; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
defined $csv_type_driver->{$type} ? |
196
|
0
|
0
|
|
|
|
|
$csv_type_driver->{$type}->($fh, $parsed_config->{$type}) : |
|
|
0
|
|
|
|
|
|
197
|
|
|
|
|
|
|
warn "No CSV output driver for $type\n" and next TYPE; |
198
|
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
|
say "-" x 8 . "END TYPE $type" . "-" x 8; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
0
|
|
|
|
|
|
say "-" x 8 . "END FILE $filename" . "-" x 8; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub _csv_interface_driver { |
206
|
0
|
|
|
0
|
|
|
my ($fh, $interfaces_ref) = @_; |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Print the CSV schema line |
209
|
0
|
|
|
|
|
|
my @interface_properties = qw{name state vlan ipv4_address ipv4_mask auto_negotiation link_speed mtu comment}; |
210
|
0
|
|
|
|
|
|
say $fh join(',', @interface_properties); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# Interface through the interfaces, extract and print their properties |
213
|
0
|
|
|
|
|
|
for my $interface (@{ $interfaces_ref }) { |
|
0
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
|
my @properties = @{ $interface }{ @interface_properties }; |
|
0
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# Replace any undef with an empty string |
217
|
0
|
0
|
|
|
|
|
@properties = map { defined $_ ? $_ : '' } @properties; |
|
0
|
|
|
|
|
|
|
218
|
0
|
|
|
|
|
|
say $fh join(',', @properties); |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub _csv_static_route_driver { |
224
|
0
|
|
|
0
|
|
|
my ($fh, $static_routes_ref) = @_; |
225
|
|
|
|
|
|
|
|
226
|
0
|
|
|
|
|
|
my @static_route_properties = qw{destination nexthop nexthop_type status}; |
227
|
0
|
|
|
|
|
|
say $fh join(',', @static_route_properties); |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
for my $route (@{ $static_routes_ref }) { |
|
0
|
|
|
|
|
|
|
230
|
0
|
|
|
|
|
|
my @properties = @{ $route }{ @static_route_properties }; |
|
0
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# Replace any undef with an empty string |
233
|
0
|
0
|
|
|
|
|
@properties = map { defined $_ ? $_ : '' } @properties; |
|
0
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
|
say $fh join(',', @properties); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub _csv_not_config_driver { |
240
|
0
|
|
|
0
|
|
|
my ($fh, $not_config) = @_; |
241
|
|
|
|
|
|
|
|
242
|
0
|
|
|
|
|
|
for my $config_line (@{ $not_config }) { |
|
0
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
print $fh "$config_line\n"; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub json_output_driver { |
253
|
0
|
|
|
0
|
1
|
|
my ($fh, $filename, $parsed_config) = @_; |
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
print encode_json($parsed_config); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
1; # End of Device::CheckPoint::ConfigParse |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
__END__ |