Refs #6124
This commit is contained in:
parent
9acaa029bb
commit
5c4a808850
|
@ -39,12 +39,11 @@ use base qw(centreon::plugins::mode);
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use Time::HiRes qw(gettimeofday tv_interval);
|
||||||
use IO::Socket;
|
use IO::Socket;
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
use Net::DHCP::Packet;
|
use Net::DHCP::Packet;
|
||||||
use Net::DHCP::Constants;
|
use Net::DHCP::Constants;
|
||||||
use Data::Dumper;
|
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %options) = @_;
|
my ($class, %options) = @_;
|
||||||
|
@ -54,70 +53,185 @@ sub new {
|
||||||
$self->{version} = '1.0';
|
$self->{version} = '1.0';
|
||||||
$options{options}->add_options(arguments =>
|
$options{options}->add_options(arguments =>
|
||||||
{
|
{
|
||||||
"serverip:s" => { name => 'serverip' },
|
"serverip:s@" => { name => 'serverip' },
|
||||||
"timeout:s" => { name => 'timeout', default => '3'},
|
"out-first-valid" => { name => 'out_first_valid' },
|
||||||
"macaddr:s" => { name => 'macaddr', default => '999999000000'},
|
"timeout:s" => { name => 'timeout', default => 15 },
|
||||||
|
"macaddr:s" => { name => 'macaddr', default => '999999100000'},
|
||||||
|
"interface:s" => { name => 'interface', default => 'eth0' },
|
||||||
|
"cidr-match:s@" => { name => 'cidr_match' },
|
||||||
});
|
});
|
||||||
|
$self->{unicast} = 0;
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_options {
|
sub check_options {
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
$self->SUPER::init(%options);
|
$self->SUPER::init(%options);
|
||||||
|
|
||||||
|
if (defined($self->{option_results}->{serverip}) && scalar(@{$self->{option_results}->{serverip}}) > 0) {
|
||||||
|
$self->{unicast} = 1;
|
||||||
|
}
|
||||||
|
$self->{subnet_matcher} = undef;
|
||||||
|
if (defined($self->{option_results}->{cidr_match}) && scalar(@{$self->{option_results}->{cidr_match}}) > 0) {
|
||||||
|
centreon::plugins::misc::mymodule_load(output => $self->{output}, module => 'Net::Subnet',
|
||||||
|
error_msg => "Cannot load module 'Net::Subnet'.");
|
||||||
|
$self->{subnet_matcher} = Net::Subnet::subnet_matcher(@{$self->{option_results}->{cidr_match}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub send_discover {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{random_number} = int(rand(0xFFFFFFFF));
|
||||||
|
#Create DHCP Discover Packet
|
||||||
|
my $discover = Net::DHCP::Packet->new(
|
||||||
|
Xid => $self->{random_number},
|
||||||
|
Flags => $self->{unicast} == 1 ? 0 : 0x8000,
|
||||||
|
Chaddr => $self->{option_results}->{macaddr},
|
||||||
|
Giaddr => $self->{my_ip},
|
||||||
|
Hops => $self->{unicast} == 1 ? 1 : 0,
|
||||||
|
DHO_HOST_NAME() => 'centreon',
|
||||||
|
DHO_VENDOR_CLASS_IDENTIFIER() => 'foo',
|
||||||
|
DHO_DHCP_MESSAGE_TYPE() => DHCPDISCOVER(),
|
||||||
|
);
|
||||||
|
my $str = $discover->serialize();
|
||||||
|
#Send UDP Packet
|
||||||
|
$self->{timing0} = [gettimeofday];
|
||||||
|
if ($self->{unicast} == 0) {
|
||||||
|
my $remoteipaddr = sockaddr_in(67, INADDR_BROADCAST);
|
||||||
|
send($self->{socket}, $str, 0, $remoteipaddr);
|
||||||
|
} else {
|
||||||
|
foreach my $server_ip (@{$self->{option_results}->{serverip}}) {
|
||||||
|
my $remoteipaddr = sockaddr_in(67, inet_aton($server_ip));
|
||||||
|
send($self->{socket}, $str, 0, $remoteipaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub create_socket {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
#Create UDP Socket
|
||||||
|
socket($self->{socket}, AF_INET, SOCK_DGRAM, getprotobyname('udp'));
|
||||||
|
setsockopt($self->{socket}, SOL_SOCKET, SO_REUSEADDR, 1);
|
||||||
|
if ($self->{unicast} == 0) {
|
||||||
|
setsockopt($self->{socket}, SOL_SOCKET, SO_BROADCAST, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{my_ip} = undef;
|
||||||
|
if ($self->{unicast} == 1) {
|
||||||
|
$self->{my_ip} = $self->get_interface_address(interface => $self->{option_results}->{interface});
|
||||||
|
}
|
||||||
|
my $port = $self->{unicast} == 1 ? '67' : '68';
|
||||||
|
my $addr = $self->{unicast} == 1 ? inet_aton($self->{my_ip}) : INADDR_ANY;
|
||||||
|
my $binding = bind($self->{socket}, sockaddr_in($port, $addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_interface_address {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
require 'sys/ioctl.ph';
|
||||||
|
my $socket;
|
||||||
|
if (!socket($socket, PF_INET, SOCK_STREAM, (getprotobyname('tcp'))[2])) {
|
||||||
|
$self->{output}->output_add(severity => 'UNKNOWN',
|
||||||
|
short_msg => "cannot get interface address: $!");
|
||||||
|
$self->{output}->display();
|
||||||
|
$self->{output}->exit();
|
||||||
|
}
|
||||||
|
my $buf = pack('a256', $options{interface});
|
||||||
|
if (ioctl($socket, SIOCGIFADDR(), $buf) && (my @address = unpack('x20 C4', $buf))) {
|
||||||
|
return join('.', @address);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{output}->output_add(severity => 'UNKNOWN',
|
||||||
|
short_msg => "cannot get interface address: $!");
|
||||||
|
$self->{output}->display();
|
||||||
|
$self->{output}->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_offer {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
$self->{discresponse} = [];
|
||||||
|
|
||||||
|
#Wait DHCP OFFER Packet
|
||||||
|
my $wait = IO::Select->new($self->{socket});
|
||||||
|
my $timeout = $self->{option_results}->{timeout};
|
||||||
|
my $time = time();
|
||||||
|
$self->{random_number} = sprintf("%x", $self->{random_number});
|
||||||
|
while (my ($found) = $wait->can_read($timeout)) {
|
||||||
|
$timeout -= time() - $time;
|
||||||
|
$time = time();
|
||||||
|
my $srcpaddr = recv($self->{socket}, my $data, 4096, 0);
|
||||||
|
my $response = new Net::DHCP::Packet($data);
|
||||||
|
my $response_readable = $response->toString();
|
||||||
|
# Need to get same Xid and MacAddr in response. Otherwise not for me
|
||||||
|
if ($response_readable =~ /^xid\s+=\s+$self->{random_number}/mi &&
|
||||||
|
$response_readable =~ /^chaddr\s+=\s+$self->{option_results}->{macaddr}/mi) {
|
||||||
|
$self->{timeelapsed} = tv_interval($self->{timing0}, [gettimeofday]);
|
||||||
|
push @{$self->{discresponse}}, $response_readable;
|
||||||
|
last if (defined($self->{option_results}->{out_first_valid}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close $self->{socket};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub check_results {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
foreach my $response (@{$self->{discresponse}}) {
|
||||||
|
$response =~ /DHO_DHCP_LEASE_TIME.*?=\s+(.*?)\n/m;
|
||||||
|
my $lease_time = $1;
|
||||||
|
my $yiaddr;
|
||||||
|
if ($response =~ /^yiaddr\s+=\s+(.*?)\n/m) {
|
||||||
|
$yiaddr = $1;
|
||||||
|
}
|
||||||
|
$response =~ /^siaddr\s+=\s+(.*?)\n/m;
|
||||||
|
my $siaddr = $1;
|
||||||
|
|
||||||
|
$self->{output}->output_add(long_msg => sprintf("Response from %s : offer address %s (lease time: %s)", $siaddr, $yiaddr, $lease_time));
|
||||||
|
if (defined($self->{subnet_matcher})) {
|
||||||
|
if (!$self->{subnet_matcher}->($yiaddr)) {
|
||||||
|
$self->{output}->output_add(severity => 'CRITICAL',
|
||||||
|
short_msg => sprintf("Offer address %s not matching (from: %s)", $yiaddr, $siaddr));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!defined($yiaddr) || $yiaddr eq '' || $yiaddr eq '0.0.0.0' ) {
|
||||||
|
$self->{output}->output_add(severity => 'CRITICAL',
|
||||||
|
short_msg => sprintf("No free lease from %s server", $siaddr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub result {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{output}->output_add(severity => 'OK',
|
||||||
|
short_msg => sprintf("DHCP Server found with free lease"));
|
||||||
|
if (scalar(@{$self->{discresponse}}) == 0) {
|
||||||
|
$self->{output}->output_add(severity => 'CRITICAL',
|
||||||
|
short_msg => sprintf("No DHCPOFFERs were received"));
|
||||||
|
} elsif ($self->{unicast} == 1) {
|
||||||
|
if (scalar(@{$self->{discresponse}}) != scalar(@{$self->{option_results}->{serverip}})) {
|
||||||
|
$self->{output}->output_add(severity => 'CRITICAL',
|
||||||
|
short_msg => sprintf("%d of %d requested servers responded",
|
||||||
|
scalar(@{$self->{discresponse}}), scalar(@{$self->{option_results}->{serverip}})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->check_results();
|
||||||
|
$self->{output}->perfdata_add(label => "time", unit => 'ms',
|
||||||
|
value => sprintf('%.3f', $self->{timeelapsed}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub run {
|
sub run {
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
my ($discover, $socket, $listen, $response, $discresponse, $buf, $serverip);
|
$self->create_socket();
|
||||||
|
$self->send_discover();
|
||||||
#Create DHCP Discover Packet
|
$self->get_offer();
|
||||||
$discover = Net::DHCP::Packet->new(
|
$self->result();
|
||||||
Xid => int(rand(0xFFFFFFFF)),
|
|
||||||
Flags => 0x8000,
|
|
||||||
Chaddr => $self->{option_results}->{macaddr},
|
|
||||||
DHO_HOST_NAME() => 'perl test',
|
|
||||||
DHO_VENDOR_CLASS_IDENTIFIER() => 'foo',
|
|
||||||
DHO_DHCP_MESSAGE_TYPE() => DHCPDISCOVER(),
|
|
||||||
);
|
|
||||||
|
|
||||||
#Create UDP Socket
|
|
||||||
socket($socket, AF_INET, SOCK_DGRAM, getprotobyname('udp'));
|
|
||||||
setsockopt($socket, SOL_SOCKET, SO_REUSEADDR, 1);
|
|
||||||
setsockopt($socket, SOL_SOCKET, SO_BROADCAST, 1);
|
|
||||||
my $remoteipaddr = sockaddr_in(67, INADDR_BROADCAST);
|
|
||||||
my $str = $discover->serialize();
|
|
||||||
my $binding = bind($socket, sockaddr_in('68', INADDR_ANY));
|
|
||||||
|
|
||||||
#Send UDP Packet
|
|
||||||
send($socket, $str, 0, $remoteipaddr);
|
|
||||||
|
|
||||||
#Wait DHCP OFFER Packet
|
|
||||||
my $wait = IO::Select->new($socket);
|
|
||||||
while (my ($found) = $wait->can_read($self->{option_results}->{timeout})) {
|
|
||||||
my $srcpaddr = recv($socket, my $data, 4096, 0);
|
|
||||||
$response = new Net::DHCP::Packet($data);
|
|
||||||
#$discresponse = $response->toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach my $k (keys(%{$response})) {
|
|
||||||
print "Clef=$k Valeur=$response{$k}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
close $socket;
|
|
||||||
|
|
||||||
#Output
|
|
||||||
if ($discresponse !~ /siaddr = $self->{option_results}->{serverip}/) {
|
|
||||||
$self->{output}->output_add(severity => 'CRITICAL',
|
|
||||||
short_msg => sprintf("No DHCP Server found"));
|
|
||||||
} elsif ( $discresponse =~ /yiaddr = 0.0.0.0/ ) {
|
|
||||||
$self->{output}->output_add(severity => 'WARNING',
|
|
||||||
short_msg => sprintf("DHCP Server found with no free lease"));
|
|
||||||
} else {
|
|
||||||
$self->{output}->output_add(severity => 'OK',
|
|
||||||
short_msg => sprintf("DHCP Server found with free lease"));
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{output}->display();
|
$self->{output}->display();
|
||||||
$self->{output}->exit();
|
$self->{output}->exit();
|
||||||
|
@ -132,13 +246,30 @@ Check DHCP server availability
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
=item B<--hostname>
|
=item B<--serverip>
|
||||||
|
|
||||||
IP Addr of the DHCP server
|
IP Addr of the DHCP server to query (do a unicast mode)
|
||||||
|
|
||||||
=item B<--timeout>
|
=item B<--timeout>
|
||||||
|
|
||||||
Connection timeout in seconds (Default: 3)
|
How much time to check dhcp responses (Default: 15 seconds)
|
||||||
|
|
||||||
|
=item B<--out-first-valid>
|
||||||
|
|
||||||
|
Stop after first valid dhcp response
|
||||||
|
|
||||||
|
=item B<--macaddr>
|
||||||
|
|
||||||
|
MAC address to use in the DHCP request
|
||||||
|
|
||||||
|
=item B<--interface>
|
||||||
|
|
||||||
|
Interface to to use for listening (Default: eth0)
|
||||||
|
|
||||||
|
=item B<--cidr-match>
|
||||||
|
|
||||||
|
Match ip addresses offered (can be used multiple times).
|
||||||
|
Returns critical for each ip addresses with no match.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ sub run {
|
||||||
apps::protocols::imap::lib::imap::connect($self, connection_exit => 'critical');
|
apps::protocols::imap::lib::imap::connect($self, connection_exit => 'critical');
|
||||||
apps::protocols::imap::lib::imap::quit();
|
apps::protocols::imap::lib::imap::quit();
|
||||||
|
|
||||||
my $timeelapsed = tv_interval ($timing0, [gettimeofday]);
|
my $timeelapsed = tv_interval($timing0, [gettimeofday]);
|
||||||
|
|
||||||
my $exit = $self->{perfdata}->threshold_check(value => $timeelapsed,
|
my $exit = $self->{perfdata}->threshold_check(value => $timeelapsed,
|
||||||
threshold => [ { label => 'critical', 'exit_litteral' => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]);
|
threshold => [ { label => 'critical', 'exit_litteral' => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]);
|
||||||
|
|
Loading…
Reference in New Issue