refactor to make check_no/acl/only share code between device and node paths
This commit is contained in:
		| @@ -2,17 +2,14 @@ package App::Netdisco::Util::Device; | ||||
|  | ||||
| use Dancer qw/:syntax :script/; | ||||
| use Dancer::Plugin::DBIC 'schema'; | ||||
|  | ||||
| use NetAddr::IP::Lite ':lower'; | ||||
| use App::Netdisco::Util::DNS 'hostname_from_ip'; | ||||
| use App::Netdisco::Util::Permission 'check_acl'; | ||||
|  | ||||
| use base 'Exporter'; | ||||
| our @EXPORT = (); | ||||
| our @EXPORT_OK = qw/ | ||||
|   get_device | ||||
|   check_acl | ||||
|   check_no | ||||
|   check_only | ||||
|   check_device_no | ||||
|   check_device_only | ||||
|   is_discoverable | ||||
|   is_arpnipable | ||||
|   is_macsuckable | ||||
| @@ -60,87 +57,7 @@ sub get_device { | ||||
|     ->find_or_new({ip => $ip}); | ||||
| } | ||||
|  | ||||
| =head2 check_acl( $ip, \@config ) | ||||
|  | ||||
| Given the IP address of a device, returns true if any of the items in C<< | ||||
| \@config >> matches that device, otherwise returns false. | ||||
|  | ||||
| Normally you use C<check_no> and C<check_only>, passing the name of the | ||||
| configuration setting to load. This helper instead requires not the name of | ||||
| the setting, but its value. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub check_acl { | ||||
|   my ($ip, $config) = @_; | ||||
|   my $device = get_device($ip) or return 0; | ||||
|   my $addr = NetAddr::IP::Lite->new($device->ip); | ||||
|  | ||||
|   foreach my $item (@$config) { | ||||
|       if (ref qr// eq ref $item) { | ||||
|           my $name = hostname_from_ip($addr->addr) or next; | ||||
|           return 1 if $name =~ $item; | ||||
|           next; | ||||
|       } | ||||
|  | ||||
|       if ($item =~ m/^([^:]+)\s*:\s*([^:]+)$/) { | ||||
|           my $prop  = $1; | ||||
|           my $match = $2; | ||||
|  | ||||
|           # if not in storage, we can't do much with device properties | ||||
|           next unless $device->in_storage; | ||||
|  | ||||
|           # lazy version of vendor: and model: | ||||
|           if ($device->can($prop) and defined $device->$prop | ||||
|               and $device->$prop =~ m/^$match$/) { | ||||
|               return 1; | ||||
|           } | ||||
|  | ||||
|           next; | ||||
|       } | ||||
|  | ||||
|       if ($item =~ m/([a-f0-9]+)-([a-f0-9]+)$/i) { | ||||
|           my $first = $1; | ||||
|           my $last  = $2; | ||||
|  | ||||
|           if ($item =~ m/:/) { | ||||
|               next unless $addr->bits == 128; | ||||
|  | ||||
|               $first = hex $first; | ||||
|               $last  = hex $last; | ||||
|  | ||||
|               (my $header = $item) =~ s/:[^:]+$/:/; | ||||
|               foreach my $part ($first .. $last) { | ||||
|                   my $ip = NetAddr::IP::Lite->new($header . sprintf('%x',$part) . '/128') | ||||
|                     or next; | ||||
|                   return 1 if $ip == $addr; | ||||
|               } | ||||
|           } | ||||
|           else { | ||||
|               next unless $addr->bits == 32; | ||||
|  | ||||
|               (my $header = $item) =~ s/\.[^.]+$/./; | ||||
|               foreach my $part ($first .. $last) { | ||||
|                   my $ip = NetAddr::IP::Lite->new($header . $part . '/32') | ||||
|                     or next; | ||||
|                   return 1 if $ip == $addr; | ||||
|               } | ||||
|           } | ||||
|  | ||||
|           next; | ||||
|       } | ||||
|  | ||||
|       my $ip = NetAddr::IP::Lite->new($item) | ||||
|         or next; | ||||
|       next unless $ip->bits == $addr->bits; | ||||
|  | ||||
|       return 1 if $ip->contains($addr); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| =head2 check_no( $ip, $setting_name ) | ||||
| =head2 check_device_no( $ip, $setting_name ) | ||||
|  | ||||
| Given the IP address of a device, returns true if the configuration setting | ||||
| C<$setting_name> matches that device, else returns false. If the setting | ||||
| @@ -182,16 +99,17 @@ To match no devices we recommend an entry of "C<localhost>" in the setting. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub check_no { | ||||
| sub check_device_no { | ||||
|   my ($ip, $setting_name) = @_; | ||||
|   my $device = get_device($ip) or return 0; | ||||
|  | ||||
|   my $config = setting($setting_name) || []; | ||||
|   return 0 if not scalar @$config; | ||||
|  | ||||
|   return check_acl($ip, $config); | ||||
|   return check_acl($device->ip, $config); | ||||
| } | ||||
|  | ||||
| =head2 check_only( $ip, $setting_name ) | ||||
| =head2 check_device_only( $ip, $setting_name ) | ||||
|  | ||||
| Given the IP address of a device, returns true if the configuration setting | ||||
| C<$setting_name> matches that device, else returns false. If the setting | ||||
| @@ -233,13 +151,14 @@ To match no devices we recommend an entry of "C<localhost>" in the setting. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub check_only { | ||||
| sub check_device_only { | ||||
|   my ($ip, $setting_name) = @_; | ||||
|   my $device = get_device($ip) or return 0; | ||||
|  | ||||
|   my $config = setting($setting_name) || []; | ||||
|   return 1 if not scalar @$config; | ||||
|  | ||||
|   return check_acl($ip, $config); | ||||
|   return check_acl($device->ip, $config); | ||||
| } | ||||
|  | ||||
| =head2 is_discoverable( $ip, $device_type? ) | ||||
| @@ -270,10 +189,10 @@ sub is_discoverable { | ||||
|   } | ||||
|  | ||||
|   return _bail_msg("is_discoverable: device matched discover_no") | ||||
|     if check_no($device, 'discover_no'); | ||||
|     if check_device_no($device, 'discover_no'); | ||||
|  | ||||
|   return _bail_msg("is_discoverable: device failed to match discover_only") | ||||
|     unless check_only($device, 'discover_only'); | ||||
|     unless check_device_only($device, 'discover_only'); | ||||
|  | ||||
|   # cannot check last_discover for as yet undiscovered devices :-) | ||||
|   return 1 if not $device->in_storage; | ||||
| @@ -304,10 +223,10 @@ sub is_arpnipable { | ||||
|   my $device = get_device($ip) or return 0; | ||||
|  | ||||
|   return _bail_msg("is_arpnipable: device matched arpnip_no") | ||||
|     if check_no($device, 'arpnip_no'); | ||||
|     if check_device_no($device, 'arpnip_no'); | ||||
|  | ||||
|   return _bail_msg("is_arpnipable: device failed to match arpnip_only") | ||||
|     unless check_only($device, 'arpnip_only'); | ||||
|     unless check_device_only($device, 'arpnip_only'); | ||||
|  | ||||
|   return _bail_msg("is_arpnipable: cannot arpnip an undiscovered device") | ||||
|     if not $device->in_storage; | ||||
| @@ -338,10 +257,10 @@ sub is_macsuckable { | ||||
|   my $device = get_device($ip) or return 0; | ||||
|  | ||||
|   return _bail_msg("is_macsuckable: device matched macsuck_no") | ||||
|     if check_no($device, 'macsuck_no'); | ||||
|     if check_device_no($device, 'macsuck_no'); | ||||
|  | ||||
|   return _bail_msg("is_macsuckable: device failed to match macsuck_only") | ||||
|     unless check_only($device, 'macsuck_only'); | ||||
|     unless check_device_only($device, 'macsuck_only'); | ||||
|  | ||||
|   return _bail_msg("is_macsuckable: cannot macsuck an undiscovered device") | ||||
|     if not $device->in_storage; | ||||
|   | ||||
| @@ -3,13 +3,13 @@ package App::Netdisco::Util::Node; | ||||
| use Dancer qw/:syntax :script/; | ||||
| use Dancer::Plugin::DBIC 'schema'; | ||||
|  | ||||
| use NetAddr::IP::Lite ':lower'; | ||||
| use App::Netdisco::Util::DNS 'hostname_from_ip'; | ||||
| use Net::MAC; | ||||
| use App::Netdisco::Util::Permission 'check_acl'; | ||||
|  | ||||
| use base 'Exporter'; | ||||
| our @EXPORT = (); | ||||
| our @EXPORT_OK = qw/ | ||||
|   check_node_acl | ||||
|   check_mac | ||||
|   check_node_no | ||||
|   check_node_only | ||||
|   is_nbtstatable | ||||
| @@ -29,68 +29,95 @@ subroutines. | ||||
|  | ||||
| =head1 EXPORT_OK | ||||
|  | ||||
| =head2 check_node_acl( $ip, \@config ) | ||||
| =head2 check_mac( $device, $node, $port_macs? ) | ||||
|  | ||||
| Given the IP address of a node, returns true if any of the items in C<< | ||||
| \@config >> matches that node, otherwise returns false. | ||||
| 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. | ||||
|  | ||||
| Normally you use C<check_node_no> and C<check_node_only>, passing the name of the | ||||
| configuration setting to load. This helper instead requires not the name of | ||||
| the setting, but its value. | ||||
| 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 | ||||
|  | ||||
| =back | ||||
|  | ||||
| Optionally pass a cached set of Device port MAC addresses as the third | ||||
| argument, in which case an additional check is added: | ||||
|  | ||||
| =over 4 | ||||
|  | ||||
| =item * | ||||
|  | ||||
| MAC address does not belong to an interface on any known Device | ||||
|  | ||||
| =back | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub check_node_acl { | ||||
|   my ($ip, $config) = @_; | ||||
|   my $device = get_device($ip) or return 0; | ||||
|   my $addr = NetAddr::IP::Lite->new($device->ip); | ||||
| sub check_mac { | ||||
|   my ($device, $node, $port_macs) = @_; | ||||
|   my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0); | ||||
|   $port_macs ||= {}; | ||||
|  | ||||
|   foreach my $item (@$config) { | ||||
|       if (ref qr// eq ref $item) { | ||||
|           my $name = hostname_from_ip($addr->addr) or next; | ||||
|           return 1 if $name =~ $item; | ||||
|           next; | ||||
|       } | ||||
|  | ||||
|       if ($item =~ m/([a-f0-9]+)-([a-f0-9]+)$/i) { | ||||
|           my $first = $1; | ||||
|           my $last  = $2; | ||||
|  | ||||
|           if ($item =~ m/:/) { | ||||
|               next unless $addr->bits == 128; | ||||
|  | ||||
|               $first = hex $first; | ||||
|               $last  = hex $last; | ||||
|  | ||||
|               (my $header = $item) =~ s/:[^:]+$/:/; | ||||
|               foreach my $part ($first .. $last) { | ||||
|                   my $ip = NetAddr::IP::Lite->new($header . sprintf('%x',$part) . '/128') | ||||
|                     or next; | ||||
|                   return 1 if $ip == $addr; | ||||
|               } | ||||
|           } | ||||
|           else { | ||||
|               next unless $addr->bits == 32; | ||||
|  | ||||
|               (my $header = $item) =~ s/\.[^.]+$/./; | ||||
|               foreach my $part ($first .. $last) { | ||||
|                   my $ip = NetAddr::IP::Lite->new($header . $part . '/32') | ||||
|                     or next; | ||||
|                   return 1 if $ip == $addr; | ||||
|               } | ||||
|           } | ||||
|  | ||||
|           next; | ||||
|       } | ||||
|  | ||||
|       my $ip = NetAddr::IP::Lite->new($item) | ||||
|         or next; | ||||
|       next unless $ip->bits == $addr->bits; | ||||
|  | ||||
|       return 1 if $ip->contains($addr); | ||||
|   # 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; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
|   # 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; | ||||
| } | ||||
|  | ||||
| =head2 check_node_no( $ip, $setting_name ) | ||||
|   | ||||
							
								
								
									
										107
									
								
								Netdisco/lib/App/Netdisco/Util/Permission.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								Netdisco/lib/App/Netdisco/Util/Permission.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| package App::Netdisco::Util::Permission; | ||||
|  | ||||
| use Dancer qw/:syntax :script/; | ||||
| use Dancer::Plugin::DBIC 'schema'; | ||||
|  | ||||
| use Scalar::Util 'blessed'; | ||||
| use NetAddr::IP::Lite ':lower'; | ||||
|  | ||||
| use base 'Exporter'; | ||||
| our @EXPORT = (); | ||||
| our @EXPORT_OK = qw/check_acl/; | ||||
| our %EXPORT_TAGS = (all => \@EXPORT_OK); | ||||
|  | ||||
| =head1 NAME | ||||
|  | ||||
| App::Netdisco::Util::Permission | ||||
|  | ||||
| =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_acl( $ip, \@config ) | ||||
|  | ||||
| Given an IP address, returns true if any of the items in C<< \@config >> | ||||
| matches that address, otherwise returns false. | ||||
|  | ||||
| Normally you use C<check_no> and C<check_only>, passing the name of the | ||||
| configuration setting to load. This helper instead requires not the name of | ||||
| the setting, but its value. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub check_acl { | ||||
|   my ($thing, $config) = @_; | ||||
|   my $real_ip = (blessed $thing ? $thing->ip : $thing); | ||||
|   my $addr = NetAddr::IP::Lite->new($real_ip); | ||||
|  | ||||
|   foreach my $item (@$config) { | ||||
|       if (ref qr// eq ref $item) { | ||||
|           my $name = hostname_from_ip($addr->addr) or next; | ||||
|           return 1 if $name =~ $item; | ||||
|           next; | ||||
|       } | ||||
|  | ||||
|       if ($item =~ m/^([^:]+)\s*:\s*([^:]+)$/) { | ||||
|           my $prop  = $1; | ||||
|           my $match = $2; | ||||
|  | ||||
|           # if not in storage, we can't do much with device properties | ||||
|           next unless blessed $thing and $thing->in_storage; | ||||
|  | ||||
|           # lazy version of vendor: and model: | ||||
|           if ($thing->can($prop) and defined $thing->$prop | ||||
|               and $thing->$prop =~ m/^$match$/) { | ||||
|               return 1; | ||||
|           } | ||||
|  | ||||
|           next; | ||||
|       } | ||||
|  | ||||
|       if ($item =~ m/([a-f0-9]+)-([a-f0-9]+)$/i) { | ||||
|           my $first = $1; | ||||
|           my $last  = $2; | ||||
|  | ||||
|           if ($item =~ m/:/) { | ||||
|               next unless $addr->bits == 128; | ||||
|  | ||||
|               $first = hex $first; | ||||
|               $last  = hex $last; | ||||
|  | ||||
|               (my $header = $item) =~ s/:[^:]+$/:/; | ||||
|               foreach my $part ($first .. $last) { | ||||
|                   my $ip = NetAddr::IP::Lite->new($header . sprintf('%x',$part) . '/128') | ||||
|                     or next; | ||||
|                   return 1 if $ip == $addr; | ||||
|               } | ||||
|           } | ||||
|           else { | ||||
|               next unless $addr->bits == 32; | ||||
|  | ||||
|               (my $header = $item) =~ s/\.[^.]+$/./; | ||||
|               foreach my $part ($first .. $last) { | ||||
|                   my $ip = NetAddr::IP::Lite->new($header . $part . '/32') | ||||
|                     or next; | ||||
|                   return 1 if $ip == $addr; | ||||
|               } | ||||
|           } | ||||
|  | ||||
|           next; | ||||
|       } | ||||
|  | ||||
|       my $ip = NetAddr::IP::Lite->new($item) | ||||
|         or next; | ||||
|       next unless $ip->bits == $addr->bits; | ||||
|  | ||||
|       return 1 if $ip->contains($addr); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| 1; | ||||
| @@ -1,7 +1,8 @@ | ||||
| package App::Netdisco::Util::SNMP; | ||||
|  | ||||
| use Dancer qw/:syntax :script/; | ||||
| use App::Netdisco::Util::Device qw/get_device check_acl check_no/; | ||||
| use App::Netdisco::Util::Device qw/get_device check_device_no/; | ||||
| use App::Netdisco::Util::Permission qw/check_acl/; | ||||
|  | ||||
| use SNMP::Info; | ||||
| use Try::Tiny; | ||||
| @@ -75,7 +76,7 @@ sub _snmp_connect_generic { | ||||
|   ); | ||||
|  | ||||
|   # an override for bulkwalk | ||||
|   $snmp_args{BulkWalk} = 0 if check_no($device, 'bulkwalk_no'); | ||||
|   $snmp_args{BulkWalk} = 0 if check_device_no($device, 'bulkwalk_no'); | ||||
|  | ||||
|   # further protect against buggy Net-SNMP, and disable bulkwalk | ||||
|   if ($snmp_args{BulkWalk} | ||||
| @@ -92,9 +93,9 @@ sub _snmp_connect_generic { | ||||
|  | ||||
|   # which SNMP versions to try and in what order | ||||
|   my @versions = | ||||
|     ( check_no($device->ip, 'snmpforce_v3') ? (3) | ||||
|     : check_no($device->ip, 'snmpforce_v2') ? (2) | ||||
|     : check_no($device->ip, 'snmpforce_v1') ? (1) | ||||
|     ( check_device_no($device->ip, 'snmpforce_v3') ? (3) | ||||
|     : check_device_no($device->ip, 'snmpforce_v2') ? (2) | ||||
|     : check_device_no($device->ip, 'snmpforce_v1') ? (1) | ||||
|     : (reverse (1 .. (setting('snmpver') || 3))) ); | ||||
|  | ||||
|   # use existing or new device class | ||||
| @@ -292,7 +293,7 @@ sub _build_communities { | ||||
|         if not $stanza->{tag} | ||||
|            and !exists $stanza->{community}; | ||||
|  | ||||
|       if ($stanza->{$mode} and check_acl($device, $stanza->{only})) { | ||||
|       if ($stanza->{$mode} and check_acl($device->ip, $stanza->{only})) { | ||||
|           if ($stored_tag and $stored_tag eq $stanza->{tag}) { | ||||
|               # last known-good by tag | ||||
|               unshift @communities, $stanza | ||||
|   | ||||
| @@ -1,118 +0,0 @@ | ||||
| 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 | ||||
|  | ||||
| =back | ||||
|  | ||||
| Optionally pass a cached set of Device port MAC addresses as the third | ||||
| argument, in which case an additional check is added: | ||||
|  | ||||
| =over 4 | ||||
|  | ||||
| =item * | ||||
|  | ||||
| MAC address does not belong to an interface on any known Device | ||||
|  | ||||
| =back | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub check_mac { | ||||
|   my ($device, $node, $port_macs) = @_; | ||||
|   my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0); | ||||
|   $port_macs ||= {}; | ||||
|  | ||||
|   # 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; | ||||
		Reference in New Issue
	
	Block a user