line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package NetworkInfo::Discovery::Register; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
7004
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
31
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4531
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
NetworkInfo::Discovery::Register - Register of network information |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 SYNOPSIS |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use NetworkInfo::Discovery::Register; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# is like doing a $r->autosave(1) and $r->file("/tmp/the.register") |
15
|
|
|
|
|
|
|
my $r = new NetworkInfo::Discovery::Register(autosave=>1, file=>"/tmp/the.register"); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
$r->read_register(); # restore state from last save |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# ACLs allow us to remember only what we are allowed to |
20
|
|
|
|
|
|
|
$r->clear_acl; |
21
|
|
|
|
|
|
|
$r->add_acl("allow", "192.168.1.3/24"); # 192.168.1.3/24 gets converted to 192.168.1.0/24 |
22
|
|
|
|
|
|
|
$r->add_acl("deny", "0.0.0.0/0"); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
my $interface = { ip => '192.168.1.1', |
25
|
|
|
|
|
|
|
mac => 'aa:bb:cc:dd:ee:ff', |
26
|
|
|
|
|
|
|
mask => '255.255.255.0', # or 24 (as in prefix notation) |
27
|
|
|
|
|
|
|
dns => 'www.somehost.org', |
28
|
|
|
|
|
|
|
}; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
$r->add_interface($interface); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my $subnet = { ip => '192.168.1.0', # this is the network address |
33
|
|
|
|
|
|
|
mask => 24, # could also be '255.255.255.0' |
34
|
|
|
|
|
|
|
}; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
$r->add_subnet($subnet); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my $gateway = { ip => '192.168.1.254', |
39
|
|
|
|
|
|
|
mask => 24, |
40
|
|
|
|
|
|
|
mac => 'ff:ee:dd:cc:bb:aa', |
41
|
|
|
|
|
|
|
dns => 'router.somehost.org', |
42
|
|
|
|
|
|
|
}; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
$r->add_gateway($gateway); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
$r->write_register(); # save state for future restore |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 DESCRIPTION |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
C is a place to combine all that we have discovered about the network. |
51
|
|
|
|
|
|
|
As more information gets put in, the more corrolation we should see here. |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
For example, finding the netmask of an interface is not easy to do. |
54
|
|
|
|
|
|
|
If we happen to find a subnet from some source (say RIP, or an ICMP "Address Mask Request"), |
55
|
|
|
|
|
|
|
we may later see that those hosts with no netmask probably fit into the subnet. Once we are sure of this, |
56
|
|
|
|
|
|
|
we can add the netmask to the interfaces, and the interfaces into the subnet. |
57
|
|
|
|
|
|
|
By combining our knowledge in this manner, hopefully we discover more than we would by finding |
58
|
|
|
|
|
|
|
random bits of information. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
The register stores information about interfaces, gateways, and subnets. |
61
|
|
|
|
|
|
|
Each is a list of hashes in it's core, |
62
|
|
|
|
|
|
|
and thus has an extensible set of attributes that we can tag onto each object. |
63
|
|
|
|
|
|
|
With that said, the pieces of information that I am using for corrolation is as follows |
64
|
|
|
|
|
|
|
(a * denotes that an attribute is mandatory): |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
interface |
67
|
|
|
|
|
|
|
ip # * this is the ip address of the interface |
68
|
|
|
|
|
|
|
mac # * this is the ethernet MAC address of the interface |
69
|
|
|
|
|
|
|
mask # the network mask in prefix or dotted-quad format |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
subnet |
72
|
|
|
|
|
|
|
ip # * an ip address on the subnet |
73
|
|
|
|
|
|
|
mask # * the network mask in prefix or dotted-quad |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
gateway |
76
|
|
|
|
|
|
|
ip # * ip address of the interface that is this gateway |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
In this module we also provide for persistance using Storable. No one likes forgetting information, right? |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head1 METHODS |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=over 4 |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=item new |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=cut |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub new { |
89
|
0
|
|
|
0
|
1
|
|
my $proto = shift; |
90
|
0
|
|
|
|
|
|
my %args = @_; |
91
|
|
|
|
|
|
|
|
92
|
0
|
|
0
|
|
|
|
my $class = ref($proto) || $proto; |
93
|
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
|
my $self = { |
95
|
|
|
|
|
|
|
'subnets' => [], # list of host indexes. |
96
|
|
|
|
|
|
|
'gateways' => [], # list of host/subnet lists |
97
|
|
|
|
|
|
|
'interfaces'=> [], # list of things we know about an interface |
98
|
|
|
|
|
|
|
'events' => [], # three dogs and a biscut |
99
|
|
|
|
|
|
|
'mac2int' => {}, # lookup table for mac to interface |
100
|
|
|
|
|
|
|
'ip2int' => {}, # lookup table for ip to interface |
101
|
|
|
|
|
|
|
'file' => '', |
102
|
|
|
|
|
|
|
'autosave' => 0, |
103
|
|
|
|
|
|
|
'_acls' => [], |
104
|
|
|
|
|
|
|
}; |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
bless ($self, $class); |
107
|
|
|
|
|
|
|
|
108
|
0
|
0
|
|
|
|
|
$self->{'file'} = $args{file} if (exists $args{file}); |
109
|
0
|
0
|
|
|
|
|
$self->{'autosave'} = $args{autosave} if (exists $args{autosave}); |
110
|
|
|
|
|
|
|
|
111
|
0
|
0
|
0
|
|
|
|
if ($self->file && -r $self->file) { |
112
|
0
|
|
|
|
|
|
$self = $self->read_register( ); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# add a subnet to cover all hosts |
116
|
0
|
|
|
|
|
|
$self->add_subnet({ ip=>'0.0.0.0', mask=>0 }); |
117
|
0
|
|
|
|
|
|
return $self; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=pod |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=item add_interface ($interface_hashref) |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=cut |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub add_interface { |
127
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
128
|
0
|
|
|
|
|
|
my $args = &verify_args(shift); |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# we must have an ip or a mac |
131
|
0
|
0
|
0
|
|
|
|
return 0 unless ($args->{ip} or $args->{mac}); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# make sure we pass our ACLs |
134
|
0
|
0
|
|
|
|
|
return 0 unless ($self->test_acl($args->{ip})); |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# if the interface exists, update it |
137
|
0
|
0
|
|
|
|
|
if (my $int = $self->has_interface($args)) { |
138
|
0
|
|
|
|
|
|
return $self->update_interface($int, $args); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# set the creation date |
142
|
0
|
|
|
|
|
|
$args->{create_date} = time; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# add us to the interface list |
146
|
0
|
|
|
|
|
|
my $index = push (@{$self->{interfaces}}, $args); |
|
0
|
|
|
|
|
|
|
147
|
0
|
|
|
|
|
|
$index--; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# $self->add_event("add_interface: at index $index ip=>" . $args->{ip} . " mac=>" . $args->{mac} ); |
150
|
|
|
|
|
|
|
|
151
|
0
|
0
|
|
|
|
|
unless ( defined $args->{mask} ) { |
152
|
0
|
|
|
|
|
|
$args->{mask} = $self->guess_mask($args->{ip}); |
153
|
0
|
|
|
|
|
|
$args->{mask_prob} = .5; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
# if we have an ip and a mask, we know our subnet |
156
|
0
|
0
|
0
|
|
|
|
if ($args->{ip} and $args->{mask}) { |
157
|
0
|
|
|
|
|
|
my $net; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# create the subnet if it doesn't exist |
160
|
0
|
0
|
|
|
|
|
unless ($net = $self->has_subnet({ ip=>$args->{ip}, mask=>$args->{mask } }) ) { |
161
|
0
|
|
|
|
|
|
$net = $self->add_subnet({ ip=>$args->{ip}, mask=>$args->{mask } }); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# add this interface to the subnet |
165
|
0
|
|
|
|
|
|
$self->add_interface_to_subnet($index, $net); |
166
|
|
|
|
|
|
|
} else { |
167
|
|
|
|
|
|
|
# we don't have a mask, add us to the default subnet |
168
|
0
|
|
|
|
|
|
$self->add_interface_to_subnet($index, 0); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# index us by ip and by mac for fast lookups |
173
|
0
|
0
|
|
|
|
|
$self->{ip2int}->{$args->{ip}} = $index if $args->{ip}; |
174
|
0
|
0
|
|
|
|
|
$self->{mac2int}->{$args->{mac}} = $index if $args->{mac}; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# being careful about the "0th" index, return the index |
177
|
0
|
0
|
|
|
|
|
return "0 but true" if $index == 0; |
178
|
0
|
|
|
|
|
|
return $index; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=pod |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=item add_interface_to_subnet ($interface_index, $subnet_index) |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=cut |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub add_interface_to_subnet { |
188
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
189
|
|
|
|
|
|
|
# look out for "0 but true" |
190
|
0
|
|
|
|
|
|
my $interface = int(shift); |
191
|
0
|
|
|
|
|
|
my $subnet = int(shift); |
192
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
$self->add_event("add_interface_to_subnet interface=$interface, subnet=$subnet"); |
194
|
|
|
|
|
|
|
# add this interface to the subnet |
195
|
0
|
|
|
|
|
|
push (@{$self->{subnets}->[$subnet]->{interfaces} }, $interface); |
|
0
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# add a pointer to the subnet in the interface |
198
|
0
|
|
|
|
|
|
$self->{interfaces}->[$interface]->{subnet} = $subnet; |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=pod |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=item delete_interface ($interface_hashref) |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
This cuts an interface out of the interface list. |
207
|
|
|
|
|
|
|
To keep holes from forming in the list, |
208
|
|
|
|
|
|
|
take the last interface off the list and put it in place of the one we want to delete. |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Also, keep track of pointers to subnets and gateways, |
211
|
|
|
|
|
|
|
from subnets and gateways, |
212
|
|
|
|
|
|
|
and interface lookup tables. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
The special case is when we are the last interface in the list, and should just cut us out. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=cut |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub delete_interface { |
219
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
220
|
0
|
|
|
|
|
|
my $args = &verify_args(shift); |
221
|
|
|
|
|
|
|
|
222
|
0
|
0
|
0
|
|
|
|
return 0 unless ($args->{ip} or $args->{mac}); |
223
|
|
|
|
|
|
|
|
224
|
0
|
0
|
|
|
|
|
if ( my $interface_index = $self->has_interface($args) ){ |
225
|
0
|
|
|
|
|
|
$self->add_event("delete_interface: from index $interface_index"); |
226
|
|
|
|
|
|
|
# index to the last interface in the list |
227
|
0
|
|
|
|
|
|
my $last_index = $#{ $self->{interfaces} }; |
|
0
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# pop the last interface off |
230
|
0
|
|
|
|
|
|
my $last_interface = pop(@{$self->{interfaces}}); |
|
0
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# remove the indexes for the last_interface |
233
|
0
|
0
|
|
|
|
|
delete $self->{ip2int}->{$last_interface->{ip}} if exists $last_interface->{ip}; |
234
|
0
|
0
|
|
|
|
|
delete $self->{mac2int}->{$last_interface->{mac}} if exists $last_interface->{mac}; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# remove the last interface from any subnets and gateways |
237
|
0
|
0
|
|
|
|
|
$self->remove_interface_from_subnet($last_index, $last_interface->{subnet}) if (exists $last_interface->{subnet}); |
238
|
0
|
0
|
|
|
|
|
$self->remove_interface_from_gateway($last_index, $last_interface->{gateway}) if (exists $last_interface->{gateway}); |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# we are done if we happen to be the last interface |
241
|
0
|
0
|
|
|
|
|
return 1 if ($last_index == $interface_index) ; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
|
$self->add_event("delete_interface: swapping index $interface_index for $last_index"); |
245
|
|
|
|
|
|
|
# remove our interface, replace with the last one |
246
|
0
|
|
|
|
|
|
my $cut_interface = splice(@{$self->{interfaces}}, $interface_index, 1, $last_interface ); |
|
0
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# clear out the cut interface's indexs |
249
|
0
|
0
|
|
|
|
|
delete $self->{ip2int}->{$cut_interface->{ip}} if exists $cut_interface->{ip}; |
250
|
0
|
0
|
|
|
|
|
delete $self->{mac2int}->{$cut_interface->{mac}} if exists $cut_interface->{mac}; |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# remove the cut interface from any subnets and gateways |
253
|
0
|
0
|
|
|
|
|
$self->remove_interface_from_subnet($interface_index, $cut_interface->{subnet}) if (exists $cut_interface->{subnet}); |
254
|
0
|
0
|
|
|
|
|
$self->remove_interface_from_gateway($interface_index, $cut_interface->{gateway}) if (exists $cut_interface->{gateway}); |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# now update indexes for the last interface |
258
|
0
|
0
|
|
|
|
|
$self->{ip2int}->{$last_interface->{ip}} = $interface_index if $last_interface->{ip}; |
259
|
0
|
0
|
|
|
|
|
$self->{mac2int}->{$last_interface->{mac}} = $interface_index if $last_interface->{mac}; |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# finally, re-add the pointers to subnets and gateways |
262
|
0
|
0
|
|
|
|
|
$self->add_interface_to_subnet($interface_index, $last_interface->{subnet}) if (exists $last_interface->{subnet}); |
263
|
0
|
0
|
|
|
|
|
$self->add_interface_to_gateway($interface_index, $last_interface->{gateway}) if (exists $last_interface->{gateway}); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
0
|
|
|
|
|
|
return 1; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=pod |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=item add_interface_to_gateway ($interface_index, $gateway_index) |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=cut |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub add_interface_to_gateway { |
276
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
277
|
0
|
|
|
|
|
|
my $interface = int(shift); |
278
|
0
|
|
|
|
|
|
my $gateway = int(shift); |
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
|
$self->add_event("add_interface_to_gateway interface=$interface, gateway=$gateway"); |
281
|
|
|
|
|
|
|
# add us to the gateway |
282
|
0
|
|
|
|
|
|
push ( @{$self->{gateways}->[$gateway]->{interfaces} }, $interface); |
|
0
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
=pod |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=item remove_interface_from_gateway ($interface_index, $gateway_index) |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=cut |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub remove_interface_from_gateway { |
291
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
292
|
0
|
|
|
|
|
|
my $interface = int(shift); |
293
|
0
|
|
|
|
|
|
my $gateway = int(shift); |
294
|
|
|
|
|
|
|
|
295
|
0
|
|
|
|
|
|
$self->add_event("remove_interface_from_gateway: interface=$interface, gateway=$gateway"); |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
# remove us from any gateways |
298
|
0
|
|
|
|
|
|
@{$self->{gateways}->[$gateway]->{interfaces} } = grep { $_ != $interface } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
@{$self->{gateways}->[$gateway]->{interfaces} }; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=pod |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=item remove_interface_from_subnet ($interface_index, $subnet_index) |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=cut |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub remove_interface_from_subnet { |
309
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
310
|
0
|
|
|
|
|
|
my $interface = int(shift); |
311
|
0
|
|
|
|
|
|
my $subnet = int(shift); |
312
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
|
$self->add_event("remove_interface_from_subnet: interface=$interface, subnet=$subnet"); |
314
|
|
|
|
|
|
|
# remove us from any subnets |
315
|
0
|
|
|
|
|
|
@{$self->{subnets}->[$subnet]->{interfaces} } = |
|
0
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
|
grep { $_ != $interface } @{$self->{subnets}->[$subnet]->{interfaces} }; |
|
0
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# remove the pointer to the subnet from the interface |
319
|
0
|
0
|
|
|
|
|
delete $self->{interfaces}->[$interface]->{subnet} if exists $self->{interfaces}->[$interface]; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=pod |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=item has_interface($interface_hashref) |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=cut |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub has_interface { |
330
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
331
|
0
|
|
|
|
|
|
my $args = &verify_args(shift); |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
#no warnings; |
334
|
|
|
|
|
|
|
|
335
|
0
|
0
|
0
|
|
|
|
if (exists $args->{ip} and exists $self->{ip2int}->{$args->{ip}} ) { |
336
|
0
|
|
|
|
|
|
my $i = $self->{ip2int}->{$args->{ip}}; |
337
|
0
|
0
|
|
|
|
|
return "0 but true" if $i == 0; |
338
|
0
|
|
|
|
|
|
return $i; |
339
|
|
|
|
|
|
|
} |
340
|
0
|
0
|
0
|
|
|
|
if ( exists $args->{mac} and exists $self->{mac2int}->{$args->{mac}} ) { |
341
|
0
|
|
|
|
|
|
my $i = $self->{mac2int}->{$args->{mac}}; |
342
|
0
|
0
|
|
|
|
|
return "0 but true" if $i == 0; |
343
|
0
|
|
|
|
|
|
return $i; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
0
|
|
|
|
|
|
return 0; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
#sub has_interface { |
350
|
|
|
|
|
|
|
# my $self = shift; |
351
|
|
|
|
|
|
|
# my %args = &verify_args(@_); |
352
|
|
|
|
|
|
|
# |
353
|
|
|
|
|
|
|
# return 0 unless ($args{ip} or $args{mac}); |
354
|
|
|
|
|
|
|
# |
355
|
|
|
|
|
|
|
# no warnings; |
356
|
|
|
|
|
|
|
# for (my $i=0; $i < @{$self->{interfaces}}; $i++) { |
357
|
|
|
|
|
|
|
# if ( $self->{interfaces}->[$i]->{ip} eq $args{ip} |
358
|
|
|
|
|
|
|
# or $self->{interfaces}->[$i]->{mac} eq $args{mac} ) { |
359
|
|
|
|
|
|
|
# |
360
|
|
|
|
|
|
|
# return "0 but true" if $i == 0; |
361
|
|
|
|
|
|
|
# return $i; |
362
|
|
|
|
|
|
|
# } |
363
|
|
|
|
|
|
|
# } |
364
|
|
|
|
|
|
|
# |
365
|
|
|
|
|
|
|
# return 0; |
366
|
|
|
|
|
|
|
#} |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=pod |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=item update_interface($interface_hashref) |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=cut |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub update_interface { |
375
|
0
|
|
|
0
|
1
|
|
my $self=shift; |
376
|
0
|
|
|
|
|
|
my $interface = int(shift); |
377
|
0
|
|
|
|
|
|
my $args = &verify_args(shift); |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# this create our new interface based on the old one |
380
|
0
|
|
|
|
|
|
my %newint = %{$self->{interfaces}->[$interface]}; |
|
0
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# release old indexes |
383
|
0
|
0
|
|
|
|
|
delete $self->{ip2int}->{$newint{ip}} if $newint{ip}; |
384
|
0
|
0
|
|
|
|
|
delete $self->{mac2int}->{$newint{mac}} if $newint{mac}; |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
# then over write the old one with the passed args |
387
|
0
|
|
|
|
|
|
while (my ($k, $v) = each(%$args) ) { |
388
|
0
|
0
|
|
|
|
|
$v="" unless $v; |
389
|
0
|
0
|
|
|
|
|
$k="" unless $k; |
390
|
0
|
0
|
|
|
|
|
if (exists $newint{$k}) { |
391
|
0
|
0
|
0
|
|
|
|
if ($v and $newint{$k} ne $v) { |
392
|
|
|
|
|
|
|
# make an event here... |
393
|
|
|
|
|
|
|
#print "changed interface $interface key $k from $newint{$k} to $v\n"; |
394
|
0
|
|
|
|
|
|
$newint{$k} = $v; |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
} else { |
397
|
|
|
|
|
|
|
#print "left interface $interface alone for $k $newint{$k} == $v\n"; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
} else { |
400
|
|
|
|
|
|
|
#print "added key $k to interface $interface\n"; |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# finish moving the last interface into place |
405
|
0
|
|
|
|
|
|
$newint{update_date} = time; |
406
|
0
|
|
|
|
|
|
%{$self->{interfaces}->[$interface]} = %newint; |
|
0
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
# set new indexes |
409
|
0
|
0
|
|
|
|
|
$self->{ip2int}->{$newint{ip}} = $interface if $newint{ip}; |
410
|
0
|
0
|
|
|
|
|
$self->{mac2int}->{$newint{mac}} = $interface if $newint{mac}; |
411
|
|
|
|
|
|
|
|
412
|
0
|
0
|
|
|
|
|
return "0 but true" if $interface == 0; |
413
|
0
|
|
|
|
|
|
return $interface; |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=pod |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=item add_subnet($subnet_hashref) |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=cut |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
sub add_subnet { |
424
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
425
|
0
|
|
|
|
|
|
my $args = &verify_args(shift); |
426
|
|
|
|
|
|
|
|
427
|
0
|
0
|
0
|
|
|
|
return 0 unless ($args->{ip} and ($args->{mask} ne "")); |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# make sure we pass our ACLs |
430
|
0
|
0
|
|
|
|
|
return 0 unless ($self->test_acl($args->{ip})); |
431
|
|
|
|
|
|
|
|
432
|
0
|
|
|
|
|
|
my $index; |
433
|
|
|
|
|
|
|
# don't add the subnet unless it doesn't exist |
434
|
0
|
0
|
|
|
|
|
unless ($index = $self->has_subnet({ ip=>$args->{ip}, mask=>$args->{mask} } )) { |
435
|
|
|
|
|
|
|
# find our network address |
436
|
0
|
|
|
|
|
|
my $ip = unpack("N", pack("C4", split(/\./, $args->{ip}))); |
437
|
0
|
|
|
|
|
|
my $networknum = ($ip >> (32 - $args->{mask})) << (32 - $args->{mask}); |
438
|
|
|
|
|
|
|
|
439
|
0
|
|
|
|
|
|
$args->{ip} = join ('.', unpack( "C4", pack( "N", $networknum ) ) ); |
440
|
|
|
|
|
|
|
|
441
|
0
|
|
|
|
|
|
$args->{create_date} = time; |
442
|
|
|
|
|
|
|
# print "add_subnet \n"; |
443
|
|
|
|
|
|
|
# while (my ($k,$v) = each (%$args)){ print " $k=>$v\n"; } |
444
|
0
|
|
|
|
|
|
$index = push (@{$self->{subnets}}, $args); |
|
0
|
|
|
|
|
|
|
445
|
0
|
|
|
|
|
|
$index--; |
446
|
0
|
|
|
|
|
|
$self->add_event("added subnet " . $args->{ip} . " at index $index"); |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
} |
449
|
0
|
0
|
|
|
|
|
return "0 but true" if $index == 0; |
450
|
0
|
|
|
|
|
|
return $index; |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=pod |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=item has_subnet($subnet_hashref) |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=cut |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub has_subnet { |
460
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
461
|
0
|
|
|
|
|
|
my $args = &verify_args(shift); |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
# print "has_subnet: just entering, ip=>" . $args->{ip} . " mask=>". $args->{mask} . "\n"; |
464
|
0
|
0
|
0
|
|
|
|
return 0 unless ($args->{ip} and $args->{mask} ne ""); |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# find our network address |
467
|
0
|
|
|
|
|
|
my $ip = unpack("N", pack("C4", split(/\./, $args->{ip}))); |
468
|
0
|
|
|
|
|
|
my $networknum = ($ip >> (32 - $args->{mask})) << (32 - $args->{mask}); |
469
|
0
|
|
|
|
|
|
$args->{ip} = join ('.', unpack( "C4", pack( "N", $networknum ) ) ); |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
|
472
|
0
|
|
|
|
|
|
for (my $i=0; $i < @{$self->{subnets}}; $i++) { |
|
0
|
|
|
|
|
|
|
473
|
0
|
0
|
0
|
|
|
|
if ($self->{subnets}->[$i]->{ip} eq $args->{ip} |
474
|
|
|
|
|
|
|
and $self->{subnets}->[$i]->{mask} eq $args->{mask} ) { |
475
|
0
|
0
|
|
|
|
|
return "0 but true" if $i == 0; |
476
|
0
|
|
|
|
|
|
return $i; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
0
|
|
|
|
|
|
return 0; |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
########## |
484
|
|
|
|
|
|
|
## Gateway stuff... |
485
|
|
|
|
|
|
|
################### |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=pod |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=item add_gateway($gateway_hashref) |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=cut |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
sub add_gateway { |
494
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
495
|
0
|
|
|
|
|
|
my $args = &verify_args(shift); |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# must have at least an ip |
498
|
0
|
0
|
|
|
|
|
return 0 unless ($args->{ip}); |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# make sure we pass our ACLs |
501
|
0
|
0
|
|
|
|
|
return 0 unless ($self->test_acl($args->{ip})); |
502
|
|
|
|
|
|
|
|
503
|
0
|
|
|
|
|
|
my $gwindex; |
504
|
0
|
0
|
|
|
|
|
if ($gwindex = $self->has_gateway($args)) { |
505
|
|
|
|
|
|
|
# update the gateway... |
506
|
|
|
|
|
|
|
} else { |
507
|
0
|
|
|
|
|
|
$gwindex = @{ $self->{gateways} }; |
|
0
|
|
|
|
|
|
|
508
|
0
|
|
|
|
|
|
$args->{gateway} = $gwindex; |
509
|
|
|
|
|
|
|
|
510
|
0
|
|
|
|
|
|
my $interfaceindex; |
511
|
0
|
0
|
|
|
|
|
if ($interfaceindex = $self->has_interface($args)) { |
512
|
0
|
|
|
|
|
|
$self->update_interface($interfaceindex, $args); |
513
|
|
|
|
|
|
|
} else { |
514
|
0
|
|
|
|
|
|
$interfaceindex = $self->add_interface($args); |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
0
|
|
|
|
|
|
my $gw; |
518
|
0
|
|
|
|
|
|
push(@{ $gw->{interfaces} }, $interfaceindex); |
|
0
|
|
|
|
|
|
|
519
|
0
|
|
|
|
|
|
push(@{ $gw->{subnets} }, $self->{interfaces}->[$interfaceindex]->{subnet}); |
|
0
|
|
|
|
|
|
|
520
|
0
|
|
|
|
|
|
push(@{ $self->{gateways} }, $gw); |
|
0
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
} |
522
|
0
|
0
|
|
|
|
|
return "0 but true" if $gwindex == 0; |
523
|
0
|
|
|
|
|
|
return $gwindex; |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=pod |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=item has_gateway($gateway_hashref) |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=cut |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub has_gateway { |
534
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
535
|
0
|
|
|
|
|
|
my $args = &verify_args(shift); |
536
|
|
|
|
|
|
|
|
537
|
0
|
0
|
|
|
|
|
return 0 unless ($args->{ip}); |
538
|
|
|
|
|
|
|
|
539
|
0
|
|
|
|
|
|
for (my $i=0; $i < @{$self->{gateways}}; $i++) { |
|
0
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
# if one of the gatway interfaces matches our ip |
541
|
0
|
0
|
|
|
|
|
if ( grep { $self->{interfaces}->[$_]->{ip} eq $args->{ip} } @{ $self->{gateways}->[$i]->{interfaces} } ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
542
|
0
|
0
|
|
|
|
|
return "0 but true" if $i == 0; |
543
|
0
|
|
|
|
|
|
return $i; |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
} |
546
|
0
|
|
|
|
|
|
return 0; |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=pod |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=item verify_args($hashref) |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
internal only |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=cut |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub verify_args{ |
558
|
0
|
|
|
0
|
1
|
|
my $args = shift; |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
# print "got: " . join(',',keys(%$args)) . "\n"; |
561
|
0
|
0
|
0
|
|
|
|
if (exists $args->{ip} and $args->{ip} ) { |
562
|
0
|
0
|
|
|
|
|
return unless $args->{ip} =~ m!^\d+\.\d+\.\d+\.\d+!; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
0
|
0
|
0
|
|
|
|
if ( exists $args->{mask} and $args->{mask} ne "") { |
566
|
0
|
0
|
|
|
|
|
return unless $args->{mask} =~ m#^(?:\d+|\d+\.\d+\.\d+\.\d+)$#; |
567
|
0
|
|
|
|
|
|
$args->{mask} = _mask2bits($args->{mask}); |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
|
570
|
0
|
0
|
0
|
|
|
|
if (exists $args->{mac} and $args->{mac}){ |
571
|
0
|
0
|
|
|
|
|
return unless $args->{mac} =~ m!^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}!; |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
|
574
|
0
|
|
|
|
|
|
return $args; |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
=pod |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=item verify_structure |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
internal only. |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=cut |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
sub verify_structure { |
586
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
# make sure interfaces are logical |
589
|
0
|
|
|
|
|
|
my $i=0; |
590
|
0
|
|
|
|
|
|
foreach my $int ( @{ $self->{interfaces} } ) { |
|
0
|
|
|
|
|
|
|
591
|
0
|
0
|
|
|
|
|
if (exists $int->{subnet}) { |
592
|
0
|
0
|
|
|
|
|
unless (grep {$_ == $i} @{$self->{subnets}->[$int->{subnet}]->{interfaces} } ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
593
|
0
|
|
|
|
|
|
warn ("interface $i has subnet " . $int->{subnet} . " but subnet " . $int->{subnet} . " only has nterfaces [ " . join(', ',@{$self->{subnets}->[$int->{subnet}]->{interfaces} } ) . " ]\n"); |
|
0
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
} |
596
|
0
|
|
|
|
|
|
$i++; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
# make sure subnets are logical |
600
|
0
|
|
|
|
|
|
$i=0; |
601
|
0
|
|
|
|
|
|
foreach my $net ( @{ $self->{subnets} } ) { |
|
0
|
|
|
|
|
|
|
602
|
0
|
0
|
|
|
|
|
if (exists $net->{interfaces}) { |
603
|
0
|
|
|
|
|
|
foreach my $int (@{ $net->{interfaces} } ) { |
|
0
|
|
|
|
|
|
|
604
|
0
|
0
|
|
|
|
|
unless ($self->{interfaces}->[$int]->{subnet} eq $i) { |
605
|
0
|
|
|
|
|
|
warn ("subnet $i has interface $int but interface $i has subnet " . $self->{interfaces}->[$int]->{subnet} . "\n" ); |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
} |
609
|
0
|
|
|
|
|
|
$i++; |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
sub _mask2bits { |
614
|
0
|
|
|
0
|
|
|
my $mask = shift; |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
# if the mask is like 255.255.255.0, make it into 24 |
617
|
0
|
0
|
|
|
|
|
if ($mask =~ m!^\d+\.\d+\.\d+\.\d+!) { |
618
|
0
|
|
|
|
|
|
my $mask_bits=unpack("B32", pack("C4", split(/\./, $mask))); |
619
|
0
|
|
|
|
|
|
$mask=length( (split(/0/,$mask_bits,2))[0] ); |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
|
622
|
0
|
|
|
|
|
|
return $mask; |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
sub _bits2mask { |
625
|
0
|
|
|
0
|
|
|
my $mask = shift; |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
# if the mask is like 24 make it into 255.255.255.0 |
628
|
0
|
0
|
|
|
|
|
if ($mask =~ m/^\d+$/) { |
629
|
0
|
|
|
|
|
|
$mask = pack('B32', 1 x $mask . 0 x (32-$mask)); |
630
|
|
|
|
|
|
|
|
631
|
0
|
|
|
|
|
|
$mask= join (".", unpack("C4", $mask) ); |
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
|
634
|
0
|
|
|
|
|
|
return $mask; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
sub _ip2int { |
638
|
0
|
|
|
0
|
|
|
my $ip = shift; |
639
|
|
|
|
|
|
|
|
640
|
0
|
0
|
|
|
|
|
if ($ip =~ m!^\d+\.\d+\.\d+\.\d+!) { |
641
|
0
|
|
|
|
|
|
$ip=unpack("N", pack("C4", split(/\./, $ip))); |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
|
644
|
0
|
|
|
|
|
|
return $ip; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
=pod |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=item print_register |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
prints the formated register to STDOUT |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=cut |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
sub print_register { |
657
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
658
|
|
|
|
|
|
|
|
659
|
0
|
|
|
|
|
|
require Data::Dumper; |
660
|
0
|
|
|
|
|
|
print Data::Dumper->Dump([$self], [qw(self)]); |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
sub dump_us { |
663
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
664
|
|
|
|
|
|
|
|
665
|
0
|
|
|
|
|
|
require Data::Dumper; |
666
|
0
|
|
|
|
|
|
print Data::Dumper->Dump([$self], [qw(self)]); |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=pod |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=item read_register ([$filename]) |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
tries to read the register from a file. |
675
|
|
|
|
|
|
|
if $filename is not give., tries to use what was set at creation |
676
|
|
|
|
|
|
|
of this object. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=cut |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
sub read_register { |
681
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
682
|
0
|
|
|
|
|
|
my $file; |
683
|
|
|
|
|
|
|
|
684
|
0
|
0
|
|
|
|
|
if (@_) { |
|
|
0
|
|
|
|
|
|
685
|
0
|
|
|
|
|
|
$file = shift; |
686
|
|
|
|
|
|
|
} elsif ( $self->file ) { |
687
|
0
|
|
|
|
|
|
$file = $self->file; |
688
|
|
|
|
|
|
|
} else { |
689
|
0
|
|
|
|
|
|
return undef; |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
|
692
|
0
|
|
|
|
|
|
require Storable; |
693
|
|
|
|
|
|
|
|
694
|
0
|
|
|
|
|
|
$self = Storable::retrieve($file); |
695
|
0
|
|
|
|
|
|
$self->{restored} = time; |
696
|
0
|
|
|
|
|
|
$self->file($file); |
697
|
|
|
|
|
|
|
|
698
|
0
|
|
|
|
|
|
return $self; |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=pod |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=item write_register ([$filename]) |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
stores the register in $filename. |
706
|
|
|
|
|
|
|
if $filename is not given, tries to use what was set at creation |
707
|
|
|
|
|
|
|
of this object. |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=cut |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
sub write_register { |
712
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
713
|
0
|
|
|
|
|
|
my $file; |
714
|
|
|
|
|
|
|
|
715
|
0
|
0
|
|
|
|
|
if (@_) { |
|
|
0
|
|
|
|
|
|
716
|
0
|
|
|
|
|
|
$file = shift; |
717
|
|
|
|
|
|
|
} elsif ( $self->file ) { |
718
|
0
|
|
|
|
|
|
$file = $self->file; |
719
|
|
|
|
|
|
|
} else { |
720
|
0
|
|
|
|
|
|
return undef; |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
|
723
|
0
|
|
|
|
|
|
require Storable; |
724
|
0
|
|
|
|
|
|
Storable::nstore($self, $file); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=pod |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=item file ([ $filename ]) |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
get/set the file to store data in |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
=cut |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
sub file { |
736
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
737
|
0
|
0
|
|
|
|
|
$self->{'file'} = shift if (@_) ; |
738
|
0
|
|
|
|
|
|
return $self->{'file'}; |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
=pod |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
=item autosave |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
get/set auto save. pass this a "1" to turn on, a "0" to turn off. |
746
|
|
|
|
|
|
|
Autosave means that we will try to save the register to our "file" before |
747
|
|
|
|
|
|
|
we exit. |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
=cut |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
sub autosave { |
752
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
753
|
0
|
0
|
|
|
|
|
$self->{'autosave'} = shift if (@_) ; |
754
|
0
|
|
|
|
|
|
return $self->{'autosave'}; |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
=pod |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
=item test_acl ($ip_to_test) |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
$ip_to_test is the ip addresse you want to check against the acl list set using add_acl. |
762
|
|
|
|
|
|
|
it should be in the form "a.b.c.d". |
763
|
|
|
|
|
|
|
we return as soon as we find a matching rule that says allow or deny. |
764
|
|
|
|
|
|
|
we return 1 to accept it, 0 to deny it. |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=cut |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
#sub test_acl { |
769
|
|
|
|
|
|
|
# my ($self, $ip) = @_; |
770
|
|
|
|
|
|
|
# |
771
|
|
|
|
|
|
|
# # this is just for kicks... lets up pass in a host obj |
772
|
|
|
|
|
|
|
# if (ref($ip) =~ m/^NetworkInfo::Discovery::Host/) { |
773
|
|
|
|
|
|
|
# $ip = $ip->ipaddress; |
774
|
|
|
|
|
|
|
# } |
775
|
|
|
|
|
|
|
# # check it against each acl and try to buffer calls to the matcher |
776
|
|
|
|
|
|
|
# my $lastAorD = "allow"; |
777
|
|
|
|
|
|
|
# my @buffered_ips; |
778
|
|
|
|
|
|
|
# |
779
|
|
|
|
|
|
|
# print "checking acls against $ip\n"; |
780
|
|
|
|
|
|
|
# foreach (@{$self->{'_acls'}}) { |
781
|
|
|
|
|
|
|
# print "____:$_\n"; |
782
|
|
|
|
|
|
|
# |
783
|
|
|
|
|
|
|
# m!^(allow|deny):(.*)!; |
784
|
|
|
|
|
|
|
# |
785
|
|
|
|
|
|
|
# # if this is the same type that we saw last time, |
786
|
|
|
|
|
|
|
# if ($lastAorD eq $1) { |
787
|
|
|
|
|
|
|
# # save it and keep going |
788
|
|
|
|
|
|
|
# push(@buffered_ips, $2); |
789
|
|
|
|
|
|
|
# next; |
790
|
|
|
|
|
|
|
# } |
791
|
|
|
|
|
|
|
# |
792
|
|
|
|
|
|
|
# # otherwise, this is a change so |
793
|
|
|
|
|
|
|
# # check what we have buffered |
794
|
|
|
|
|
|
|
# if (@buffered_ips) { |
795
|
|
|
|
|
|
|
# #we are supposed to allow these... |
796
|
|
|
|
|
|
|
# if ($lastAorD eq "allow") { |
797
|
|
|
|
|
|
|
# # return 1 to if we found an allow |
798
|
|
|
|
|
|
|
# print "calling return 1 if ($self->acl_match($ip, @buffered_ips))\n"; |
799
|
|
|
|
|
|
|
# return 1 if ($self->acl_match($ip, @buffered_ips)); |
800
|
|
|
|
|
|
|
# |
801
|
|
|
|
|
|
|
# #we are supposed to deny these... |
802
|
|
|
|
|
|
|
# } else { |
803
|
|
|
|
|
|
|
# # return 0 to if we found a deny match |
804
|
|
|
|
|
|
|
# print "calling return 0 if ($self->acl_match($ip, @buffered_ips))\n"; |
805
|
|
|
|
|
|
|
# return 0 if ($self->acl_match($ip, @buffered_ips)); |
806
|
|
|
|
|
|
|
# } |
807
|
|
|
|
|
|
|
# |
808
|
|
|
|
|
|
|
# # we are done with the buffer, clen it out |
809
|
|
|
|
|
|
|
# @buffered_ips=(); |
810
|
|
|
|
|
|
|
# } |
811
|
|
|
|
|
|
|
# |
812
|
|
|
|
|
|
|
# |
813
|
|
|
|
|
|
|
# # save what we have now |
814
|
|
|
|
|
|
|
# push(@buffered_ips, $2); |
815
|
|
|
|
|
|
|
# # don't forget where we've been |
816
|
|
|
|
|
|
|
# $lastAorD = $1; |
817
|
|
|
|
|
|
|
# |
818
|
|
|
|
|
|
|
# #thanks. may i have another? |
819
|
|
|
|
|
|
|
# } |
820
|
|
|
|
|
|
|
#} |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
sub test_acl { |
823
|
0
|
|
|
0
|
1
|
|
my ($self, $ip) = @_; |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
# print "checking acls against $ip\n"; |
826
|
0
|
|
|
|
|
|
foreach (@{$self->{'_acls'}}) { |
|
0
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
# print "____:$_\n"; |
828
|
0
|
|
|
|
|
|
m!^(allow|deny):(.*)!; |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
#we are supposed to allow these... |
831
|
0
|
0
|
|
|
|
|
if ($1 eq "allow") { |
832
|
|
|
|
|
|
|
# return 1 to if we found an allow |
833
|
|
|
|
|
|
|
# print "calling return 1 if ($self->acl_match($ip, $2))\n"; |
834
|
0
|
0
|
|
|
|
|
return 1 if ($self->acl_match($ip, $2)); |
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
#we are supposed to deny these... |
837
|
|
|
|
|
|
|
} else { |
838
|
|
|
|
|
|
|
# return 0 to if we found a deny match |
839
|
|
|
|
|
|
|
# print "calling return 0 if ($self->acl_match($ip, $2))\n"; |
840
|
0
|
0
|
|
|
|
|
return 0 if ($self->acl_match($ip, $2)); |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
#if we passed all of the above, we must not have an acl for this ip |
844
|
0
|
|
|
|
|
|
return 1; |
845
|
|
|
|
|
|
|
} |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
=pod |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=item acl_match ($ip_to_test, @against_these) |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
ip is like 172.16.20.4 |
852
|
|
|
|
|
|
|
the acls are either in CIDR notation "172.16.4.12/25" or a single address |
853
|
|
|
|
|
|
|
returns true if the ip matches the acl. |
854
|
|
|
|
|
|
|
returns false otherwise |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
=cut |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
sub acl_match { |
859
|
0
|
|
|
0
|
1
|
|
my ($self, $ip, @others) = @_; |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
# get our ip in machine representation |
862
|
0
|
|
|
|
|
|
my $mainIP = unpack("N", pack("C4", split(/\./, $ip))); |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
# for all the acls |
865
|
0
|
|
|
|
|
|
foreach (@others) { |
866
|
|
|
|
|
|
|
# split off the CIDR mask if there is one |
867
|
0
|
|
|
|
|
|
m!^(\d+\.\d+\.\d+\.\d+)(?:/(\d+))?!g; |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
# 0.0.0.0/0 matches all |
870
|
0
|
0
|
0
|
|
|
|
if (($1 eq "0.0.0.0") and ($2 eq 0)) { |
871
|
0
|
|
|
|
|
|
return 1; |
872
|
|
|
|
|
|
|
} |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
# what is left over from the mask |
875
|
0
|
|
0
|
|
|
|
my $bits = 32 - ($2 || 32); |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
# put this acl into machine representation |
878
|
0
|
|
|
|
|
|
my $otherIP = unpack("N", pack("C4", split(/\./, $1))); |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
# keep only the important parts of the ip address/mask pair |
881
|
0
|
|
|
|
|
|
my $maskedIP = $otherIP >> $bits; |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
# if there was a CIDR mask |
884
|
0
|
0
|
|
|
|
|
if ($bits) { |
885
|
|
|
|
|
|
|
# return true if this one matches |
886
|
|
|
|
|
|
|
#print "bits->$bits, maskedIP->$maskedIP, mainIP->" . ($mainIP>>$bits) . "\n"; |
887
|
0
|
0
|
|
|
|
|
return 1 if ($maskedIP == ($mainIP >> $bits)); |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
} else { |
890
|
|
|
|
|
|
|
# return true if this one matches (without mask) |
891
|
0
|
|
|
|
|
|
print "bits->$bits, maskedIP->$maskedIP, mainIP->$mainIP\n"; |
892
|
0
|
0
|
|
|
|
|
return 1 if ($maskedIP == $mainIP); |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
} |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
# return false if we didn't match any acl |
897
|
0
|
|
|
|
|
|
return 0; |
898
|
|
|
|
|
|
|
} |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
=pod |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
=item add_acl ("(allow|deny)", @acls) |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
this function sets a list of hosts/networks that we are allowed to discover. |
905
|
|
|
|
|
|
|
note that order matters. |
906
|
|
|
|
|
|
|
the first argument is set to allow or deny. the meaning should be clear. |
907
|
|
|
|
|
|
|
@acls is a list of ip addresses in the form: |
908
|
|
|
|
|
|
|
a.b.c.d/mask # to acl a whole network |
909
|
|
|
|
|
|
|
or |
910
|
|
|
|
|
|
|
a.b.c.d # to acl a host |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
the following calls will allow us to discover stuff on only the network 172.16.1.0/24: |
913
|
|
|
|
|
|
|
$d->add_acl("allow", "172.16.1.0/24"); |
914
|
|
|
|
|
|
|
$d->add_acl("deny", "0.0.0.0/0"); |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
the following calls will allow us to discover anything but stuff on network 172.16.1.0/24: |
917
|
|
|
|
|
|
|
$d->add_acl("deny", "172.16.1.0/24"); |
918
|
|
|
|
|
|
|
$d->add_acl("allow", "0.0.0.0/0"); |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
=cut |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
sub add_acl { |
923
|
0
|
|
|
0
|
1
|
|
my ($self,$AorD, @acls) = @_; |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
# only accept this if we have valid allow or deny rules. |
926
|
0
|
0
|
|
|
|
|
return undef unless ($AorD =~ m/(allow|deny)/); |
927
|
|
|
|
|
|
|
|
928
|
0
|
|
|
|
|
|
foreach my $a (@acls) { |
929
|
|
|
|
|
|
|
# only accept this if we have addresses like "a.b.c.d" or "a.b.c.d/n" |
930
|
0
|
0
|
|
|
|
|
return undef unless($a =~ m!^\d+\.\d+\.\d+\.\d+(?:/\d+)?!); |
931
|
|
|
|
|
|
|
|
932
|
0
|
|
|
|
|
|
push (@{$self->{"_acls"}}, "$AorD:$a"); |
|
0
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
} |
934
|
0
|
|
|
|
|
|
return 1; |
935
|
|
|
|
|
|
|
} |
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=pod |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
=item clear_acl |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
this function clears the acl list |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
=cut |
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
sub clear_acl { |
946
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
947
|
0
|
|
|
|
|
|
@{$self->{"_acls"}} = (); |
|
0
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
=pod |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
=item guess_mask ($ip) |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
attempt to guess the mask based on the ip. |
955
|
|
|
|
|
|
|
returns the guessed mask |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
=cut |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
sub guess_mask { |
960
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
961
|
0
|
|
|
|
|
|
my $ip = shift; |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
# see how many ones lead the ipaddress |
964
|
0
|
|
|
|
|
|
my $bits = _mask2bits($ip); |
965
|
0
|
|
|
|
|
|
my $mask = 0; |
966
|
|
|
|
|
|
|
|
967
|
0
|
0
|
|
|
|
|
if ($bits eq 0) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
968
|
|
|
|
|
|
|
# class a address |
969
|
0
|
|
|
|
|
|
$mask = "255.0.0.0"; |
970
|
|
|
|
|
|
|
} elsif ( $bits eq 1 ) { |
971
|
|
|
|
|
|
|
# class B address |
972
|
0
|
|
|
|
|
|
$mask = "255.255.0.0"; |
973
|
|
|
|
|
|
|
} elsif ( $bits eq 2 ) { |
974
|
|
|
|
|
|
|
# class C address |
975
|
0
|
|
|
|
|
|
$mask = "255.255.255.0"; |
976
|
|
|
|
|
|
|
} |
977
|
0
|
|
|
|
|
|
return $mask; |
978
|
|
|
|
|
|
|
} |
979
|
|
|
|
|
|
|
=pod |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
=item add_event ("string") |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
add an event to the log |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
=cut |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
sub add_event { |
988
|
0
|
|
|
0
|
1
|
|
my $self=shift; |
989
|
|
|
|
|
|
|
|
990
|
0
|
|
|
|
|
|
my $msg = time . " " . join(",",@_); |
991
|
|
|
|
|
|
|
|
992
|
0
|
|
|
|
|
|
push(@{$self->{events}}, $msg); |
|
0
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
} |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
=pod |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
=item DESTROY |
998
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
just tries to write_register if we have autosave turned on |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
=cut |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
sub DESTROY { |
1004
|
0
|
|
|
0
|
|
|
my $self=shift; |
1005
|
0
|
0
|
|
|
|
|
$self->write_register() if ($self->autosave); |
1006
|
|
|
|
|
|
|
} |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
=pod |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
=back |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
=cut |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
1; |