use Tree::DAG_Node;
use Data::Dumper;
use Net::IP;
# compares two Tree::DAG Nodes and returns positive if right (second) argument is bigger
sub compare_nodes {
my ($compare_node, $leaf_node) = @_;
my $source_OK = compare_subnet($compare_node->{'attributes'}{'source'},$leaf_node->{'attributes'}{'source'});
my $destination_OK = compare_subnet($compare_node->{'attributes'}{'destination'},$leaf_node->{'attributes'}{'destination'});
print "$compare_node->{'attributes'}{'original'} is a daughter of $leaf_node->{'attributes'}{'original'}\n\n" if ($source_OK && $destination_OK);
return 1 if ($source_OK && $destination_OK);
return undef;
}
# create nodes for tree construction later on
my $root = Tree::DAG_Node->new;
$root->attributes ({
original => 'permit ip any any',
source => ['0.0.0.0/0'],
destination => ['0.0.0.0/0']
});
my $leaf_1 = Tree::DAG_Node->new;
$leaf_1->attributes ({
original => 'permit ip 10.0.0.0/8 172.16.0.0/16',
source => ['10.0.0.0/8'],
destination => ['172.16.0.0/16']
});
my $leaf_2 = Tree::DAG_Node->new;
$leaf_2->attributes ({
original => 'permit ip 10.0.0.0/16 172.16.0.0/24',
source => ['10.0.0.0/16'],
destination => ['172.16.0.0/24']
});
my $leaf_3 = Tree::DAG_Node->new;
$leaf_3->attributes ({
original => 'permit ip 192.168.0.0/16 12.16.0.0/24',
source => ['192.168.0.0/16'],
destination => ['12.16.0.0/24']
});
my @node_list;
push @node_list, $leaf_1, $leaf_2, $leaf_3 ;
# Subnet comparison
# returns true if $x is a subset of $y
sub compare_subnet {
my ($x, $y) = @_;
a_in_b ($_, @$y) or return '' foreach @$x; #Check if each element of
return 1;
};
# check one ip address against array of ip addresses
# first argument is single address, second one is array
sub a_in_b {
my $node1 = shift(@_);
my @ip_list = @_;
for my $node2 (@ip_list) {
my $ip1 = new Net::IP ($node1) || die (Net::IP::Error());
my $ip2 = new Net::IP ($node2) || die (Net::IP::Error());
if (($ip1->overlaps($ip2) == $IP_A_IN_B_OVERLAP) || ($ip1->overlaps($ip2) == $IP_IDENTICAL)) {
return 1;
}
}
return '';
}
#build the tree
foreach my $node (@node_list){
my $location;
$root->walk_down({
callback => sub {
my $this_node = shift;
if (compare_nodes($node,$this_node)){
$location = $this_node->address;
1;
}
else{
0;
}
}
});
$root->address($location)->add_daughter($node) if defined $root->address($location);
}
# print the tree
$root->walk_down({
callback => sub {
my $node = shift;
print " " x $_[0]->{_depth};
print $node->{'attributes'}{'original'}, "\n";
},
_depth => 0,
});
$root->delete_tree();
####
permit ip any any
permit ip 10.0.0.0/8 172.16.0.0/16
permit ip 10.0.0.0/16 172.16.0.0/24
permit ip 192.168.0.0/16 12.16.0.0/24
####
root > A > B > C
####
[A,C,B]
####
root
A
C
B
####
root
A
B
C