vectorvillain has asked for the wisdom of the Perl Monks concerning the following question:

I'm having some problems with an OO module that does PIX firewall ACL parsing (PIX::Walker), and I can't figure out what's going on. In some cases the array reference that should be returned by $configs{$fw}->obj($line->source_str) to should be dereferenced into @sources is returning null, e.g.:

1) deny (ip) IP_Block -> 0.0.0.0/0 IP_Block $VAR1 = [];

It only seems to happen on deny rules, but I'm not 100% positive this is the only case.

Here's the script, I've commented out the code that I've been using to try to troubleshoot this. I've used this module before and the obj object, and never run into anything like this.

#!/usr/bin/perl use strict; use PIX::Walker; use Getopt::Std; use Socket; use Data::Dumper; my $usage = "Usage: portproto-rpt.pl -d config directory -d is required Output is in CSV format to STDOUT, redirect to a file as required use portproto-rpt.pl -h to get this help\n\n"; my @internal = ("10.0.0.0\/8","172.16.0.0\/14","192.168.0.0\/16"); my @firewalls = ("east","west","central"); my %protocols = ( tcp => 1, udp => 1, icmp => 1, gre => 1, esp => 1, ip => 1, ); my %options; my %configs; my %elements; my (@ports,@dests,@sources,@protos); my ($fw,$acl); getopts('hd:', \%options); if ($options{h}) { die $usage }; foreach (@firewalls) { $fw = sprintf "%s\/%s.config",$options{d},$_; if (-e $fw) { $configs{$_} = new PIX::Walker($fw); } else { die "Cannot find config file $_ in \n"; } } print "Firewall,Source,Destination,Protocol,Port,Action\n"; foreach $fw (keys %configs) { $acl = $configs{$fw}->acl("outside-in") || die "ACL: outside-in do +es not exist on filewal config $fw\n"; foreach my $line ($acl->lines) { (@ports,@dests,@sources,@protos,%elements) = 0; # if ($line->action =~ /deny/) { # print $line->print, "\n"; # } if ($protocols{$line->proto_str}) { push @protos, $line->proto_str; } else { my @protos = $configs{$fw}->obj($line->proto_str) } while ($elements{proto} = pop @protos) { if (!$line->destport_str) { push @ports, "any"; } elsif ($line->destport_str =~ /^\d/) { push @ports, $line->destport_str; } else { my @ports = $configs{$fw}->obj($line->destport_st +r) } unless ($ports[0]) {shift @ports}; while ($elements{port} = shift @ports) { if ($line->dest_str =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d +{1,3}/) { push @dests, $line->dest_str; } else { my @dests = $configs{$fw}->obj($line->dest_st +r) } while ($elements{dest} = pop @dests) { if ($line->source_str =~ /^\d{1,3}\.\d{1,3}\.\d{1, +3}\.\d{1,3}/) { push @sources, $line->source_str; } else { print "Help Me\t" . $line->source_str . "\n"; my @sources = $configs{$fw}->obj($line->source +_str); } # if ($line->action =~ /deny/) { # print $line->source_str, "\n"; # unless ($configs{$fw}->obj($line->source_str +)) {print "Cannot find " . $line->source_str, "\n"} # print Dumper(@sources); # } while ($elements{source} = pop @sources) { # if ($line->action =~ /deny/) { print Dumper( +%elements) } unless (checksource($elements{source})) { printf "%s,%s,%s,%s,%s,%s\n", $fw,$element +s{source},$elements{dest},$elements{proto},$elements{port},$line->act +ion; } } } } } } } sub checksource { my $block = shift; $block =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/; my $ip = $1; my $out = 0; foreach (@internal) { my ($net,$bit) = split('/'); if (unpack("N",inet_aton($net)) le unpack("N",inet_aton($ip)) +&& unpack("N",inet_aton($ip)) lt (unpack("N",inet_aton($net))+(2**(32 +-$bit)))) { $out = 1; } } return $out; }

Thanks for any help I can get.

Vec

Edit:

I've realized that a major part of my problem is that I should have been using @sources = $configs{$fw}->obj($line->source_str)->list when I was looking at a smaller utility that determines if an IP is in a particular group.

Replies are listed 'Best First'.
Re: Objectionable reference
by NetWallah (Canon) on Dec 11, 2009 at 20:34 UTC
    You are discarding the results from the "..{fw}->obj" call in
    } else { print "Help Me\t" . $line->source_str . "\n"; my @sources = $configs{$fw}->obj($line->source +_str); }
    because you declare a new block-scoped my @sources within the block.

         Theory is when you know something, but it doesn't work.
        Practice is when something works, but you don't know why it works.
        Programmers combine Theory and Practice: Nothing works and they don't know why.         -Anonymous

      The issue existed before I put in the Help Me check. Based on your suggestion I returned that output of $line->source_str into a scalar and tested everything from there:
      $tmp = $line->source_str; if ($tmp =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) { push @sources, $tmp; } else { # print "Help Me\t" . $line->source_str . "\n"; my @sources = $configs{$fw}->obj($tmp); }

      With these changes in my unsanitized script, I got the same results.

      Edit:

      I re-read your post. When I don't use my @sources = I seem to get the entire firewall object (i.e. the object referenced in $configs{$fw}), rather than the array of the address that should be held in $configs{$fw}->obj($tmp). That's why I put the my in in the first place. Is there a better way to deal with that issue?

        I'm having trouble understanding your intent - what do you want to do if $tmp does not match an IPv4 address pattern ?

        Adding $tmp did not change the flow, or logic.

        It may be more helpful to print

        #REPLACE THIS# print "Help Me\t" . $line->source_str . "\n"; print "IPv4 not matched in line\[" .$line->print() . "] str=". $line- +>source_str . ";\n";
        Yes - the "->obj()" method will return an object. What attribute of that object did you need to extract ?

        I also noticed another place where you are throwing away information the same way as my @source:

        } else { my @protos = $configs{$fw}->obj($line->proto_str) }
        Here, the block-scoped @protos is thrown away.

             Theory is when you know something, but it doesn't work.
            Practice is when something works, but you don't know why it works.
            Programmers combine Theory and Practice: Nothing works and they don't know why.         -Anonymous

Re: Objectionable reference
by chromatic (Archbishop) on Dec 12, 2009 at 18:48 UTC

    Like NetWallah said, you're creating new lexicals which shadow existing lexicals in some of your else blocks. Fix your scoping and you'll have an easier time of debugging. Declaring lexicals at the top of your code:

    my (@ports,@dests,@sources,@protos); my ($fw,$acl);

    ... often leads to problems.