monitoring-plugins-cyconet/check_wireguard/check_wireguard

130 lines
4 KiB
Perl

#!/usr/bin/env perl
use strict;
use warnings;
use Monitoring::Plugin::Getopt;
use Monitoring::Plugin::Functions;
my $VERSION = '0.5.0';
my $default_binary = '/usr/bin/wg';
my $default_interfaces_expected = 1;
my $default_seconds_connected = 300;
# Get Opts
my $go = Monitoring::Plugin::Getopt->new(
usage => "Usage: %s [ -b $default_binary ] [ -i $default_interfaces_expected ] [ -s $default_seconds_connected ]",
version => $VERSION,
url => 'https://gitlab.com/alasdairkeyes/nagios-plugin-check_wireguard',
blurb => "Check wireguard server.",
);
$go->arg(
spec => 'binary|b=s',
help => "The full path to the wg executable. (default: $default_binary)",
required => 0,
default => $default_binary,
);
$go->arg(
spec => 'interfaces|i=i',
help => "The number of interfaces expected to be found. (default: $default_interfaces_expected)",
required => 1,
default => $default_interfaces_expected,
);
$go->arg(
spec => 'seconds_connected|s=i',
help => "A peer is considered connected if a handshake has been set within this many seconds. If set to 0 it will always be considered connected if at least one handshake has been sent. (default: $default_seconds_connected)",
required => 1,
default => $default_seconds_connected,
);
$go->getopts;
my $binary = $go->binary;
my $interfaces_expected = $go->interfaces;
my $seconds_connected = $go->seconds_connected;
# Check binary is usable
plugin_exit ( CRITICAL, "Path $binary is not executable")
unless (-x $binary);
# Execute
my $output = `$binary show`;
# Parse and process wg output
my $data = parse_output($output);
process_output($data);
sub parse_output {
my $output = shift;
my @lines = split(/\n/, $output);
my $data = {};
my $interface;
foreach my $line (@lines) {
if ($line =~ /^interface:\s+(.*)$/) {
$interface = $1;
$data->{ $interface }{ peers } = 0;
$data->{ $interface }{ connected } = 0;
next;
}
# Increment peer and connected counters
if ($line =~ /^peer:\s+(.*)$/) {
$data->{ $interface }{ peers }++;
} elsif ($line =~ /^\s+latest handshake:\s+(.*)$/) {
$data->{ $interface }{ connected }++
if (!$seconds_connected || (seconds_since_handshake($1) < $seconds_connected));
}
}
return $data;
}
sub seconds_since_handshake {
my $handshake_time_value = shift;
my $seconds = 0;
foreach my $time_section (split (/,\s?/, $handshake_time_value)) {
if ($time_section eq "Now") {
$seconds += 1;
} elsif ($time_section =~ /^(\d+)\s+(\w+)\b/) {
my $time_value = $1;
my $time_denomination = $2;
# Convert times into a single second value
if ($time_denomination =~ /^years?/) {
$seconds += $time_value * 60 * 60 * 24 * 365;
} elsif ($time_denomination =~ /^days?/) {
$seconds += $time_value * 60 * 60 * 24;
} elsif ($time_denomination =~ /^hours?/) {
$seconds += $time_value * 60 * 60;
} elsif ($time_denomination =~ /^minutes?/) {
$seconds += $time_value * 60;
} elsif ($time_denomination =~ /^seconds?/) {
$seconds += $time_value;
}
} else {
die "Unknown handshake value: $handshake_time_value";
}
}
return $seconds;
}
sub process_output {
my $data = shift;
my $number_of_interfaces = scalar(keys(%$data));
my $result_string = "Interfaces: Online:$number_of_interfaces Expected:$interfaces_expected";
foreach my $interface (sort(keys(%$data))) {
$result_string .= " $interface:$data->{ $interface }{ connected }/$data->{ $interface }{ peers }";
}
my $status = OK;
$status = CRITICAL
if ($number_of_interfaces != $interfaces_expected);
plugin_exit ( $status, $result_string);
}