refactor to make check_no/acl/only share code between device and node paths
This commit is contained in:
@@ -3,7 +3,7 @@ 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::SanityCheck 'check_mac';
|
use App::Netdisco::Util::Node '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';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use Dancer qw/:syntax :script/;
|
|||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
use App::Netdisco::Util::PortMAC 'get_port_macs';
|
use App::Netdisco::Util::PortMAC 'get_port_macs';
|
||||||
use App::Netdisco::Util::SanityCheck 'check_mac';
|
use App::Netdisco::Util::Node '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';
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package App::Netdisco::Core::Nbtstat;
|
|||||||
use Dancer qw/:syntax :script/;
|
use Dancer qw/:syntax :script/;
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
|
||||||
use App::Netdisco::Util::SanityCheck 'check_mac';
|
use App::Netdisco::Util::Node 'check_mac';
|
||||||
use NetAddr::IP::Lite ':lower';
|
use NetAddr::IP::Lite ':lower';
|
||||||
use Time::HiRes 'gettimeofday';
|
use Time::HiRes 'gettimeofday';
|
||||||
use Net::NBName;
|
use Net::NBName;
|
||||||
|
|||||||
@@ -2,17 +2,14 @@ package App::Netdisco::Util::Device;
|
|||||||
|
|
||||||
use Dancer qw/:syntax :script/;
|
use Dancer qw/:syntax :script/;
|
||||||
use Dancer::Plugin::DBIC 'schema';
|
use Dancer::Plugin::DBIC 'schema';
|
||||||
|
use App::Netdisco::Util::Permission 'check_acl';
|
||||||
use NetAddr::IP::Lite ':lower';
|
|
||||||
use App::Netdisco::Util::DNS 'hostname_from_ip';
|
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
our @EXPORT_OK = qw/
|
our @EXPORT_OK = qw/
|
||||||
get_device
|
get_device
|
||||||
check_acl
|
check_device_no
|
||||||
check_no
|
check_device_only
|
||||||
check_only
|
|
||||||
is_discoverable
|
is_discoverable
|
||||||
is_arpnipable
|
is_arpnipable
|
||||||
is_macsuckable
|
is_macsuckable
|
||||||
@@ -60,87 +57,7 @@ sub get_device {
|
|||||||
->find_or_new({ip => $ip});
|
->find_or_new({ip => $ip});
|
||||||
}
|
}
|
||||||
|
|
||||||
=head2 check_acl( $ip, \@config )
|
=head2 check_device_no( $ip, $setting_name )
|
||||||
|
|
||||||
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 )
|
|
||||||
|
|
||||||
Given the IP address of a device, returns true if the configuration setting
|
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
|
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
|
=cut
|
||||||
|
|
||||||
sub check_no {
|
sub check_device_no {
|
||||||
my ($ip, $setting_name) = @_;
|
my ($ip, $setting_name) = @_;
|
||||||
|
my $device = get_device($ip) or return 0;
|
||||||
|
|
||||||
my $config = setting($setting_name) || [];
|
my $config = setting($setting_name) || [];
|
||||||
return 0 if not scalar @$config;
|
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
|
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
|
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
|
=cut
|
||||||
|
|
||||||
sub check_only {
|
sub check_device_only {
|
||||||
my ($ip, $setting_name) = @_;
|
my ($ip, $setting_name) = @_;
|
||||||
|
my $device = get_device($ip) or return 0;
|
||||||
|
|
||||||
my $config = setting($setting_name) || [];
|
my $config = setting($setting_name) || [];
|
||||||
return 1 if not scalar @$config;
|
return 1 if not scalar @$config;
|
||||||
|
|
||||||
return check_acl($ip, $config);
|
return check_acl($device->ip, $config);
|
||||||
}
|
}
|
||||||
|
|
||||||
=head2 is_discoverable( $ip, $device_type? )
|
=head2 is_discoverable( $ip, $device_type? )
|
||||||
@@ -270,10 +189,10 @@ sub is_discoverable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return _bail_msg("is_discoverable: device matched discover_no")
|
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")
|
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 :-)
|
# cannot check last_discover for as yet undiscovered devices :-)
|
||||||
return 1 if not $device->in_storage;
|
return 1 if not $device->in_storage;
|
||||||
@@ -304,10 +223,10 @@ sub is_arpnipable {
|
|||||||
my $device = get_device($ip) or return 0;
|
my $device = get_device($ip) or return 0;
|
||||||
|
|
||||||
return _bail_msg("is_arpnipable: device matched arpnip_no")
|
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")
|
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")
|
return _bail_msg("is_arpnipable: cannot arpnip an undiscovered device")
|
||||||
if not $device->in_storage;
|
if not $device->in_storage;
|
||||||
@@ -338,10 +257,10 @@ sub is_macsuckable {
|
|||||||
my $device = get_device($ip) or return 0;
|
my $device = get_device($ip) or return 0;
|
||||||
|
|
||||||
return _bail_msg("is_macsuckable: device matched macsuck_no")
|
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")
|
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")
|
return _bail_msg("is_macsuckable: cannot macsuck an undiscovered device")
|
||||||
if not $device->in_storage;
|
if not $device->in_storage;
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ 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 NetAddr::IP::Lite ':lower';
|
use Net::MAC;
|
||||||
use App::Netdisco::Util::DNS 'hostname_from_ip';
|
use App::Netdisco::Util::Permission 'check_acl';
|
||||||
|
|
||||||
use base 'Exporter';
|
use base 'Exporter';
|
||||||
our @EXPORT = ();
|
our @EXPORT = ();
|
||||||
our @EXPORT_OK = qw/
|
our @EXPORT_OK = qw/
|
||||||
check_node_acl
|
check_mac
|
||||||
check_node_no
|
check_node_no
|
||||||
check_node_only
|
check_node_only
|
||||||
is_nbtstatable
|
is_nbtstatable
|
||||||
@@ -29,68 +29,95 @@ subroutines.
|
|||||||
|
|
||||||
=head1 EXPORT_OK
|
=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<<
|
Given a Device database object and a MAC address, perform various sanity
|
||||||
\@config >> matches that node, otherwise returns false.
|
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
|
Returns false, and might log a debug level message, if the checks fail.
|
||||||
configuration setting to load. This helper instead requires not the name of
|
|
||||||
the setting, but its value.
|
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
|
=cut
|
||||||
|
|
||||||
sub check_node_acl {
|
sub check_mac {
|
||||||
my ($ip, $config) = @_;
|
my ($device, $node, $port_macs) = @_;
|
||||||
my $device = get_device($ip) or return 0;
|
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0);
|
||||||
my $addr = NetAddr::IP::Lite->new($device->ip);
|
$port_macs ||= {};
|
||||||
|
|
||||||
foreach my $item (@$config) {
|
# incomplete MAC addresses (BayRS frame relay DLCI, etc)
|
||||||
if (ref qr// eq ref $item) {
|
if ($mac->get_error) {
|
||||||
my $name = hostname_from_ip($addr->addr) or next;
|
debug sprintf ' [%s] check_mac - mac [%s] malformed - skipping',
|
||||||
return 1 if $name =~ $item;
|
$device->ip, $node;
|
||||||
next;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if ($item =~ m/([a-f0-9]+)-([a-f0-9]+)$/i) {
|
# lower case, hex, colon delimited, 8-bit groups
|
||||||
my $first = $1;
|
$node = lc $mac->as_IEEE;
|
||||||
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;
|
# 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 )
|
=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;
|
package App::Netdisco::Util::SNMP;
|
||||||
|
|
||||||
use Dancer qw/:syntax :script/;
|
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 SNMP::Info;
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
@@ -75,7 +76,7 @@ sub _snmp_connect_generic {
|
|||||||
);
|
);
|
||||||
|
|
||||||
# an override for bulkwalk
|
# 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
|
# further protect against buggy Net-SNMP, and disable bulkwalk
|
||||||
if ($snmp_args{BulkWalk}
|
if ($snmp_args{BulkWalk}
|
||||||
@@ -92,9 +93,9 @@ sub _snmp_connect_generic {
|
|||||||
|
|
||||||
# which SNMP versions to try and in what order
|
# which SNMP versions to try and in what order
|
||||||
my @versions =
|
my @versions =
|
||||||
( check_no($device->ip, 'snmpforce_v3') ? (3)
|
( check_device_no($device->ip, 'snmpforce_v3') ? (3)
|
||||||
: check_no($device->ip, 'snmpforce_v2') ? (2)
|
: check_device_no($device->ip, 'snmpforce_v2') ? (2)
|
||||||
: check_no($device->ip, 'snmpforce_v1') ? (1)
|
: check_device_no($device->ip, 'snmpforce_v1') ? (1)
|
||||||
: (reverse (1 .. (setting('snmpver') || 3))) );
|
: (reverse (1 .. (setting('snmpver') || 3))) );
|
||||||
|
|
||||||
# use existing or new device class
|
# use existing or new device class
|
||||||
@@ -292,7 +293,7 @@ sub _build_communities {
|
|||||||
if not $stanza->{tag}
|
if not $stanza->{tag}
|
||||||
and !exists $stanza->{community};
|
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}) {
|
if ($stored_tag and $stored_tag eq $stanza->{tag}) {
|
||||||
# last known-good by tag
|
# last known-good by tag
|
||||||
unshift @communities, $stanza
|
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