[#162] Change from Net::MAC to NetAddr::MAC

Note that IEEE and Microsoft are the WRONG WAY ROUND in NetAddr::MAC. I've
emailed the author about this. A dirty hack is in place to deal with it.
This commit is contained in:
Oliver Gorwits
2014-11-14 22:49:07 +00:00
parent e4c668fb12
commit a308d1a177
15 changed files with 52 additions and 50 deletions

View File

@@ -6,6 +6,7 @@
* [#165] Mention system clock in docs * [#165] Mention system clock in docs
* [#164] Workers should restart periodically * [#164] Workers should restart periodically
* [#168] Jobs requested via web UI are treated as high priority * [#168] Jobs requested via web UI are treated as high priority
* [#162] Change from Net::MAC to NetAddr::MAC
* Add "Run Expire Job" to the Admin Menu * Add "Run Expire Job" to the Admin Menu
[BUG FIXES] [BUG FIXES]

View File

@@ -59,7 +59,7 @@ requires:
Net::DNS: 0.72 Net::DNS: 0.72
Net::Domain: 1.23 Net::Domain: 1.23
Net::LDAP: 0 Net::LDAP: 0
Net::MAC: 2.103622 NetAddr::MAC: 0.87
NetAddr::IP: 4.068 NetAddr::IP: 4.068
Opcode: 1.07 Opcode: 1.07
Path::Class: 0.32 Path::Class: 0.32

View File

@@ -1,12 +1,12 @@
use inc::Module::Install; use inc::Module::Install;
name 'App-Netdisco'; name 'App-Netdisco';
license 'bsd'; license 'bsd';
all_from 'lib/App/Netdisco.pm'; all_from 'lib/App/Netdisco.pm';
test_requires 'Test::More' => 0.88; test_requires 'Test::More' => 0.88;
test_requires 'Env::Path' => 0; test_requires 'Env::Path' => 0;
requires 'Algorithm::Cron' => 0.07; requires 'Algorithm::Cron' => 0.07;
requires 'AnyEvent' => 7.05; requires 'AnyEvent' => 7.05;
requires 'AnyEvent::DNS::EtcHosts' => 0; requires 'AnyEvent::DNS::EtcHosts' => 0;
@@ -38,7 +38,7 @@ requires 'MCE' => 1.515;
requires 'Net::Domain' => 1.23; requires 'Net::Domain' => 1.23;
requires 'Net::DNS' => 0.72; requires 'Net::DNS' => 0.72;
requires 'Net::LDAP' => 0; requires 'Net::LDAP' => 0;
requires 'Net::MAC' => 2.103622; requires 'NetAddr::MAC' => 0.87;
requires 'NetAddr::IP' => 4.068; requires 'NetAddr::IP' => 4.068;
requires 'Opcode' => 1.07; requires 'Opcode' => 1.07;
requires 'Path::Class' => 0.32; requires 'Path::Class' => 0.32;

View File

@@ -10,7 +10,7 @@ use NetAddr::IP::Lite ':lower';
use List::MoreUtils (); use List::MoreUtils ();
use Encode; use Encode;
use Try::Tiny; use Try::Tiny;
use Net::MAC; use NetAddr::MAC;
use base 'Exporter'; use base 'Exporter';
our @EXPORT = (); our @EXPORT = ();
@@ -754,9 +754,9 @@ sub store_neighbors {
$device->ip, $remote_ip, $port, $remote_id; $device->ip, $remote_ip, $port, $remote_id;
if (!defined $neigh) { if (!defined $neigh) {
my $mac = Net::MAC->new(mac => $remote_id, 'die' => 0, verbose => 0); my $mac = NetAddr::MAC->new(mac => $remote_id);
if (not $mac->get_error) { if ($mac and not $mac->errstr) {
$neigh = $devices->single({mac => $mac->as_IEEE()}); $neigh = $devices->single({mac => $mac->as_microsoft()});
} }
} }
@@ -765,13 +765,13 @@ sub store_neighbors {
# "myswitchname(012345-012345)" # "myswitchname(012345-012345)"
if (!defined $neigh) { if (!defined $neigh) {
(my $tmpid = $remote_id) =~ s/.([0-9a-f]{6})-([0-9a-f]{6})./$1$2/; (my $tmpid = $remote_id) =~ s/.([0-9a-f]{6})-([0-9a-f]{6})./$1$2/;
my $mac = Net::MAC->new(mac => $tmpid, 'die' => 0, verbose => 0); my $mac = NetAddr::MAC->new(mac => $tmpid);
if (not $mac->get_error) { if ($mac and not $mac->errstr) {
info sprintf info sprintf
'[%s] neigh - found neighbor %s by MAC %s', '[%s] neigh - found neighbor %s by MAC %s',
$device->ip, $remote_id, $mac->as_IEEE(); $device->ip, $remote_id, $mac->as_microsoft();
$neigh = $devices->single({mac => $mac->as_IEEE()}); $neigh = $devices->single({mac => $mac->as_microsoft()});
} }
} }

View File

@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::DevicePort;
use strict; use strict;
use warnings; use warnings;
use Net::MAC; use NetAddr::MAC;
use MIME::Base64 'encode_base64url'; use MIME::Base64 'encode_base64url';
@@ -339,10 +339,10 @@ sub base64url_port { return encode_base64url((shift)->port) }
=head2 net_mac =head2 net_mac
Returns the C<mac> column instantiated into a L<Net::MAC> object. Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
=cut =cut
sub net_mac { return Net::MAC->new(mac => (shift)->mac) } sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
1; 1;

View File

@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::Node;
use strict; use strict;
use warnings; use warnings;
use Net::MAC; use NetAddr::MAC;
use base 'DBIx::Class::Core'; use base 'DBIx::Class::Core';
__PACKAGE__->table("node"); __PACKAGE__->table("node");
@@ -175,10 +175,10 @@ sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
=head2 net_mac =head2 net_mac
Returns the C<mac> column instantiated into a L<Net::MAC> object. Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
=cut =cut
sub net_mac { return Net::MAC->new(mac => (shift)->mac) } sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
1; 1;

View File

@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::NodeIp;
use strict; use strict;
use warnings; use warnings;
use Net::MAC; use NetAddr::MAC;
use base 'DBIx::Class::Core'; use base 'DBIx::Class::Core';
__PACKAGE__->table("node_ip"); __PACKAGE__->table("node_ip");
@@ -221,10 +221,10 @@ sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
=head2 net_mac =head2 net_mac
Returns the C<mac> column instantiated into a L<Net::MAC> object. Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
=cut =cut
sub net_mac { return Net::MAC->new(mac => (shift)->mac) } sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
1; 1;

View File

@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::NodeNbt;
use strict; use strict;
use warnings; use warnings;
use Net::MAC; use NetAddr::MAC;
use base 'DBIx::Class::Core'; use base 'DBIx::Class::Core';
__PACKAGE__->table("node_nbt"); __PACKAGE__->table("node_nbt");
@@ -178,10 +178,10 @@ sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
=head2 net_mac =head2 net_mac
Returns the C<mac> column instantiated into a L<Net::MAC> object. Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
=cut =cut
sub net_mac { return Net::MAC->new(mac => (shift)->mac) } sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
1; 1;

View File

@@ -7,7 +7,7 @@ package App::Netdisco::DB::Result::NodeWireless;
use strict; use strict;
use warnings; use warnings;
use Net::MAC; use NetAddr::MAC;
use base 'DBIx::Class::Core'; use base 'DBIx::Class::Core';
__PACKAGE__->table("node_wireless"); __PACKAGE__->table("node_wireless");
@@ -87,10 +87,10 @@ __PACKAGE__->belongs_to( node => 'App::Netdisco::DB::Result::Node',
=head2 net_mac =head2 net_mac
Returns the C<mac> column instantiated into a L<Net::MAC> object. Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
=cut =cut
sub net_mac { return Net::MAC->new(mac => (shift)->mac) } sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
1; 1;

View File

@@ -14,10 +14,10 @@ the L<documentation|App::Netdisco>. Then:
su - netdisco && cd $HOME su - netdisco && cd $HOME
mkdir git && cd git mkdir git && cd git
git clone git://git.code.sf.net/p/netdisco/netdisco-ng netdisco-ng git clone git://git.code.sf.net/p/netdisco/netdisco-ng netdisco-ng
cd netdisco-ng/Netdisco cd netdisco-ng/Netdisco
DBIC_TRACE=1 ~/bin/localenv plackup -R share,lib -p 5001 bin/netdisco-web-fg DBIC_TRACE=1 ~/bin/localenv plackup -R share,lib -p 5001 bin/netdisco-web-fg
The above creates you a git clone (change the URL if you're a Netdisco The above creates you a git clone (change the URL if you're a Netdisco
@@ -259,7 +259,7 @@ Compared to the current Netdisco, the handler routines are very small. This is
because (a) they don't include any HTML - this is delegated to a template, and because (a) they don't include any HTML - this is delegated to a template, and
(b) they don't include an SQL - this is delegated to DBIx::Class. Small (b) they don't include an SQL - this is delegated to DBIx::Class. Small
routines are more manageable, and easier to maintain. You'll also notice use routines are more manageable, and easier to maintain. You'll also notice use
of modules such as L<Net::MAC> and L<NetAddr::IP::Lite> to simplify and make of modules such as L<NetAddr::MAC> and L<NetAddr::IP::Lite> to simplify and make
more robust the handling of data. more robust the handling of data.
In fact, many sections of the web application have been factored out into In fact, many sections of the web application have been factored out into

View File

@@ -3,7 +3,7 @@ package App::Netdisco::Util::Node;
use Dancer qw/:syntax :script/; use Dancer qw/:syntax :script/;
use Dancer::Plugin::DBIC 'schema'; use Dancer::Plugin::DBIC 'schema';
use Net::MAC; use NetAddr::MAC;
use App::Netdisco::Util::Permission 'check_acl'; use App::Netdisco::Util::Permission 'check_acl';
use base 'Exporter'; use base 'Exporter';
@@ -66,23 +66,23 @@ MAC address does not belong to an interface on any known Device
sub check_mac { sub check_mac {
my ($device, $node, $port_macs) = @_; my ($device, $node, $port_macs) = @_;
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0); my $mac = NetAddr::MAC->new(mac => $node);
my $devip = (ref $device ? $device->ip : ''); my $devip = (ref $device ? $device->ip : '');
$port_macs ||= {}; $port_macs ||= {};
# incomplete MAC addresses (BayRS frame relay DLCI, etc) # incomplete MAC addresses (BayRS frame relay DLCI, etc)
if ($mac->get_error) { if (!defined $mac or $mac->errstr) {
debug sprintf ' [%s] check_mac - mac [%s] malformed - skipping', debug sprintf ' [%s] check_mac - mac [%s] malformed - skipping',
$devip, $node; $devip, $node;
return 0; return 0;
} }
else { else {
# lower case, hex, colon delimited, 8-bit groups # lower case, hex, colon delimited, 8-bit groups
$node = lc $mac->as_IEEE; $node = lc $mac->as_microsoft;
} }
# broadcast MAC addresses # broadcast MAC addresses
return 0 if $node eq 'ff:ff:ff:ff:ff:ff'; return 0 if $mac->is_broadcast;
# all-zero MAC addresses # all-zero MAC addresses
return 0 if $node eq '00:00:00:00:00:00'; return 0 if $node eq '00:00:00:00:00:00';
@@ -91,21 +91,21 @@ sub check_mac {
return 0 if $node eq '00:00:00:00:00:01'; return 0 if $node eq '00:00:00:00:00:01';
# multicast # multicast
if ($node =~ m/^[0-9a-f](?:1|3|5|7|9|b|d|f):/) { if ($mac->is_multicast and not $mac->is_msnlb) {
debug sprintf ' [%s] check_mac - multicast mac [%s] - skipping', debug sprintf ' [%s] check_mac - multicast mac [%s] - skipping',
$devip, $node; $devip, $node;
return 0; return 0;
} }
# VRRP # VRRP
if (index($node, '00:00:5e:00:01:') == 0) { if ($mac->is_vrrp) {
debug sprintf ' [%s] check_mac - VRRP mac [%s] - skipping', debug sprintf ' [%s] check_mac - VRRP mac [%s] - skipping',
$devip, $node; $devip, $node;
return 0; return 0;
} }
# HSRP # HSRP
if (index($node, '00:00:0c:07:ac:') == 0) { if ($mac->is_hsrp or $mac->is_hsrp2) {
debug sprintf ' [%s] check_mac - HSRP mac [%s] - skipping', debug sprintf ' [%s] check_mac - HSRP mac [%s] - skipping',
$devip, $node; $devip, $node;
return 0; return 0;

View File

@@ -129,8 +129,7 @@ hook 'before_template' => sub {
$tokens->{device_ports}->query_param($key, params->{$key}); $tokens->{device_ports}->query_param($key, params->{$key});
} }
# for Net::MAC method $tokens->{mac_format_call} = 'as_'. lc(params->{'mac_format'})
$tokens->{mac_format_call} = 'as_'. params->{'mac_format'}
if params->{'mac_format'}; if params->{'mac_format'};
foreach my $col (@{ var('port_columns') }) { foreach my $col (@{ var('port_columns') }) {

View File

@@ -6,7 +6,7 @@ use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible; use Dancer::Plugin::Auth::Extensible;
use NetAddr::IP::Lite ':lower'; use NetAddr::IP::Lite ':lower';
use Net::MAC (); use NetAddr::MAC ();
use App::Netdisco::Web::Plugin; use App::Netdisco::Web::Plugin;
use App::Netdisco::Util::Web 'sql_match'; use App::Netdisco::Util::Web 'sql_match';
@@ -20,9 +20,9 @@ ajax '/ajax/content/search/node' => require_login sub {
content_type('text/html'); content_type('text/html');
my $agenot = param('age_invert') || '0'; my $agenot = param('age_invert') || '0';
my ( $start, $end ) = param('daterange') =~ /(\d+-\d+-\d+)/gmx; my ( $start, $end ) = param('daterange') =~ m/(\d+-\d+-\d+)/gmx;
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0); my $mac = NetAddr::MAC->new(mac => $node);
my @active = (param('archived') ? () : (-bool => 'active')); my @active = (param('archived') ? () : (-bool => 'active'));
my @times = (); my @times = ();
@@ -48,7 +48,7 @@ ajax '/ajax/content/search/node' => require_login sub {
my @where_mac = my @where_mac =
($using_wildcards ? \['me.mac::text ILIKE ?', $likeval] ($using_wildcards ? \['me.mac::text ILIKE ?', $likeval]
: ($mac->get_error ? \'0=1' : ('me.mac' => $mac->as_IEEE)) ); : ((!defined $mac or $mac->errstr) ? \'0=1' : ('me.mac' => $mac->as_microsoft)) );
my $sightings = schema('netdisco')->resultset('Node') my $sightings = schema('netdisco')->resultset('Node')
->search({-and => [@where_mac, @active, @times]}, { ->search({-and => [@where_mac, @active, @times]}, {

View File

@@ -125,9 +125,10 @@
<li> <li>
<em class="muted">MAC address format:</em><br/> <em class="muted">MAC address format:</em><br/>
<select id="nd_mac-format" name="mac_format"> <select id="nd_mac-format" name="mac_format">
[% FOREACH format IN [ 'IEEE', 'Cisco', 'Microsoft', 'Sun' ] %] <option[% ' selected="selected"' IF params.mac_format == 'Cisco' %]>Cisco</option>
<option[% ' selected="selected"' IF params.mac_format == format %]>[% format %]</option> <option[% ' selected="selected"' IF params.mac_format == 'Microsoft' %] value="Microsoft">IEEE</option>
[% END %] <option[% ' selected="selected"' IF params.mac_format == 'IEEE' %] value="IEEE">Microsoft</option>
<option[% ' selected="selected"' IF params.mac_format == 'Sun' %]>Sun</option>
</select> </select>
</li> </li>
[% FOREACH item IN vars.connected_properties %] [% FOREACH item IN vars.connected_properties %]

View File

@@ -55,9 +55,10 @@
<div class="clearfix"> <div class="clearfix">
<em class="muted">MAC address format:</em><br/> <em class="muted">MAC address format:</em><br/>
<select id="nd_node-mac-format" name="mac_format"> <select id="nd_node-mac-format" name="mac_format">
[% FOREACH format IN [ 'IEEE', 'Cisco', 'Microsoft', 'Sun' ] %] <option[% ' selected="selected"' IF params.mac_format == 'Cisco' %]>Cisco</option>
<option[% ' selected="selected"' IF params.mac_format == format %]>[% format %]</option> <option[% ' selected="selected"' IF params.mac_format == 'Microsoft' %] value="Microsoft">IEEE</option>
[% END %] <option[% ' selected="selected"' IF params.mac_format == 'IEEE' %] value="IEEE">Microsoft</option>
<option[% ' selected="selected"' IF params.mac_format == 'Sun' %]>Sun</option>
</select> </select>
</div> </div>
<button id="[% tab.tag %]_submit" type="submit" class="btn btn-info"> <button id="[% tab.tag %]_submit" type="submit" class="btn btn-info">