Search
j0ke.net Open Build Service
>
Projects
>
server:monitoring
>
nagios-plugins-snmp
> check_fortigate.pl
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File check_fortigate.pl of Package nagios-plugins-snmp
#!/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"; } } # end scalar count # if preferred master serial is not master if ( $pri_serial && ( $pri_serial ne $curr_serial ) ) { $string = $string . ", preferred master " . $pri_serial . " is not master!"; $state = "CRITICAL"; } # Write an output string... $string = $state . ": " . $curr_device . " (Master: " . $curr_serial . ", Slave: " . @help_serials[$#help_serials] . "): " . $string; return ($state, $string); } # end cluster state sub get_vpn_state { my $ipstunsdown = 0; my $ipstuncount = 0; my $ipstunsopen = 0; my $ActiveSSL = 0; my $ActiveSSLTunnel = 0; my $string_errors = ""; my %entitystate = ( '1' => 'down', # Enumeration for the tunnel up/down states '2' => 'up' ); $state = "OK"; # Unless specifically requesting IPSec checks only, do an SSL connection check if ($vpnmode ne "ipsec"){ $ActiveSSL = get_snmp_value($session, $oid_ActiveSSL); $ActiveSSLTunnel = get_snmp_value($session, $oid_ActiveSSLTunnel); } # Unless specifically requesting SSL checks only, do an IPSec tunnel check if ($vpnmode ne "ssl"){ # Get just the top level tunnel data my %tunnels = %{get_snmp_table($session, $oid_ipsectuntableroot . $oidf_tunndx)}; while (($oid, $value) = each (%tunnels)) { #Bump the total tunnel count $ipstuncount++; #print "Tunnel name (" . $oid_ipsectuntableroot . $oidf_tunname . "." . $ipstuncount . ") is: " . get_snmp_value($session, $oid_ipsectuntableroot . $oidf_tunname . "." . $ipstuncount) . "\n"; #print "Tunnel status (" . $oid_ipsectuntableroot . $oidf_tunstatus . "." . $ipstuncount . ") is: " . get_snmp_value($session, $oid_ipsectuntableroot . $oidf_tunstatus . "." . $ipstuncount) . "\n"; #If the tunnel is up, bump the connected tunnel count if ( $entitystate{get_snmp_value($session, $oid_ipsectuntableroot . $oidf_tunstatus . "." . $ipstuncount)} eq "up" ) { $ipstunsopen++; } else { #Tunnel is down. Add it to the failed counter $ipstunsdown++; # If we're counting failures and/or monitoring, put together an output error string of the tunnel name and its status if ($mode >= 1){ $string_errors .= ", "; $string_errors .= get_snmp_value($session, $oid_ipsectuntableroot . $oidf_tunname . "." . $ipstuncount)." ".$entitystate{get_snmp_value($session, $oid_ipsectuntableroot . $oidf_tunstatus . "." . $ipstuncount)}; } } } } #Set Unitstate my $unitstate="OK"; if (($mode >= 2 ) && ($vpnmode ne "ssl")) { if ($ipstunsdown == 1) { $unitstate="WARNING"; } if ($ipstunsdown >= 2) { $unitstate="CRITICAL"; } } # Write an output string... $string = $unitstate . ": " . $curr_device . " (Master: " . $curr_serial .")"; if ($vpnmode ne "ipsec") { #Add the SSL tunnel count $string = $string . ": Active SSL-VPN Connections/Tunnels: " . $ActiveSSL."/".$ActiveSSLTunnel.""; } if ($vpnmode ne "ssl") { #Add the IPSec tunnel count and any errors.... $string = $string . ": IPSEC Tunnels: Configured/Active: " . $ipstuncount . "/" . $ipstunsopen. " " . $string_errors; } # Create performance data $perf="|'ActiveSSL-VPN'=".$ActiveSSL." 'ActiveIPSEC'=".$ipstunsopen; $string = $string.$perf; # Check to see if the output string contains either "unkw", "WARNING" or "down", and set an output state accordingly... if($string =~/uknw/){ $state = "UNKNOWN"; } if($string =~/WARNING/){ $state = "WARNING"; } if($string =~/down/){ $state = "CRITICAL"; } return ($state, $string); } # end vpn state sub close_snmp_session{ my $session = $_[0]; $session->close(); } # end close snmp session sub get_snmp_value{ my $session = $_[0]; my $oid = $_[1]; my (%result) = %{get_snmp_request($session, $oid) or die ("SNMP service is not available on ".$ip) }; return $result{$oid}; } # end get snmp value sub get_snmp_request{ my $session = $_[0]; my $oid = $_[1]; return $session->get_request($oid) || die ("SNMP service not responding"); } # end get snmp request sub get_snmp_table{ my $session = $_[0]; my $oid = $_[1]; return $session->get_table( -baseoid =>$oid ); } # end get snmp table sub parse_args { my $ip = ""; my $community = "public"; my $pri_serial = ""; my $reset_file = ""; my $type = "status"; my $warn = 80; my $crit = 90; my $slave = 0; my $vpnmode = "both"; my $mode = 2; my $help = 0; pod2usage(-message => "UNKNOWN: No Arguments given", -exitval => 3, -verbose => 0) if ( !@ARGV ); GetOptions( 'host|H=s' => \$ip, 'type|T=s' => \$type, 'community|C:s' => \$community, 'serial|S:s' => \$pri_serial, 'vpnmode|V:s' => \$vpnmode, 'mode|M:s' => \$mode, 'warning|w:i' => \$warn, 'critical|c:i' => \$crit, 'slave|s:1' => \$slave, 'reset|R:1' => \$reset_file, 'help|?!' => \$help, ) or pod2usage(-exitval => 3, -verbose => 0); pod2usage(-exitval => 3, -verbose => 2) if $help; return ($ip, $community, $type, $warn, $crit, $slave, $pri_serial, $reset_file, $mode, $vpnmode); } __END__ =head1 NAME Check Fortinet FortiGate Appliances =head1 SYNOPSIS =item S<check_fortigate.pl -H -C -T [-w|-c|-S|-s|-R|-M|-V|-?]> Options: -H --host STRING or IPADDRESS Check interface on the indicated host -C --community STRING Community-String for SNMP -T -- type STRING CPU, MEM, Ses, VPN, Cluster -S --serial STRING Primary serial number -s --slave get values of slave -w --warning INTEGER Warning threshold, applies to cpu, mem, session. -c --critical INTEGER Critical threshold, applies to cpu, mem, session. -R --reset Resets ip file (cluster only) -M --mode STRING Output-Mode: 0 => just print, 1 => print and show failed tunnel, 2 => critical -V --vpnmode STRING VPN-Mode: both => IPSec & SSL/OpenVPN, ipsec => IPSec only, ssl => SSL/OpenVPN only -? --help Returns full help text =head1 OPTIONS =over 8 =item B<-H--host> STRING or IPADDRESS - Check interface on the indicated host. =item B<-C|--community> STRING - Community-String for SNMP =item B<-T|--type> STRING - CPU, MEM, net, Ses, VPN, Cluster =item B<-S|--serial> STRING - Primary serial number. =item B<-s|--slave> BOOL - Get values of slave =item B<-w|--warning> INTEGER - Warning threshold, applies to cpu, mem, session. =item B<-c|--critical> INTEGER - Critical threshold, applies to cpu, mem, session. =item B<-R|--reset> BOOL - Resets ip file (cluster only) =item B<-M|--mode> STRING - Output-Mode: 0 => just print, 1 => print and show failed tunnel, 2 => critical =item B<-V|--vpnmode> STRING - VPN-Mode: both => IPSec & SSL/OpenVPN, ipsec => IPSec only, ssl => SSL/OpenVPN only =back =head1 DESCRIPTION This plugin checks Fortinet FortiGate devices via SNMP =head2 From Web: =item 1. Select Network -> Interface -> Local interface =item 2. Administrative Access: Enable SNMP =item 3. Select Config -> SNMP =item 4. Enable SNMP, fill your details =item 5. SNMP v1/v2c: Create new =item 6. Configure for your needs, Traps are not required for this plugin! =head2 From CLI: config system interface edit "internal" set allowaccess ping https ssh snmp fgfm next end config system snmp sysinfo set description "DMZ1 FortiGate 300C" set location "Room 404" set conctact-info "BOFH" set status enable end config system snmp community edit 1 set events cpu-high mem-low fm-if-change config hosts edit 1 set interface "internal" set ip %SNMP Client IP% next end set name "public" set trap-v1-status disable set trap-v2c-status disable next end Thats it! =cut # EOF