line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Device::OUI; |
2
|
9
|
|
|
9
|
|
418808
|
use strict; use warnings; |
|
9
|
|
|
9
|
|
21
|
|
|
9
|
|
|
|
|
372
|
|
|
9
|
|
|
|
|
51
|
|
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
383
|
|
3
|
|
|
|
|
|
|
our $VERSION = '1.04'; |
4
|
9
|
|
|
9
|
|
8490
|
use IO::File (); |
|
9
|
|
|
|
|
2147267
|
|
|
9
|
|
|
|
|
279
|
|
5
|
9
|
|
|
9
|
|
81
|
use Carp qw( croak carp ); |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
484
|
|
6
|
9
|
|
|
9
|
|
9665
|
use AnyDBM_File; |
|
9
|
|
|
|
|
68074
|
|
|
9
|
|
|
|
|
936
|
|
7
|
|
|
|
|
|
|
use overload ( |
8
|
9
|
|
|
|
|
81
|
'<=>' => 'overload_cmp', |
9
|
|
|
|
|
|
|
'cmp' => 'overload_cmp', |
10
|
|
|
|
|
|
|
'""' => 'normalized', |
11
|
|
|
|
|
|
|
fallback => 1, |
12
|
9
|
|
|
9
|
|
5547
|
); |
|
9
|
|
|
|
|
3509
|
|
13
|
9
|
|
|
9
|
|
1094
|
use base qw( Class::Accessor::Grouped ); |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
20621
|
|
14
|
9
|
|
|
|
|
126
|
use Sub::Exporter -setup => { |
15
|
|
|
|
|
|
|
exports => [qw( normalize_oui oui_cmp parse_oui_entry oui_to_integers )], |
16
|
9
|
|
|
9
|
|
1678681
|
}; |
|
9
|
|
|
|
|
145527
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
__PACKAGE__->mk_group_accessors( inherited => qw( |
19
|
|
|
|
|
|
|
cache_db cache_file |
20
|
|
|
|
|
|
|
file_url search_url |
21
|
|
|
|
|
|
|
) ); |
22
|
|
|
|
|
|
|
my $cache = $^O eq 'MSWin32' ? 'C:\device_oui' : '/var/cache/device_oui'; |
23
|
|
|
|
|
|
|
__PACKAGE__->cache_db( $cache ); |
24
|
|
|
|
|
|
|
__PACKAGE__->cache_file( $cache . '.txt' ); |
25
|
|
|
|
|
|
|
__PACKAGE__->search_url( 'http://standards.ieee.org/cgi-bin/ouisearch?%s' ); |
26
|
|
|
|
|
|
|
__PACKAGE__->file_url( 'http://standards.ieee.org/regauth/oui/oui.txt' ); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub cache_handle { |
29
|
89
|
|
|
89
|
1
|
2597
|
my $self = shift; |
30
|
|
|
|
|
|
|
|
31
|
89
|
100
|
|
|
|
206
|
if ( @_ ) { $self->set_inherited( 'cache_handle', @_ ) } |
|
2
|
|
|
|
|
11
|
|
32
|
89
|
|
|
|
|
365
|
my $handle = $self->get_inherited( 'cache_handle' ); |
33
|
89
|
100
|
|
|
|
1909
|
if ( $handle ) { return $handle } |
|
72
|
|
|
|
|
256
|
|
34
|
17
|
|
|
|
|
44
|
$handle = {}; |
35
|
17
|
100
|
|
|
|
566
|
if ( my $db = $self->cache_db ) { |
36
|
8
|
|
|
|
|
182
|
my $opts = Fcntl::O_RDWR | Fcntl::O_CREAT; |
37
|
8
|
|
|
|
|
14
|
my %cache; |
38
|
8
|
100
|
|
|
|
1910
|
if ( tie( %cache, 'AnyDBM_File', $db, $opts, 0666 ) ) { ## no critic |
39
|
7
|
|
|
|
|
17
|
$handle = \%cache; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
} |
42
|
17
|
|
|
|
|
492
|
$self->set_inherited( 'cache_handle', $handle ); |
43
|
17
|
|
|
|
|
291
|
return $handle; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub cache { |
47
|
77
|
|
|
77
|
1
|
6582
|
my $self = shift; |
48
|
77
|
100
|
100
|
|
|
428
|
my $oui = ( @_ && not ref $_[0] ) ? shift : $self->norm; |
49
|
|
|
|
|
|
|
|
50
|
77
|
|
|
|
|
186
|
my $handle = $self->cache_handle; |
51
|
|
|
|
|
|
|
|
52
|
77
|
100
|
|
|
|
355
|
if ( @_ ) { |
|
|
100
|
|
|
|
|
|
53
|
53
|
|
|
|
|
62
|
my %hash = %{ shift() }; |
|
53
|
|
|
|
|
324
|
|
54
|
53
|
|
|
|
|
156
|
for my $x ( keys %hash ) { |
55
|
186
|
100
|
|
|
|
522
|
if ( not defined $hash{ $x } ) { $hash{ $x } = '' } |
|
1
|
|
|
|
|
3
|
|
56
|
|
|
|
|
|
|
} |
57
|
53
|
|
|
|
|
1310
|
return $handle->{ $oui } = join( "\0", %hash ); |
58
|
|
|
|
|
|
|
} elsif ( my $x = $handle->{ $oui } ) { |
59
|
13
|
|
|
|
|
224
|
return { split( "\0", $x ) }; |
60
|
|
|
|
|
|
|
} |
61
|
11
|
|
|
|
|
43
|
return; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub new { |
65
|
98
|
|
|
98
|
1
|
49984
|
my $self = bless( {}, shift ); |
66
|
98
|
100
|
|
|
|
799
|
$self->oui( shift ) if @_; |
67
|
97
|
|
|
|
|
399
|
return $self; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub oui { |
71
|
102
|
|
|
102
|
1
|
2634
|
my $self = shift; |
72
|
|
|
|
|
|
|
|
73
|
102
|
100
|
|
|
|
335
|
if ( @_ ) { |
74
|
96
|
|
|
|
|
120
|
my $oui = shift; |
75
|
96
|
100
|
|
|
|
196
|
if ( my $norm = normalize_oui( $oui ) ) { |
76
|
95
|
|
|
|
|
817
|
$self->{ 'oui' } = $oui; |
77
|
95
|
|
|
|
|
159
|
$self->{ 'oui_norm' } = $norm; |
78
|
95
|
|
|
|
|
192
|
delete $self->{ 'lookup' }; |
79
|
|
|
|
|
|
|
} else { |
80
|
1
|
|
|
|
|
39
|
croak "Invalid OUI format: $oui"; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
101
|
100
|
|
|
|
383
|
if ( not $self->{ 'oui' } ) { croak "Object does not have an OUI" } |
|
1
|
|
|
|
|
21
|
|
85
|
|
|
|
|
|
|
|
86
|
100
|
|
|
|
|
193
|
return $self->{ 'oui' }; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub oui_to_integers { |
90
|
5159
|
|
100
|
5159
|
1
|
14226
|
my $oui = shift || return; |
91
|
|
|
|
|
|
|
|
92
|
5153
|
100
|
|
|
|
11605
|
if ( ref $oui ) { return map { hex } split( '-', $oui->norm ) } |
|
292
|
|
|
|
|
764
|
|
|
876
|
|
|
|
|
1783
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# 00-06-2A or 0:6:2a, etc. any non-hex delimiter will do |
95
|
|
|
|
|
|
|
{ |
96
|
4861
|
|
|
|
|
5445
|
my @parts = grep { length } split( /[^a-f0-9]+/i, $oui ); |
|
4861
|
|
|
|
|
31583
|
|
|
13141
|
|
|
|
|
45532
|
|
97
|
4861
|
100
|
|
|
|
13632
|
if ( @parts == 3 ) { return map { hex } @parts } |
|
4140
|
|
|
|
|
8851
|
|
|
12420
|
|
|
|
|
42258
|
|
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# 00062a, requires exactly 6 hex characters |
101
|
|
|
|
|
|
|
{ |
102
|
721
|
|
|
|
|
1109
|
my @parts = ( $oui =~ /([a-f0-9])/ig ); |
|
721
|
|
|
|
|
6437
|
|
103
|
721
|
100
|
|
|
|
3061
|
if ( @parts == 6 ) { |
104
|
|
|
|
|
|
|
return( |
105
|
719
|
|
|
|
|
4622
|
hex( $parts[0].$parts[1] ), |
106
|
|
|
|
|
|
|
hex( $parts[2].$parts[3] ), |
107
|
|
|
|
|
|
|
hex( $parts[4].$parts[5] ), |
108
|
|
|
|
|
|
|
); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
} |
111
|
2
|
|
|
|
|
22
|
return (); |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub normalize_oui { |
115
|
3847
|
|
|
3847
|
1
|
2328077
|
my $oui = shift; |
116
|
3847
|
100
|
|
|
|
12364
|
my @int = oui_to_integers( $oui ) or return; |
117
|
3839
|
|
|
|
|
38313
|
return sprintf( '%02X-%02X-%02X', @int ); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
1223
|
|
|
1223
|
1
|
3550
|
sub normalized { return shift->{ 'oui_norm' } } |
121
|
|
|
|
|
|
|
*norm = \&normalized; |
122
|
|
|
|
|
|
|
|
123
|
18
|
|
|
18
|
1
|
2913
|
sub organization { return shift->lookup->{ 'organization' } } |
124
|
5
|
|
|
5
|
1
|
3154
|
sub company_id { return shift->lookup->{ 'company_id' } } |
125
|
5
|
|
|
5
|
1
|
2681
|
sub address { return shift->lookup->{ 'address' } } |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub is_private { |
128
|
5
|
|
|
5
|
1
|
2747
|
my $self = shift; |
129
|
|
|
|
|
|
|
|
130
|
5
|
100
|
|
|
|
17
|
return $self->organization eq 'PRIVATE' ? 1 : 0; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub lookup { |
134
|
28
|
|
|
28
|
1
|
46
|
my $self = shift; |
135
|
|
|
|
|
|
|
|
136
|
28
|
|
|
|
|
32
|
my $x; |
137
|
28
|
100
|
|
|
|
82
|
if ( $x = $self->{ 'lookup' } ) { return $x } |
|
15
|
|
|
|
|
88
|
|
138
|
|
|
|
|
|
|
|
139
|
13
|
100
|
|
|
|
50
|
if ( $x = $self->cache ) { return $self->{ 'lookup' } = $x } |
|
2
|
|
|
|
|
19
|
|
140
|
11
|
50
|
|
|
|
38
|
if ( $x = $self->update_from_file ) { return $self->{ 'lookup' } = $x } |
|
11
|
|
|
|
|
77
|
|
141
|
0
|
0
|
|
|
|
0
|
if ( $x = $self->update_from_web ) { return $self->{ 'lookup' } = $x } |
|
0
|
|
|
|
|
0
|
|
142
|
0
|
0
|
|
|
|
0
|
if ( $self->mirror_file ) { |
143
|
0
|
0
|
|
|
|
0
|
if ( $x = $self->update_from_file ) { |
144
|
0
|
|
|
|
|
0
|
return $self->{ 'lookup' } = $x; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
0
|
return $self->{ 'lookup' } = {}; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub update_from_file { |
152
|
13
|
|
|
13
|
1
|
19
|
my $self = shift; |
153
|
13
|
|
|
|
|
30
|
my $oui = $self->norm; |
154
|
|
|
|
|
|
|
|
155
|
13
|
|
|
|
|
404
|
my $cf = $self->cache_file; |
156
|
13
|
100
|
|
|
|
323
|
if ( ! $cf ) { return } |
|
1
|
|
|
|
|
5
|
|
157
|
12
|
|
|
|
|
121
|
my $fh = IO::File->new( $cf, 'r' ); |
158
|
12
|
100
|
|
|
|
1454
|
if ( ! $fh ) { return } |
|
1
|
|
|
|
|
5
|
|
159
|
|
|
|
|
|
|
|
160
|
11
|
|
|
|
|
53
|
local $/ = ""; |
161
|
|
|
|
|
|
|
|
162
|
11
|
|
|
|
|
309
|
while ( my $entry = $fh->getline ) { |
163
|
46
|
100
|
|
|
|
2546
|
if ( substr( $entry, 0, 8 ) eq $oui ) { |
164
|
11
|
|
|
|
|
40
|
my $data = $self->parse_oui_entry( $entry ); |
165
|
11
|
|
|
|
|
30
|
$self->cache( $data ); |
166
|
11
|
|
|
|
|
239
|
return $data; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
} |
169
|
0
|
|
|
|
|
0
|
return; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
{ |
173
|
|
|
|
|
|
|
my $HAVE_LWP_SIMPLE; |
174
|
|
|
|
|
|
|
sub have_lwp_simple { |
175
|
17
|
|
|
17
|
1
|
28
|
my $self = shift; |
176
|
17
|
100
|
|
|
|
50
|
if ( defined $HAVE_LWP_SIMPLE ) { return $HAVE_LWP_SIMPLE } |
|
15
|
|
|
|
|
48
|
|
177
|
2
|
|
|
|
|
110970
|
eval "require LWP::Simple"; ## no critic |
178
|
2
|
50
|
|
|
|
18
|
if ( $@ ) { |
179
|
0
|
|
|
|
|
0
|
carp "Unable to load LWP::Simple, network access not available\n"; |
180
|
0
|
|
|
|
|
0
|
$HAVE_LWP_SIMPLE = 0; |
181
|
|
|
|
|
|
|
} else { |
182
|
2
|
|
|
|
|
18
|
$HAVE_LWP_SIMPLE = 1; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub mirror_file { |
188
|
14
|
|
|
14
|
1
|
6984
|
my $self = shift; |
189
|
14
|
|
100
|
|
|
291
|
my $url = shift || $self->file_url; |
190
|
14
|
100
|
|
|
|
118
|
if ( ! $url ) { return } |
|
2
|
|
|
|
|
11
|
|
191
|
12
|
|
100
|
|
|
101
|
my $file = shift || $self->cache_file; |
192
|
12
|
100
|
|
|
|
96
|
if ( ! $file ) { return } |
|
1
|
|
|
|
|
12
|
|
193
|
11
|
50
|
|
|
|
75
|
if ( ! $self->have_lwp_simple ) { return } |
|
0
|
|
|
|
|
0
|
|
194
|
|
|
|
|
|
|
|
195
|
11
|
|
|
|
|
56
|
my $res = LWP::Simple::mirror( $url, $file ); |
196
|
11
|
100
|
|
|
|
2365326
|
if ( $res == LWP::Simple::RC_NOT_MODIFIED() ) { return 0 } |
|
4
|
|
|
|
|
21
|
|
197
|
7
|
50
|
|
|
|
45
|
if ( ! LWP::Simple::is_success( $res ) ) { |
198
|
0
|
|
|
|
|
0
|
carp "Failed to mirror $url to $file ($res)"; |
199
|
0
|
|
|
|
|
0
|
return; |
200
|
|
|
|
|
|
|
} |
201
|
7
|
|
|
|
|
84
|
return 1; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub get_url { |
205
|
8
|
|
|
8
|
1
|
1184
|
my $self = shift; |
206
|
8
|
|
|
|
|
10
|
my $url = shift; |
207
|
8
|
100
|
|
|
|
98
|
if ( ! $url ) { return } |
|
1
|
|
|
|
|
5
|
|
208
|
|
|
|
|
|
|
|
209
|
7
|
|
|
|
|
131
|
return LWP::Simple::get( $url ); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub load_cache_from_web { |
213
|
3
|
|
|
3
|
1
|
364189
|
my $self = shift; |
214
|
3
|
|
33
|
|
|
14
|
my $url = shift || $self->file_url; |
215
|
3
|
50
|
|
|
|
11
|
if ( ! $url ) { return } |
|
0
|
|
|
|
|
0
|
|
216
|
3
|
|
66
|
|
|
89
|
my $file = shift || $self->cache_file; |
217
|
3
|
50
|
|
|
|
50
|
if ( ! $file ) { return } |
|
0
|
|
|
|
|
0
|
|
218
|
|
|
|
|
|
|
|
219
|
3
|
50
|
|
|
|
12
|
if ( $self->mirror_file( $url, $file ) ) { |
220
|
3
|
|
|
|
|
23
|
return $self->load_cache_from_file( $file ); |
221
|
|
|
|
|
|
|
} |
222
|
0
|
|
|
|
|
0
|
return; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub load_cache_from_file { |
226
|
5
|
|
|
5
|
1
|
694
|
my $self = shift; |
227
|
5
|
|
|
|
|
8
|
my $file = shift; |
228
|
5
|
100
|
|
|
|
18
|
if ( ! $file ) { $file = $self->cache_file } |
|
1
|
|
|
|
|
32
|
|
229
|
5
|
50
|
|
|
|
32
|
if ( ! $file ) { return } |
|
0
|
|
|
|
|
0
|
|
230
|
|
|
|
|
|
|
|
231
|
5
|
|
|
|
|
36
|
my $fh = IO::File->new( $file ); |
232
|
5
|
|
|
|
|
527
|
local $/ = ""; |
233
|
5
|
|
|
|
|
196
|
$fh->getline; # dump the header |
234
|
5
|
|
|
|
|
231
|
my $counter = 0; |
235
|
5
|
|
|
|
|
198
|
while ( my $entry = $fh->getline ) { |
236
|
25
|
|
|
|
|
820
|
my $data = $self->parse_oui_entry( $entry ); |
237
|
25
|
|
|
|
|
76
|
$self->cache( $data->{ 'oui' } => $data ); |
238
|
25
|
|
|
|
|
754
|
$counter++; |
239
|
|
|
|
|
|
|
} |
240
|
5
|
|
|
|
|
248
|
return $counter; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub search_url_for { |
244
|
8
|
|
|
8
|
1
|
779
|
my $self = shift; |
245
|
8
|
|
|
|
|
22
|
my $oui = normalize_oui( shift ); |
246
|
8
|
100
|
|
|
|
26
|
if ( ! $oui ) { $oui = $self->norm } |
|
6
|
|
|
|
|
14
|
|
247
|
|
|
|
|
|
|
|
248
|
8
|
|
|
|
|
270
|
my $url_format = $self->search_url; |
249
|
8
|
50
|
|
|
|
379
|
if ( ! $url_format ) { return } |
|
0
|
|
|
|
|
0
|
|
250
|
|
|
|
|
|
|
|
251
|
8
|
50
|
|
|
|
32
|
if ( $url_format =~ /%s/ ) { |
252
|
8
|
|
|
|
|
43
|
return sprintf( $url_format, $oui ); |
253
|
|
|
|
|
|
|
} else { |
254
|
0
|
|
|
|
|
0
|
return $url_format.$oui; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub update_from_web { |
259
|
6
|
|
|
6
|
1
|
27
|
my $self = shift; |
260
|
|
|
|
|
|
|
|
261
|
6
|
50
|
|
|
|
15
|
if ( not ref $self ) { return } |
|
0
|
|
|
|
|
0
|
|
262
|
6
|
50
|
|
|
|
15
|
if ( not $self->have_lwp_simple ) { return } |
|
0
|
|
|
|
|
0
|
|
263
|
|
|
|
|
|
|
|
264
|
6
|
|
|
|
|
14
|
my $url = $self->search_url_for; |
265
|
6
|
50
|
|
|
|
15
|
if ( ! $url ) { return } |
|
0
|
|
|
|
|
0
|
|
266
|
|
|
|
|
|
|
|
267
|
6
|
50
|
|
|
|
17
|
if ( my $page = $self->get_url( $url ) ) { |
268
|
6
|
50
|
|
|
|
216
|
if ( $page =~ /listing contains no match/ ) { return } |
|
0
|
|
|
|
|
0
|
|
269
|
6
|
|
|
|
|
52
|
my @entries = ( $page =~ m{(.*?) }gs ); |
270
|
6
|
50
|
|
|
|
19
|
if ( @entries > 1 ) { croak "Too many entries returned from $url\n" } |
|
0
|
|
|
|
|
0
|
|
271
|
6
|
|
|
|
|
18
|
my $data = $self->parse_oui_entry( shift( @entries ) ); |
272
|
6
|
|
|
|
|
20
|
$self->cache( $data ); |
273
|
6
|
|
|
|
|
31
|
return $data; |
274
|
|
|
|
|
|
|
} |
275
|
0
|
|
|
|
|
0
|
return; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
sub parse_oui_entry { |
279
|
52
|
|
|
52
|
1
|
8492
|
local $_ = pop( @_ ); # pop in case we get called as a class method |
280
|
9
|
|
|
9
|
|
31364
|
use Carp qw( confess ); |
|
9
|
|
|
|
|
30
|
|
|
9
|
|
|
|
|
7536
|
|
281
|
52
|
50
|
|
|
|
153
|
if ( ! $_ ) { confess "eh?" } |
|
0
|
|
|
|
|
0
|
|
282
|
52
|
|
|
|
|
162
|
s{?b>}{}g; |
283
|
52
|
|
|
|
|
93
|
s/\r//g; |
284
|
|
|
|
|
|
|
|
285
|
52
|
|
|
|
|
305
|
s/\s*\(hex\)\s*/\n/gm; |
286
|
52
|
|
|
|
|
396
|
s/\s*\(base 16\).*$//gm; |
287
|
52
|
|
|
|
|
1868
|
s/^\s*|\s*$//gsm; |
288
|
|
|
|
|
|
|
|
289
|
52
|
|
|
|
|
105
|
my %data = (); |
290
|
52
|
|
|
|
|
366
|
@data{ qw( oui organization company_id address ) } = split( "\n", $_, 4 ); |
291
|
52
|
100
|
|
|
|
164
|
delete $data{ 'address' } unless $data{ 'address' }; |
292
|
52
|
|
|
|
|
165
|
return \%data; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
146
|
50
|
|
146
|
1
|
881
|
sub overload_cmp { return oui_cmp( pop( @_ ) ? reverse @_ : @_ ) } |
296
|
|
|
|
|
|
|
sub oui_cmp { |
297
|
656
|
|
|
656
|
1
|
157823
|
my @l = oui_to_integers( shift ); |
298
|
656
|
|
|
|
|
1639
|
my @r = oui_to_integers( shift ); |
299
|
|
|
|
|
|
|
|
300
|
656
|
|
66
|
|
|
5433
|
return ( $l[0] <=> $r[0] || $l[1] <=> $r[1] || $l[2] <=> $r[2] ); |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
sub dump_cache { |
304
|
5
|
|
|
5
|
1
|
9
|
my $self = shift; |
305
|
|
|
|
|
|
|
|
306
|
5
|
|
|
|
|
17
|
my @lines = ( |
307
|
|
|
|
|
|
|
"\n", |
308
|
|
|
|
|
|
|
"OUI\t\t\t\tOrganization\n", |
309
|
|
|
|
|
|
|
"company_id\t\t\tOrganization\n", |
310
|
|
|
|
|
|
|
"\t\t\t\tAddress\n", |
311
|
|
|
|
|
|
|
"\n", "\n", |
312
|
|
|
|
|
|
|
); |
313
|
|
|
|
|
|
|
|
314
|
5
|
|
|
|
|
11
|
my $db = $self->cache_handle; |
315
|
|
|
|
|
|
|
|
316
|
5
|
|
|
|
|
8
|
foreach my $oui ( sort { $a cmp $b } keys %{ $db } ) { |
|
40
|
|
|
|
|
60
|
|
|
5
|
|
|
|
|
194
|
|
317
|
25
|
|
|
|
|
382
|
my $d = { split( "\0", $db->{ $oui } ) }; |
318
|
25
|
|
|
|
|
69
|
my $org = $d->{ 'organization' }; |
319
|
|
|
|
|
|
|
|
320
|
25
|
100
|
|
|
|
150
|
push( @lines, |
321
|
|
|
|
|
|
|
sprintf( "%-10s (hex)\t\t%s\n", $d->{ 'oui' }, $org ), |
322
|
|
|
|
|
|
|
sprintf( |
323
|
|
|
|
|
|
|
"%-10s (base 16)\t\t%s\n", |
324
|
|
|
|
|
|
|
$d->{ 'company_id' }, |
325
|
|
|
|
|
|
|
$org eq 'PRIVATE' ? '' : $org, |
326
|
|
|
|
|
|
|
), |
327
|
|
|
|
|
|
|
); |
328
|
25
|
100
|
|
|
|
48
|
if ( my $a = $d->{ 'address' } ) { |
329
|
20
|
|
|
|
|
55
|
for my $x ( split( "\n", $d->{ 'address' } ) ) { |
330
|
65
|
|
|
|
|
128
|
push( @lines, "\t\t\t\t$x\n" ); |
331
|
|
|
|
|
|
|
} |
332
|
20
|
|
|
|
|
64
|
push( @lines, "\n" ); |
333
|
|
|
|
|
|
|
} else { |
334
|
5
|
|
|
|
|
18
|
push( @lines, "\t\t\t\t\n" ); |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
5
|
|
|
|
|
92
|
return join( "", @lines ); |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
1; |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
__END__ |