v3
This commit is contained in:
parent
ac853eeda9
commit
eeb231d6c0
@ -1,6 +1,6 @@
|
|||||||
# check_online_status
|
# check_online_status
|
||||||
|
|
||||||
Icinga/Nagios nrpe check script testing online reachability.
|
Icinga/Nagios compatible script for checking if an interface can reach hosts via icmp ping
|
||||||
|
|
||||||
## Install guide (Debian >= 9.0)
|
## Install guide (Debian >= 9.0)
|
||||||
Install required packages
|
Install required packages
|
||||||
|
243
check_online_status
Normal file
243
check_online_status
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
# INTRO:
|
||||||
|
# Script for checking if an interface can reach hosts via icmp ping.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# USAGE:
|
||||||
|
# <script> --src-dev=<ethX> --target=<8.8.8.8> [--target=<2001:4860:4860::8888> ...] [--src-ip=<203.0.113.1|2001:db8::1>] [--family=<AF_INET|AF_INET6>] [--allow-rfc1918] [--allow-rfc4193] [--enable-warning]
|
||||||
|
# * --src-dev source network interface for sending out icmp requests
|
||||||
|
# * --target set icmp test targets, use again for multiple test targets
|
||||||
|
# * --src-ip source ip address of source network interface (OPTIONAL)
|
||||||
|
# * --family set type of network address AF_INET = IPv4, AF_INET6 = IPv6 (OPTIONAL)
|
||||||
|
# * --allow-rfc1918 allow private/local/reserved IPv4 addresses (OPTIONAL)
|
||||||
|
# * --allow-rfc4193 allow private/local/reserved IPv6 addresses (OPTIONAL)
|
||||||
|
# * --enable-warning enable WARNING state and return exit code 2 if applicable (OPTIONAL)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# TIPS AND TRICKS:
|
||||||
|
# 1. always the first valid address of an interface gets select if --src-ip is not set
|
||||||
|
# 2. default --family is "AF_INET" (IPv4), to test the IPv6 connection set it to "AF_INET6"
|
||||||
|
# 2. use multiple targets, as long as one target is reachable the check returns non-CRITICAL
|
||||||
|
# 3. for allowing private or local network addresses, set --allow-rfc1918 and/or --allow-rfc4193
|
||||||
|
# 4. for returning a WARNING state if at least one host if reachable set --enable-warning
|
||||||
|
# 5. setting "0.0.0.0" or "::/0" as --src-ip is the same as setting none (useful for automation)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# INSTALL:
|
||||||
|
# ANY system
|
||||||
|
# * required perl modules:
|
||||||
|
# * Net::Interface
|
||||||
|
# * Net::Oping
|
||||||
|
# * Net::Subnet
|
||||||
|
#
|
||||||
|
# Debian >= 9.0
|
||||||
|
# * required perl packages via apt:
|
||||||
|
# * libnet-interface-perl libnet-subnet-perl libnet-oping-perl liboping0
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# INFORMATION:
|
||||||
|
# Version: 0.3
|
||||||
|
# Created by: fjs.xicon.de <XiCoN-FJS->
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# CHANGELOG:
|
||||||
|
# v0.3 (2020-11-22):
|
||||||
|
# * switched from Net::Ping to Net::Oping
|
||||||
|
# * enabled full IPv6 support
|
||||||
|
# * added RFC4193++ matcher
|
||||||
|
# * added option to allow RFC1918 and RFC4193 addresses
|
||||||
|
# * added option for WARNING state if not all hosts are reachable
|
||||||
|
# * fixed bug where vlan-interfaces like eth2.4 where stripped down to eth2
|
||||||
|
# * extented the manual
|
||||||
|
#
|
||||||
|
# v0.2 (2020-11-03):
|
||||||
|
# * switched to Net::Interface from "manual" regex-ing system commands
|
||||||
|
# * integrated minimal IPv6 support
|
||||||
|
# * added RFC1918 matcher
|
||||||
|
#
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Getopt::Long;
|
||||||
|
use Net::Interface qw(inet_ntop :inet :lower);
|
||||||
|
use Net::Oping;
|
||||||
|
use Net::Subnet;
|
||||||
|
|
||||||
|
my @test_targets = ();
|
||||||
|
my $interface_dev = "";
|
||||||
|
my $interface_ip = "";
|
||||||
|
my $family = "";
|
||||||
|
my $_family = "";
|
||||||
|
my $allow_rfc1918 = 0;
|
||||||
|
my $allow_rfc4193 = 0;
|
||||||
|
my $enable_warning = 0;
|
||||||
|
|
||||||
|
GetOptions ("target=s" => \@test_targets,
|
||||||
|
"src-dev=s" => \$interface_dev,
|
||||||
|
"src-ip=s" => \$interface_ip,
|
||||||
|
"family=s" => \$family,
|
||||||
|
"allow-rfc1918" => \$allow_rfc1918,
|
||||||
|
"allow-rfc4193" => \$allow_rfc4193,
|
||||||
|
"enable-warning" => \$enable_warning
|
||||||
|
)
|
||||||
|
or die("\nUsage: ".$0." --src-dev=<ethX> --target=<8.8.8.8> [--target=<2001:4860:4860::8888> ...] [--src-ip=<203.0.113.1|2001:db8::1>] [--family=<AF_INET|AF_INET6>] [--allow-rfc1918] [--allow-rfc4193] [--enable-warning]\n\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### check if the required arguments are somewhat valid
|
||||||
|
if($interface_dev eq "" or (!defined ($test_targets[0]) or $test_targets[0] eq ""))
|
||||||
|
{
|
||||||
|
print "\nUsage: ".$0." --src-dev=<ethX> --target=<8.8.8.8> [--target=<2001:4860:4860::8888> ...] [--src-ip=<203.0.113.1|2001:db8::1>] [--family=<AF_INET|AF_INET6>] [--allow-rfc1918] [--allow-rfc4193] [--enable-warning]\n\n";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### set AF_INET* vars
|
||||||
|
if($family ne "AF_INET6")
|
||||||
|
{
|
||||||
|
$family = "AF_INET";
|
||||||
|
$_family = Net::Interface::AF_INET();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$family = "AF_INET6";
|
||||||
|
$_family = Net::Interface::AF_INET6();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### get the RFC address ranges
|
||||||
|
my $is_rfc1918 = get_rfc1918_matcher($allow_rfc1918);
|
||||||
|
my $is_rfc4193 = get_rfc4193_matcher($allow_rfc4193);
|
||||||
|
|
||||||
|
|
||||||
|
### get/set source address
|
||||||
|
if($interface_ip eq '' || $interface_ip eq '0.0.0.0' || $interface_ip eq '::/0')
|
||||||
|
{
|
||||||
|
$interface_ip = get_ip_from_interface($interface_dev, $interface_ip, $family, $_family, $is_rfc1918, $is_rfc4193);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### exit UNKNOWN if no source address could be used
|
||||||
|
if($interface_ip eq '') { print "UNKNOWN: couldn't determine an IP on interface '".$interface_dev."!\n"; exit(3); }
|
||||||
|
|
||||||
|
|
||||||
|
### do the icmp tests
|
||||||
|
my $online = check_pings($interface_ip, $interface_dev, $family, @test_targets);
|
||||||
|
|
||||||
|
|
||||||
|
### validate the results
|
||||||
|
if($online == 0)
|
||||||
|
{
|
||||||
|
my $targets = join(", ",@test_targets);
|
||||||
|
print "CRITICAL: uplink (".$interface_ip." @ ".$interface_dev.") can't reach test hosts: ".$targets."!\n";
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
elsif($online < (scalar @test_targets) and $enable_warning == 1)
|
||||||
|
{
|
||||||
|
print "WARNING: uplink (".$interface_ip." @ ".$interface_dev.") is online. (".$online." of ".scalar @test_targets." test hosts reachable)\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print "OK: uplink (".$interface_ip." @ ".$interface_dev.") is online. (".$online." of ".scalar @test_targets." test hosts reachable)\n";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
### FUNCTIONS
|
||||||
|
###
|
||||||
|
|
||||||
|
sub get_ip_from_interface
|
||||||
|
{
|
||||||
|
my ($interface_dev, $interface_ip, $family, $_family, $is_rfc1918, $is_rfc4193) = @_;
|
||||||
|
my $interface;
|
||||||
|
my @infs = Net::Interface->interfaces();
|
||||||
|
|
||||||
|
foreach my $inf (@infs)
|
||||||
|
{
|
||||||
|
if($inf->{'name'} eq $interface_dev)
|
||||||
|
{
|
||||||
|
$interface = $inf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my @addresses = $interface->address($_family);
|
||||||
|
|
||||||
|
foreach my $ip (@addresses)
|
||||||
|
{
|
||||||
|
if($family eq "AF_INET")
|
||||||
|
{
|
||||||
|
$ip = inet_ntoa($ip);
|
||||||
|
if(!$is_rfc1918->($ip))
|
||||||
|
{
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($family eq "AF_INET6")
|
||||||
|
{
|
||||||
|
$ip = inet_ntop($ip);
|
||||||
|
if(!$is_rfc4193->($ip))
|
||||||
|
{
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub check_pings
|
||||||
|
{
|
||||||
|
my ($src,$dev,$family, @test_targets) = @_;
|
||||||
|
my $pings_ok = 0;
|
||||||
|
foreach my $target ( @test_targets )
|
||||||
|
{
|
||||||
|
my $ping_result = ping_test($target,$src,$dev);
|
||||||
|
if(defined($ping_result->{$target}) && $ping_result->{$target} =~/^\d+(?:\.\d+)?/) # match float value
|
||||||
|
{
|
||||||
|
$pings_ok++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $pings_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub ping_test
|
||||||
|
{
|
||||||
|
my ($dst,$src,$dev) = @_;
|
||||||
|
my $oping = Net::Oping->new();
|
||||||
|
$oping->timeout("2");
|
||||||
|
$oping->bind($src);
|
||||||
|
$oping->device($dev);
|
||||||
|
$oping->host_add($dst);
|
||||||
|
return $oping->ping();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_rfc1918_matcher
|
||||||
|
{
|
||||||
|
my ($match) = @_;
|
||||||
|
my @subnets = ();
|
||||||
|
my @real_subnets = ('10.0.0.0/8','172.16.0.0/12','192.168.0.0/16');
|
||||||
|
|
||||||
|
if(!$match) { @subnets = @real_subnets; }
|
||||||
|
my $is_rfc = subnet_matcher @subnets;
|
||||||
|
|
||||||
|
return $is_rfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_rfc4193_matcher
|
||||||
|
{
|
||||||
|
my ($match) = @_;
|
||||||
|
my @subnets = ();
|
||||||
|
my @real_subnets = ('fc00::/7','fe80::/10','2001:0002::/48','2001:0010::/28','2001:db8::/32','ff00::/8');
|
||||||
|
|
||||||
|
if(!$match) { @subnets = @real_subnets; }
|
||||||
|
my $is_rfc = subnet_matcher @subnets;
|
||||||
|
|
||||||
|
return $is_rfc;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user