Skip to content

Commit

Permalink
src - Check IPSec Site-to-Site vpn connection (#26)
Browse files Browse the repository at this point in the history
* src - Add old vpn check

* src - Use new SNMP values to report VPN status

This feature has been introduced in Sophos XG v20.0
  • Loading branch information
phibos authored Dec 18, 2023
1 parent f048a41 commit cb5f544
Show file tree
Hide file tree
Showing 2 changed files with 297 additions and 4 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,9 @@ Check the state of the services running on the device.
### check_sophos_xg_vpn.pl

> **Warning**
> This plugin might NOT work as expected. Some devices seem to report wrong values or at least values we do not expect from the documentation. If someone finds a way to fix it. Please open a PR.
>
> The plugin has been removed in version 0.4.1. If you wants to fix it please feel free to have a look at the git repository.
> This plugin requires at least Sophos XG v20.0
Check Site-to-Site vpn tunnels and active connections.
Check Site-to-Site vpn connections.

Installation
------------
Expand Down
295 changes: 295 additions & 0 deletions check_sophos_xg_vpn.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
#!/usr/bin/perl
# SPDX-FileCopyrightText: PhiBo from DinoTools (2022)
# SPDX-License-Identifier: GPL-3.0-or-later

use strict;
use warnings FATAL => 'all';

use Pod::Text::Termcap;

use Net::SNMP;

use constant OK => 0;
use constant WARNING => 1;
use constant CRITICAL => 2;
use constant UNKNOWN => 3;

use constant VERSION => '';

my %IPSecVPNConnectionStatus = (
0 => 'inactive',
1 => 'active',
2 => 'partially-active',
);

my %IPSecVPNActivationStatus = (
0 => 'inactive',
1 => 'active',
);

my $pkg_monitoring_available = 0;
BEGIN {
my $pkg_nagios_available = 0;
eval {
require Monitoring::Plugin;
require Monitoring::Plugin::Functions;
require Monitoring::Plugin::Threshold;
$pkg_monitoring_available = 1;
};
if (!$pkg_monitoring_available) {
eval {
require Nagios::Plugin;
require Nagios::Plugin::Functions;
require Nagios::Plugin::Threshold;
*Monitoring::Plugin:: = *Nagios::Plugin::;
$pkg_nagios_available = 1;
};
}
if (!$pkg_monitoring_available && !$pkg_nagios_available) {
print("UNKNOWN - Unable to find module Monitoring::Plugin or Nagios::Plugin\n");
exit UNKNOWN;
}
}

my @g_long_message;
my $parser = Pod::Text::Termcap->new (sentence => 0, width => 78);
my $extra_doc = <<'END_MESSAGE';
=pod
=head1 Requirements
The required information where introduced in Sophos XG v20.0
=head1 Connection state
This check plugin uses the information from the documentation [0] to report the
status of the Site-to-Site VPN connection.
[0] https://doc.sophos.com/nsg/sophos-firewall/20.0/help/en-us/webhelp/onlinehelp/AdministratorHelp/SiteToSiteVPN/IPsec/index.html#connection-status
=cut
END_MESSAGE

my $extra_doc_output;
$parser->output_string(\$extra_doc_output);
$parser->parse_string_document($extra_doc);

my $mp = Monitoring::Plugin->new(
shortname => 'Sophos XG Site-to-Site VPN',
usage => 'This check plugin checks the current the of a Site-to-Site VPN connection',
version => VERSION,
extra => $extra_doc_output,
);

$mp->add_arg(
spec => 'community|C=s',
help => 'Community string (Default: public)',
default => 'public'
);

$mp->add_arg(
spec => 'hostname|H=s',
help => 'Hostname or IP of the device with SNMP access enabled',
required => 1
);

$mp->add_arg(
spec => 'username|u=s',
help => 'Username for SNMPv3',
);

$mp->add_arg(
spec => 'authpassword|A=s',
help => 'Authentication protocol password',
);

$mp->add_arg(
spec => 'authprotocol|a=s',
help => 'Authentication protocol: MD5, SHA, SHA-224, SHA-256, SHA-384, SHA-512 (Default: MD5)',
default => 'md5',
);

$mp->add_arg(
spec => 'privpassword|X=s',
help => 'privacy protocol password',
);

$mp->add_arg(
spec => 'privprotocol|x=s',
help => 'Privacy protocol: DES, AES (Default: DES)',
default => 'des',
);

$mp->add_arg(
spec => 'name=s',
help => 'Name of the VPN tunnel',
);

$mp->add_arg(
spec => 'inactive-ok',
help => 'If it is OK if the activation state of the IPSec tunnel is inactive.',
default => 0,
);

$mp->add_arg(
spec => 'verbose',
help => 'Print verbose/debug information',
default => 0,
);

$mp->getopts;

my ($session, $error);
if (defined($mp->opts->username) && defined($mp->opts->authpassword)) {
# SNMPv3 login
verb('SNMPv3 login');
if (!defined($mp->opts->privpassword)) {
verb('SNMPv3 AuthNoPriv login : %s, %s', $mp->opts->username, $mp->opts->authprotocol);
($session, $error) = Net::SNMP->session(
-hostname => $mp->opts->hostname,
-version => 'snmpv3',
-username => $mp->opts->username,
-authprotocol => $mp->opts->authprotocol,
-authpassword => $mp->opts->authpassword,
);
} else {
verb('SNMPv3 AuthPriv login : %s, %s, %s', $mp->opts->username, $mp->opts->authprotocol, $mp->opts->privprotocol);
($session, $error) = Net::SNMP->session(
-hostname => $mp->opts->hostname,
-version => 'snmpv3',
-username => $mp->opts->username,
-authprotocol => $mp->opts->authprotocol,
-authpassword => $mp->opts->authpassword,
-privprotocol => $mp->opts->privprotocol,
-privpassword => $mp->opts->privpassword,
);
}
} else {
verb('SNMP v2c login');
($session, $error) = Net::SNMP->session(
-hostname => $mp->opts->hostname,
-version => 'snmpv2c',
-community => $mp->opts->community,
);
}

if (!defined($session)) {
wrap_exit(UNKNOWN, $error)
}

check();

my ($code, $message) = $mp->check_messages();
wrap_exit($code, $message . "\n" . join("\n", @g_long_message));

sub check
{
my $sfosIPSecVpnTunnelEntry = '.1.3.6.1.4.1.2604.5.1.6.1.1.1.1';
my $sfosIPSecVpnConnName = $sfosIPSecVpnTunnelEntry . '.2';
my $sfosIPSecVpnConnStatus = $sfosIPSecVpnTunnelEntry . '.9';
my $sfosIPSecVpnActivated = $sfosIPSecVpnTunnelEntry . '.10';

my $result = $session->get_table(
-baseoid => $sfosIPSecVpnTunnelEntry
);

if(!defined $result) {
wrap_exit(UNKNOWN, 'Unable to get information');
}

my $vpn_found = 0;
foreach my $key (keys %$result) {
my $vpn_connection_id = undef;
if (
$key =~ /^$sfosIPSecVpnConnName\.(\d+)$/ &&
$result->{"${sfosIPSecVpnConnName}.${1}"} eq $mp->opts->name
) {
$vpn_found = 1;
$vpn_connection_id = $1;
} else {
next;
}
my $vpn_name = $result->{"${sfosIPSecVpnConnName}.${vpn_connection_id}"};
my $vpn_connection_name = $result->{"${sfosIPSecVpnConnName}.${vpn_connection_id}"};
my $vpn_connection_status = $result->{"${sfosIPSecVpnConnStatus}.${vpn_connection_id}"};
my $vpn_activated = $result->{"${sfosIPSecVpnActivated}.${vpn_connection_id}"};

if ($vpn_activated == 1) {
if ($vpn_connection_status == 0) {
$mp->add_message(
CRITICAL,
sprintf(
'Connection \'%s\' is active, but tunnel isn\'t established.',
$vpn_connection_name,
)
);
} elsif ($vpn_connection_status == 1) {
$mp->add_message(
OK,
sprintf(
'Connection \'%s\' is active and tunnels are established.',
$vpn_connection_name,
)
);
} elsif ($vpn_connection_status == 2) {
$mp->add_message(
WARNING,
sprintf(
'Connection \'%s\' is active, but at least one tunnel isn\'t established.',
$vpn_connection_name,
)
);
} else {
$mp->add_message(
UNKNOWN,
sprintf(
'Connection \'%s\' is active, but an unknown status code has been reported by the devices.',
$vpn_connection_name,
)
);
}
} elsif ($mp->opts->{'inactive-ok'}) {
$mp->add_message(
CRITICAL,
sprintf(
'Connection \'%s\' is not active, but this is ok.',
$vpn_connection_name,
)
);
} else {
$mp->add_message(
CRITICAL,
sprintf(
'Connection \'%s\' is not active',
$vpn_connection_name,
)
);
}

}
if ($vpn_found == 0) {
wrap_exit(
UNKNOWN,
sprintf(
'Connection \'%s\' not found',
$mp->opts->name,
)
);
}
}

sub verb
{
my $t = shift;
if ($mp->opts->verbose) {
printf($t . "\n", @_);
}
}

sub wrap_exit
{
if($pkg_monitoring_available == 1) {
$mp->plugin_exit( @_ );
} else {
$mp->nagios_exit( @_ );
}
}

0 comments on commit cb5f544

Please sign in to comment.