File Coverage

blib/lib/Tie/NetAddr/IP.pm
Criterion Covered Total %
statement 71 78 91.0
branch 17 24 70.8
condition 2 3 66.6
subroutine 12 13 92.3
pod 0 1 0.0
total 102 119 85.7


line stmt bran cond sub pod time code
1             package Tie::NetAddr::IP;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Tie::NetAddr::IP - Implements a Hash where the key is a subnet
8              
9             =head1 SYNOPSIS
10              
11             use Tie::NetAddr::IP;
12              
13             my %WhereIs;
14            
15             tie %WhereIs, Tie::NetAddr::IP;
16              
17             $WhereIs{"10.0.10.0/24"} = "Lab, First Floor";
18             $WhereIs{"10.0.20.0/24"} = "Datacenter, Second Floor";
19             $WhereIs{"10.0.30.0/27"} = "Remote location";
20             $WhereIs{"0.0.0.0/0"} = "God knows where";
21              
22             foreach $host ("10.0.10.1", "10.0.20.15", "10.0.32.17", "10.10.0.1") {
23             print "Host $host is in ", $WhereIs{$host}, "\n";
24             }
25              
26             foreach $subnet (keys %WhereIs) {
27             print "Network ", $subnet, " is used in ",
28             $WhereIs{$subnet}, "\n";
29             }
30              
31             untie %WhereIs;
32              
33             =head1 DESCRIPTION
34              
35             This module overloads hashes so that the key can be a subnet as in
36             B. When looking values up, an interpretation will be made
37             to find the given key B the subnets specified in the hash.
38              
39             The code sample provided on the B would print out the
40             locations of every machine in the C loop.
41              
42             Care must be taken, as only strings that can be parsed as an IP
43             address by B can be used as keys for this hash.
44              
45             Iterators on the hash such as C, C, C and
46             C will only see the actual subnets provided as keys to the
47             hash. When looking up a value such as in C<$hash{$ipaddress}> this IP
48             address will be looked up among the subnets existing as keys within
49             the hash. The matching subnet with the longest mask (ie, the most
50             specific subnet) will win and its associated value will be returned.
51              
52             This code can be distributed freely according to the terms set forth
53             in the PERL license provided that proper credit is maintained. Please
54             send bug reports and feedback to the author for further improvement.
55              
56             =cut
57              
58 6     6   4638 use strict;
  6         11  
  6         223  
59 6     6   31 use vars qw($VERSION);
  6         11  
  6         252  
60 6     6   42 use Carp;
  6         10  
  6         433  
61 6     6   6097 use NetAddr::IP 3.00;
  6         227448  
  6         47  
62              
63             $VERSION = '1.51';
64              
65             sub new {
66 0     0 0 0 TIEHASH(shift);
67             }
68              
69             sub TIEHASH {
70 5     5   4150 my $class = shift;
71 5         12 my $self = [ ];
72 5         25 bless $self, $class;
73             }
74              
75             sub FETCH {
76 27     27   8368 my $self = shift;
77 27         43 my $where = shift;
78 27         96 my $ip = new NetAddr::IP $where;
79              
80 27 50       2619 if ($ip) {
81 27         7818 my @fles = reverse @$self;
82 27         52 for my $item (@fles) {
83 2103 100       4163 next unless ref $item;
84 1984         1798 for my $a (keys %{$item}) {
  1984         4756  
85 68 100       701 if ($item->{$a}->{where}->contains($ip)) {
86 26         606 return $item->{$a}->{what};
87             }
88             }
89             }
90             } else {
91 0         0 croak "$where is not a valid NetAddr::IP specification";
92             }
93              
94 1         8 return; # None of the networks matched the spec
95             }
96              
97             sub STORE {
98 23     23   2357 my $self = shift;
99 23         38 my $where = shift;
100 23         36 my $what = shift;
101 23         106 my $ip = new NetAddr::IP $where;
102              
103 23 50       2843 if ($ip) {
104 23         8797 $self->[$ip->masklen]->{$ip->addr} = {
105             where => $ip,
106             what => $what,
107             };
108             } else {
109 0         0 croak "$where is not a valid IP address specification";
110             }
111             }
112              
113             sub EXISTS {
114 2     2   14 my $self = shift;
115 2         4 my $where = shift;
116 2         8 my $ip = new NetAddr::IP $where;
117              
118 2 50       162 if ($ip) {
119 2         488 return exists $self->[$ip->masklen]->{$ip->addr};
120             } else {
121 0         0 croak "$where is not a valid NetAddr::IP specification";
122             }
123 0         0 return;
124             }
125              
126             sub DELETE {
127 5     5   742 my $self = shift;
128 5         28 my $where = shift;
129 5         28 my $ip = new NetAddr::IP $where;
130              
131 5 50       473 if ($ip) {
132 5         1404 my $mask = $ip->masklen;
133 5         67 my $addr = $ip->addr;
134              
135 5         669 return delete $self->[$mask]->{$addr};
136              
137             } else {
138 0         0 croak "$where is not a valid NetAddr::IP specification";
139             }
140 0         0 return;
141             }
142              
143             sub CLEAR {
144 2     2   1068 my $self = shift;
145 2         5 splice(@$self, 0, $#{$self});
  2         59  
146 2         8 return;
147             }
148              
149             sub NEXTKEY {
150 37     37   3574 my $self = shift;
151 37         46 my $last = shift;
152              
153 37 100       73 if (defined $last) {
154 27         96 my $l_ip = new NetAddr::IP $last;
155 27 50       2658 return undef unless $l_ip;
156              
157 27         10961 my $found = 0;
158              
159 27         142 for my $bits ($l_ip->masklen .. 128) {
160 1155         1611 for my $a (keys %{$self->[$bits]}) {
  1155         3445  
161 77 100 66     404 if ($a eq $l_ip->addr and $bits == $l_ip->masklen) {
162 27         4150 $found = 1;
163 27         83 next;
164             }
165 50 100       7720 if ($found) {
166 18         77 my $r = $self->[$bits]->{$a}->{where}->cidr;
167 18 50       2565 return wantarray ? ($r) : $r;
168             }
169             }
170             }
171             } else {
172 10         24 for my $bits (0 .. 128) {
173 162         162 for my $a (keys %{$self->[$bits]}) {
  162         424  
174 9         39 my $r = $self->[$bits]->{$a}->{where}->cidr;
175 9 50       1302 return wantarray ? ($r) : $r;
176             }
177             }
178            
179             }
180 10         64 return;
181             }
182              
183 10     10   1203 sub FIRSTKEY { NEXTKEY $_[0], undef; }
184              
185             1;
186              
187             __END__