From 7f2ea7f8dc4c4a865c26e20bda20184d29ae8df1 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 27 May 2013 15:18:15 +0100 Subject: [PATCH] remove check_mac to own module, use in macsuck too --- Netdisco/lib/App/Netdisco/Core/Arpnip.pm | 88 +------------- Netdisco/lib/App/Netdisco/Core/Macsuck.pm | 17 +-- Netdisco/lib/App/Netdisco/Util/SanityCheck.pm | 115 ++++++++++++++++++ 3 files changed, 125 insertions(+), 95 deletions(-) create mode 100644 Netdisco/lib/App/Netdisco/Util/SanityCheck.pm diff --git a/Netdisco/lib/App/Netdisco/Core/Arpnip.pm b/Netdisco/lib/App/Netdisco/Core/Arpnip.pm index 42394530..d4015d1b 100644 --- a/Netdisco/lib/App/Netdisco/Core/Arpnip.pm +++ b/Netdisco/lib/App/Netdisco/Core/Arpnip.pm @@ -3,15 +3,15 @@ package App::Netdisco::Core::Arpnip; use Dancer qw/:syntax :script/; 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 NetAddr::IP::Lite ':lower'; use Time::HiRes 'gettimeofday'; -use Net::MAC; use base 'Exporter'; 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); =head1 NAME @@ -82,91 +82,13 @@ sub _get_arps { while (my ($arp, $node) = each %$paddr) { my $ip = $netaddr->{$arp}; next unless defined $ip; - push @arps, [$node, $ip, hostname_from_ip($ip)] - if check_mac($device, $node, $port_macs); + next unless check_mac($device, $node, $port_macs); + push @arps, [$node, $ip, hostname_from_ip($ip)]; } 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 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? ) Stores a new entry to the C table with the given MAC, IP (v4 or v6) diff --git a/Netdisco/lib/App/Netdisco/Core/Macsuck.pm b/Netdisco/lib/App/Netdisco/Core/Macsuck.pm index 5251e9ab..071e9a7c 100644 --- a/Netdisco/lib/App/Netdisco/Core/Macsuck.pm +++ b/Netdisco/lib/App/Netdisco/Core/Macsuck.pm @@ -3,7 +3,8 @@ package App::Netdisco::Core::Macsuck; use Dancer qw/:syntax :script/; 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 Time::HiRes 'gettimeofday'; @@ -77,9 +78,9 @@ sub do_macsuck { } # 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 $port (keys %{ $fwtable->{$vlan} }) { if ($device_ports->{$port}->is_uplink) { @@ -270,6 +271,7 @@ sub _walk_fwtable { while (my ($idx, $mac) = each %$fw_mac) { my $bp_id = $fw_port->{$idx}; + next unless check_mac($device, $mac, $port_macs); unless (defined $bp_id) { debug sprintf @@ -361,15 +363,6 @@ sub _walk_fwtable { 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}; } diff --git a/Netdisco/lib/App/Netdisco/Util/SanityCheck.pm b/Netdisco/lib/App/Netdisco/Util/SanityCheck.pm new file mode 100644 index 00000000..43a3fe5a --- /dev/null +++ b/Netdisco/lib/App/Netdisco/Util/SanityCheck.pm @@ -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 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;