|
@@ -0,0 +1,487 @@
+#!/usr/bin/perl
+# This Plugin checks the cluster state of FortiGate
+# Tested on: FortiGate 100D / FortiGate 300C (both 5.0.3)
+# Tested on: FortiGate 100D / FortiGate 300C (both 5.0.3)
+#
+# Author: Oliver Skibbe (oliskibbe (at) gmail.com)
+# Date: 2013-01-16
+#
+# Changelog:
+# - initial release (cluster, cpu, memory, session support)
+# - added vpn support, based on check_fortigate_vpn.pl: Copyright (c) 2009 Gerrit Doornenbal, g(dot)doornenbal(at)hccnet(dot)nl
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# If you wish to receive a copy of the GNU General Public License,
+# write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-130
+# Description:
+
+use strict;
+use Net::SNMP;
+use List::Compare;
+use Switch;
+use Getopt::Long qw(:config no_ignore_case bundling);
+use Pod::Usage;
+
+my $script = "check_fortigate.pl";
+my $script_version = "1.2";
+
+# Parse out the arguments...
+my ($ip, $community, $type, $warn, $crit, $slave, $pri_serial, $reset_file, $mode, $vpnmode) = parse_args();
+
+# Initialize variables....
+my $net_snmp_debug_level = 0x0; # See http://search.cpan.org/~dtown/Net-SNMP-v6.0.1/lib/Net/SNMP.pm#debug()_-_set_or_get_the_debug_mode_for_the_module
+ # for more information.
+my %status = ( 'UNKNOWN' => '-1', # Enumeration for the output Nagios states
+ 'OK' => '0',
+ 'WARNING' => '1',
+ 'CRITICAL' => '2' );
+
+## SNMP ##
+my ($session, $error) = get_snmp_session($ip, $community); # Open an SNMP connection...
+
+## OIDs ##
+my $oid_unitdesc = ".1.3.6.1.2.1.1.1.0"; # Location of Fortinet device description... (String)
+my $oid_serial = ".1.3.6.1.2.1.1.5.0"; # Location of Fortinet serial number (String)
+my $oid_cluster_type = ".1.3.6.1.4.1.12356.101.13.1.1.0"; # Location of Fortinet serial number (String)
+my $oid_cluster_serials = ".1.3.6.1.4.1.12356.101.13.2.1.1.2"; # Location of Cluster serials (String)
+my $oid_cpu = ".1.3.6.1.4.1.12356.101.13.2.1.1.3"; # Location of cluster member CPU (%)
+my $oid_net = ".1.3.6.1.4.1.12356.101.13.2.1.1.5"; # Location of cluster member Net (int, UOM ?)
+my $oid_mem = ".1.3.6.1.4.1.12356.101.13.2.1.1.4"; # Location of cluster member Mem (%)
+my $oid_ses = ".1.3.6.1.4.1.12356.101.13.2.1.1.6"; # Location of cluster member Sessions (int)
+
+# VPN OIDs
+my $oid_ActiveSSL = ".1.3.6.1.4.1.12356.101.12.2.3.1.2.1"; # Location of Fortinet firewall SSL VPN Tunnel connection count
+my $oid_ActiveSSLTunnel = ".1.3.6.1.4.1.12356.101.12.2.3.1.6.1"; # Location of Fortinet firewall SSL VPN Tunnel connection count
+my $oid_ipsectuntableroot = ".1.3.6.1.4.1.12356.101.12.2.2.1"; # Table of IPSec VPN tunnels
+my $oidf_tunstatus = ".20"; # Location of a tunnel's connection status
+my $oidf_tunndx = ".1"; # Location of a tunnel's index...
+my $oidf_tunname = ".3"; # Location of a tunnel's name...
+
+## Stuff ##
+my $state; # return state
+my $path = "/usr/lib/nagios/plugins/FortiSerial"; # path to store serial filenames
+my $filename = $path . "/" . $ip; # file name to store serials
+my $oid; # helper var
+my $value; # helper var
+my $string; # return string
+my $perf; # performance data
+
+# Check SNMP connection and get the description of the device...
+my $curr_device = get_snmp_value($session, $oid_unitdesc);
+# Check SNMP connection and get the serial of the device...
+my $curr_serial = get_snmp_value($session, $oid_serial);
+
+switch ( lc($type) ) {
+ case "cpu" { ($state, $string) = get_health_value($oid_cpu, "CPU", "%"); }
+ case "mem" { ($state, $string) = get_health_value($oid_mem, "Memory", "%"); }
+ case "net" { ($state, $string) = get_health_value($oid_net, "Network", ""); }
+ case "ses" { ($state, $string) = get_health_value($oid_ses, "Session", ""); }
+ case "vpn" { ($state, $string) = get_vpn_state(); }
+ else { ($state, $string) = get_cluster_state(); }
+}
+
+# Close the connection
+close_snmp_session($session);
+
+# exit with a return code matching the state...
+print $string."\n";
+exit($status{$state});
+
+########################################################################
+## Subroutines below here....
+########################################################################
+sub get_snmp_session{
+ my $ip = $_[0];
+ my $community = $_[1];
+ my ($session, $error) = Net::SNMP->session(
+ -hostname => $ip,
+ -community => $community,
+ -port => 161,
+ -timeout => 5,
+ -retries => 3,
+ -debug => $net_snmp_debug_level,
+ -version => 2,
+ -translate => [-timeticks => 0x0] #schaltet Umwandlung von Timeticks in Zeitformat aus
+ );
+ return ($session, $error);
+} # end get snmp session
+
+sub get_health_value {
+
+ my $label = $_[1];
+ my $UOM = $_[2];
+
+ if ( $slave == 1 ) {
+ $oid = $_[0] . ".2";
+ $label = "slave_" . $label;
+ } else {
+ $oid = $_[0] . ".1";
+ }
+
+ $value = get_snmp_value($session, $oid);
+
+ if ( $value >= $crit . $UOM ) {
+ $state = "CRITICAL";
+ $string = $label . " is critical: " . $value . $UOM;
+ } elsif ( $value >= $warn . $UOM ) {
+ $state = "WARNING";
+ $string = $label . " is warning: " . $value . $UOM;
+ } else {
+ $state = "OK";
+ $string = $label . " is okay: " . $value. $UOM;
+ }
+
+ $perf = "|'" . lc($label) . "'=" . $value . $UOM . ";" . $warn . ";" . $crit;
+ $string = $state . ": " . $curr_device . " (Master: " . $curr_serial .") " . $string . $perf;
+ return ($state, $string);
+
+} # end health value
+
+sub get_cluster_state {
+
+ my @help_serials; # helper array
+
+ # get all cluster member serials
+ my %snmp_serials = %{get_snmp_table($session, $oid_cluster_serials)};
+ my $cluster_type = get_snmp_value($session, $oid_cluster_type);
+
+ my %cluster_types = (1 => "Standalone", 2 => "Active/Active", 3 => "Active/Passive");
+
+ # first time, write cluster members to helper file
+ if ( ! -e $filename || $reset_file ) {
+ # open file handle to write (create/truncate)
+ open (SERIALHANDLE,"+>$filename") || die "Error while creating $filename";
+
+ # write serials to file
+ while (($oid, $value) = each (%snmp_serials)) {
+ print (SERIALHANDLE $value . "\n");
+ }
+ }
+
+ # snmp serials
+ while (($oid, $value) = each (%snmp_serials)) {
+ chomp; # remove "\n" if exists
+ push @help_serials, $value;
+ }
+
+ # if less then 2 nodes found: critical
+ if ( scalar(@help_serials) < 2 ) {
+ $string = "HA (" . $cluster_types{$cluster_type} . ") inactive, single node found: " . $curr_serial;
+ $state = "CRITICAL";
+ # else check if there are differences in ha nodes
+ } else {
+ # open existing serials
+ open ( SERIALHANDLE, "$filename") || die "Error while opening file $filename";
+ my @file_serials = <SERIALHANDLE>; # push lines into file_serials
+ chomp(@file_serials); # remove "\n" if exists in array elements
+ close (SERIALHANDLE); # close file handle
+
+
+ # compare serial arrays
+ my $comparedList = List::Compare->new('--unsorted', \@help_serials, \@file_serials);
+
+ if ( $comparedList->is_LequivalentR ) {
+ $string = "HA (" . $cluster_types{$cluster_type} . ") is active";
+ $state = "OK";
+ } else {
+ $string = "Unknown node in active HA (" . $cluster_types{$cluster_type} . ") found";
+ $state = "WARNING";
+ }
|