remove check_mac to own module, use in macsuck too

This commit is contained in:
Oliver Gorwits
2013-05-27 15:18:15 +01:00
parent b995cf6398
commit 7f2ea7f8dc
3 changed files with 125 additions and 95 deletions

View File

@@ -3,15 +3,15 @@ package App::Netdisco::Core::Arpnip;
use Dancer qw/:syntax :script/; use Dancer qw/:syntax :script/;
use Dancer::Plugin::DBIC 'schema'; use Dancer::Plugin::DBIC 'schema';
use App::Netdisco::Util::PortMAC ':all'; use App::Netdisco::Util::PortMAC 'get_port_macs';
use App::Netdisco::Util::SanityCheck 'check_mac';
use App::Netdisco::Util::DNS ':all'; use App::Netdisco::Util::DNS ':all';
use NetAddr::IP::Lite ':lower'; use NetAddr::IP::Lite ':lower';
use Time::HiRes 'gettimeofday'; use Time::HiRes 'gettimeofday';
use Net::MAC;
use base 'Exporter'; use base 'Exporter';
our @EXPORT = (); our @EXPORT = ();
our @EXPORT_OK = qw/ do_arpnip check_mac store_arp /; our @EXPORT_OK = qw/ do_arpnip store_arp /;
our %EXPORT_TAGS = (all => \@EXPORT_OK); our %EXPORT_TAGS = (all => \@EXPORT_OK);
=head1 NAME =head1 NAME
@@ -82,91 +82,13 @@ sub _get_arps {
while (my ($arp, $node) = each %$paddr) { while (my ($arp, $node) = each %$paddr) {
my $ip = $netaddr->{$arp}; my $ip = $netaddr->{$arp};
next unless defined $ip; next unless defined $ip;
push @arps, [$node, $ip, hostname_from_ip($ip)] next unless check_mac($device, $node, $port_macs);
if check_mac($device, $node, $port_macs); push @arps, [$node, $ip, hostname_from_ip($ip)];
} }
return @arps; return @arps;
} }
=head2 check_mac( $device, $node, $port_macs? )
Given a Device database object and a MAC address, perform various sanity
checks which need to be done before writing an ARP/Neighbor entry to the
database storage.
Returns false, and logs a debug level message, if the checks fail.
Returns a true value if these checks pass:
=over 4
=item *
MAC address is not malformed
=item *
MAC address is not broadcast, CLIP, VRRP or HSRP
=item *
MAC address does not belong to an interface on C<$device>
=back
Optionally pass a cached set of Device port MAC addresses as the fourth
argument, or else C<check_mac> will retrieve this for itself from the
database.
=cut
sub check_mac {
my ($device, $node, $port_macs) = @_;
$port_macs ||= get_port_macs($device);
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0);
# incomplete MAC addresses (BayRS frame relay DLCI, etc)
if ($mac->get_error) {
debug sprintf ' [%s] arpnip - mac [%s] malformed - skipping',
$device->ip, $node;
return 0;
}
else {
# lower case, hex, colon delimited, 8-bit groups
$node = lc $mac->as_IEEE;
}
# broadcast MAC addresses
return 0 if $node eq 'ff:ff:ff:ff:ff:ff';
# CLIP
return 0 if $node eq '00:00:00:00:00:01';
# VRRP
if (index($node, '00:00:5e:00:01:') == 0) {
debug sprintf ' [%s] arpnip - VRRP mac [%s] - skipping',
$device->ip, $node;
return 0;
}
# HSRP
if (index($node, '00:00:0c:07:ac:') == 0) {
debug sprintf ' [%s] arpnip - HSRP mac [%s] - skipping',
$device->ip, $node;
return 0;
}
# device's own MACs
if (exists $port_macs->{$node}) {
debug sprintf ' [%s] arpnip - mac [%s] is device port - skipping',
$device->ip, $node;
return 0;
}
return 1;
}
=head2 store_arp( $mac, $ip, $name, $now? ) =head2 store_arp( $mac, $ip, $name, $now? )
Stores a new entry to the C<node_ip> table with the given MAC, IP (v4 or v6) Stores a new entry to the C<node_ip> table with the given MAC, IP (v4 or v6)

View File

@@ -3,7 +3,8 @@ package App::Netdisco::Core::Macsuck;
use Dancer qw/:syntax :script/; use Dancer qw/:syntax :script/;
use Dancer::Plugin::DBIC 'schema'; use Dancer::Plugin::DBIC 'schema';
use App::Netdisco::Util::PortMAC ':all'; use App::Netdisco::Util::PortMAC 'get_port_macs';
use App::Netdisco::Util::SanityCheck 'check_mac';
use App::Netdisco::Util::SNMP 'snmp_comm_reindex'; use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
use Time::HiRes 'gettimeofday'; use Time::HiRes 'gettimeofday';
@@ -77,9 +78,9 @@ sub do_macsuck {
} }
# now it's time to call store_node for every node discovered # now it's time to call store_node for every node discovered
# on every port on every vlan on every device. # on every port on every vlan on this device.
# reverse sort allows vlan 0 entries to be added as fallback # reverse sort allows vlan 0 entries to be included only as fallback
foreach my $vlan (reverse sort keys %$fwtable) { foreach my $vlan (reverse sort keys %$fwtable) {
foreach my $port (keys %{ $fwtable->{$vlan} }) { foreach my $port (keys %{ $fwtable->{$vlan} }) {
if ($device_ports->{$port}->is_uplink) { if ($device_ports->{$port}->is_uplink) {
@@ -270,6 +271,7 @@ sub _walk_fwtable {
while (my ($idx, $mac) = each %$fw_mac) { while (my ($idx, $mac) = each %$fw_mac) {
my $bp_id = $fw_port->{$idx}; my $bp_id = $fw_port->{$idx};
next unless check_mac($device, $mac, $port_macs);
unless (defined $bp_id) { unless (defined $bp_id) {
debug sprintf debug sprintf
@@ -361,15 +363,6 @@ sub _walk_fwtable {
next unless setting('macsuck_bleed'); next unless setting('macsuck_bleed');
} }
if ($mac =~ /^([0-9a-f]{2}):/i and ($1 =~ /.(1|3|5|7|9|b|d|f)/i)) {
debug sprintf ' [%s] macsuck %s is multicast - skipping.',
$device->ip, $mac;
next;
}
next if $mac eq '00:00:00:00:00:00';
next if lc($mac) eq 'ff:ff:ff:ff:ff:ff';
++$cache->{$port}->{$mac}; ++$cache->{$port}->{$mac};
} }

View File

@@ -0,0 +1,115 @@
package App::Netdisco::Util::SanityCheck;
use Dancer qw/:syntax :script/;
use Dancer::Plugin::DBIC 'schema';
use App::Netdisco::Util::PortMAC ':all';
use Net::MAC;
use base 'Exporter';
our @EXPORT = ();
our @EXPORT_OK = qw/ check_mac /;
our %EXPORT_TAGS = (all => \@EXPORT_OK);
=head1 NAME
App::Netdisco::Util::SanityCheck
=head1 DESCRIPTION
Helper subroutines to support parts of the Netdisco application.
There are no default exports, however the C<:all> tag will export all
subroutines.
=head1 EXPORT_OK
=head2 check_mac( $device, $node, $port_macs? )
Given a Device database object and a MAC address, perform various sanity
checks which need to be done before writing an ARP/Neighbor entry to the
database storage.
Returns false, and might log a debug level message, if the checks fail.
Returns a true value if these checks pass:
=over 4
=item *
MAC address is well-formed (according to common formats)
=item *
MAC address is not all-zero, broadcast, CLIP, VRRP or HSRP
=item *
MAC address does not belong to an interface on any known Device
=back
Optionally pass a cached set of Device port MAC addresses as the third
argument, or else C<check_mac> will retrieve this for itself from the
database.
=cut
sub check_mac {
my ($device, $node, $port_macs) = @_;
$port_macs ||= get_port_macs($device);
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0);
# incomplete MAC addresses (BayRS frame relay DLCI, etc)
if ($mac->get_error) {
debug sprintf ' [%s] check_mac - mac [%s] malformed - skipping',
$device->ip, $node;
return 0;
}
else {
# lower case, hex, colon delimited, 8-bit groups
$node = lc $mac->as_IEEE;
}
# broadcast MAC addresses
return 0 if $node eq 'ff:ff:ff:ff:ff:ff';
# all-zero MAC addresses
return 0 if $node eq '00:00:00:00:00:00';
# CLIP
return 0 if $node eq '00:00:00:00:00:01';
# multicast
if ($node =~ m/^[0-9a-f](?:1|3|5|7|9|b|d|f):/) {
debug sprintf ' [%s] check_mac - multicast mac [%s] - skipping',
$device->ip, $node;
return 0;
}
# VRRP
if (index($node, '00:00:5e:00:01:') == 0) {
debug sprintf ' [%s] check_mac - VRRP mac [%s] - skipping',
$device->ip, $node;
return 0;
}
# HSRP
if (index($node, '00:00:0c:07:ac:') == 0) {
debug sprintf ' [%s] check_mac - HSRP mac [%s] - skipping',
$device->ip, $node;
return 0;
}
# device's own MACs
if (exists $port_macs->{$node}) {
debug sprintf ' [%s] check_mac - mac [%s] is device port - skipping',
$device->ip, $node;
return 0;
}
return 1;
}
1;