App-PaloAlto-PolicyVerify
view release on metacpan or search on metacpan
lib/App/PaloAlto/PolicyVerify.pm view on Meta::CPAN
open( $self->{fh}, '<:encoding(utf8)', $filepath )
or die "Could not open file '$filepath'";
return $self;
}
sub fields {
my $self = shift;
my %column_numbers = @_;
die "Five fields are required" unless ( keys %column_numbers == 5 );
$self->{fields} =
[ @column_numbers{qw(src_ip dst_ip src_port dst_port protocol)} ];
return $self;
}
use constant {
SRC_IP => 0,
DST_IP => 1,
SRC_PORT => 2,
DST_PORT => 3,
PROTO => 4
};
{
# Cache for src/dst IP, dst port, and proto flows.
my %run_cache;
sub run {
my $self = shift;
my $flow_cache_key;
while ( my $row = $self->{csv}->getline( $self->{fh} ) ) {
# Extract the flow fields
my @flow_info = @{$row}[ @{ $self->{fields} } ];
my $num_fields = grep { defined $_ } @flow_info;
if ( $num_fields != 5 ) {
die
"Only $num_fields fields extracted based on the separating character. We expect 5";
}
# Set up the cache key and return an entry if it exists
# Note that we don't cache based on source port.
$flow_cache_key =
join( ':', @flow_info[ SRC_IP, DST_IP, DST_PORT, PROTO ] );
# Pull the result out of cache, or we test
# the security policy
my $result =
$run_cache{flow_cache_key} || $self->_test_sec_policy(@flow_info);
next unless $result;
# Add the result to the cache if needed.
$run_cache{$flow_cache_key} //= $result;
say $result->rulename . ','
. $result->action . ','
. $result->index . ',';
}
}
}
sub _test_sec_policy {
my $self = shift;
my @flow_info = @_;
# Find the zones for the source and dst IPs
my $src_zone = $self->ip_to_zone( $flow_info[SRC_IP] ) or return;
my $dst_zone = $self->ip_to_zone( $flow_info[DST_IP] ) or return;
# Find the security policy
my $result = $self->{fw}->test->sec_policy(
from => $src_zone,
to => $dst_zone,
src_ip => $flow_info[SRC_IP],
dst_ip => $flow_info[DST_IP],
protocol => $flow_info[PROTO]
);
return $result;
}
{
# Cache for FIB entries so we don't continuously make calls out to
# fib_lookup
my %fib_cache;
# Cache the interfaces on the firewall
my $interfaces;
sub ip_to_zone {
my $self = shift;
my ($ip) = @_;
# Find the egress interface from the FIB
# We check if the entry exists because we want to know about
# undefined routes that don't exist.
my $fib_entry;
if ( exists $fib_cache{$ip} ) {
$fib_entry = $fib_cache{$ip};
}
else {
$fib_entry = $fib_cache{$ip} = $self->{fw}->test->fib_lookup(
ip => $ip,
virtual_router => $self->{vr}
);
}
warn "No valid route for IP '$ip', skipping..." and return
unless $fib_entry;
# FIXME: we're diving straight into the Device::Firewall::PaloAlto::Test::FIB's
# internal structure. Once its interface is better defined we'll go through that.
my $fib_interface = $fib_entry->{entries}[0]{interface};
( run in 3.201 seconds using v1.01-cache-2.11-cpan-364913b4093 )