Nagios проверка срока SSL сертификатов

Nagios проверка срока SSL сертификатов

Для нагиоса есть набор плагинов http://www.jhweiss.de/software/nagios.html. И в списке плагинов есть чекалка сертификатов check_certexp.pl. Однако если у вас сертификат нужно проверять для ipv6, то данный скрипт не работает. Я исправил текущий плагин для проверки сроков действия сертификатов для хоста по его имени для всех его ip, как ipv4 так и ipv6. Вот как его можно исправить для себя.

#!/usr/bin/perl -w

# $Id: check_certexp,v 1.1 2006/03/10 18:25:35 holger Exp $
#
# check certificate expiry
#
# Copyright (c) 2006 Holger Weiss <Этот адрес электронной почты защищен от спам-ботов. У вас должен быть включен JavaScript для просмотра. >
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
#Changed by Kuleshov Sergey

use strict;
#use Socket6;
Socket6->import(qw(inet_pton getaddrinfo));
use IO::Socket::INET6;
#use Socket;
#use IO::Socket::INET;

use Getopt::Long;
use Net::SSLeay;
use Date::Manip;

use lib "/usr/local/libexec/nagios";
use utils qw(%ERRORS $TIMEOUT &print_revision &support);
use vars qw($PROGNAME $PORT $CRIT $opt_H $opt_V $opt_c $opt_h $opt_p
            $opt_t $opt_v $opt_w);

sub days_until_expiry ($$);
sub expiry_date ($$);
sub die_crit ($);
sub die_warn ($);
sub die_unknown ($);
sub print_usage ();
sub print_help ();
my ($ssl_port, $warning, $critical, $timeout, $days);

$PROGNAME = "check_certexp";
$PORT = 443;
$CRIT = 28;
$SIG{'ALRM'} = sub { die_unknown("Timeout"); };
$ENV{'PATH'} = '';
$ENV{'ENV'} = '';
$ENV{'TZ'} = 'CET';

Getopt::Long::Configure("bundling");
if (!GetOptions("V" => \$opt_V, "version" => \$opt_V,
            "h" => \$opt_h, "help" => \$opt_h,
            # actually, we won't produce any verbose output
            "v+" => \$opt_v, "verbose+" => \$opt_v,
            "H=s" => \$opt_H, "hostname=s" => \$opt_H,
            "c=i" => \$opt_c, "critical=i" => \$opt_c,
            "p=i" => \$opt_p, "port=i" => \$opt_p,
            "t=i" => \$opt_t, "timeout=i" => \$opt_t,
            "w=i" => \$opt_w, "warning=i" => \$opt_w)) {
    print "CERTEXP UNKNOWN - Error processing command line options\n";
    print_usage();
    exit $ERRORS{'UNKNOWN'};
}
if ($opt_V) {
    print_revision($PROGNAME,'$Revision: 1.1 $ ');
    exit $ERRORS{'OK'};
}
if ($opt_h) {
    print_help();
    exit $ERRORS{'OK'};
}
unless ($opt_H) {
    print "CERTEXP UNKNOWN - No target host specified\n";
    print_usage();
    exit $ERRORS{'UNKNOWN'};
}

if ( ($opt_H=~/((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)/) or ($opt_H=~/((^|:)([0-9a-fA-F]{0,4})){1,8}$/) ) {
    print "CERTEXP UNKNOWN - No target host specified\n";
    print_usage();
    exit $ERRORS{'UNKNOWN'};
}

$critical = $opt_c ? $opt_c : $CRIT;
$warning = $opt_w ? $opt_w : $critical;
if ($warning < $critical) {
    print "CERTEXP UNKNOWN - Warning smaller than critical threshold\n";
    print_usage();
    exit $ERRORS{'UNKNOWN'};
}
$ssl_port = $opt_p ? $opt_p : $PORT;
$timeout = $opt_t ? $opt_t : $TIMEOUT;
alarm($timeout);

my @crit_ip;my @warn_ip;my $ret = 0;
my @ip4 = `/usr/bin/host $opt_H | /usr/bin/grep -v IPv6 | /usr/bin/awk '{print \$4}'`;
chomp @ip4;
my @ip6 = `/usr/bin/host $opt_H | /usr/bin/grep IPv6 | /usr/bin/awk '{print \$5}'`;
chomp @ip6;

my @ip = (@ip4, @ip6);
my $ipv;

foreach (@ip) {
    $opt_H = $_;
    if ($opt_H =~ /((^|:)([0-9a-fA-F]{0,4})){1,8}$/) {$ipv = 6} else {$ipv = 4}
    $days = days_until_expiry($opt_H, $ssl_port);
    $days =~ s/^-// && die_crit("certificate expired $days days ago") if $days < 0;
    $ret = die_crit("certificate expires in $days days for $opt_H;") if $days < $critical;
    if ($ret == 2) {push @crit_ip, $opt_H;next}
    $ret = die_warn("certificate expires in $days days for $opt_H;") if $days < $warning;
    if ($ret == 1) {push @warn_ip, $opt_H;next}
    print "OK for $opt_H - cert expires in $days days;";
    #exit $ERRORS{'OK'};
}

exit 1 if @warn_ip;
exit 2 if @crit_ip;

sub days_until_expiry ($$) {
    my ($host, $port) = @_;

    (my $exp = expiry_date($host, $port)) =~ s/ GMT//;
    int((&UnixDate(&ParseDate($exp),"%s") - time) / 86400);
}

sub expiry_date ($$) {
    my ($host, $port) = @_;
    my ($buffer, $iaddr, $paddr, $ctx, $ssl, $crt, $end, $str);

# connect socket
    $iaddr = $ipv eq '4' ? inet_pton(AF_INET,$host) : inet_pton(AF_INET6,$host)
    || die_unknown("Invalid hostname/address: $host");
    $paddr = $ipv == 4 ? sockaddr_in($port, $iaddr) : sockaddr_in6($port, $iaddr);
    if ($ipv == 4) {socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp')) || die_unknown("Socket error: $!")}
    else {socket(SOCK, PF_INET6, SOCK_STREAM, getprotobyname('tcp')) || die_unknown("Socket error: $!")}
    connect(SOCK, $paddr) || die_unknown("Error connecting to $host: $!");

# initialize SSL
    Net::SSLeay::load_error_strings();
    Net::SSLeay::SSLeay_add_ssl_algorithms();
    Net::SSLeay::randomize();

    $ctx = Net::SSLeay::CTX_new();
    $ssl = Net::SSLeay::new($ctx);

    Net::SSLeay::set_fd($ssl, fileno(SOCK));
    Net::SSLeay::connect($ssl) || die_unknown(Net::SSLeay::print_errs());

# get certificate
    $crt = Net::SSLeay::get_peer_certificate($ssl)
    || die_unknown(Net::SSLeay::print_errs());

# get expiry date (string)
    $end = Net::SSLeay::X509_get_notAfter($crt);
    $str = Net::SSLeay::P_ASN1_UTCTIME_put2string($end);

# cleanup
    Net::SSLeay::free($ssl);
    Net::SSLeay::CTX_free($ctx);
    close SOCK;

    $str;
}

sub die_unknown ($) {
    printf "CERTEXP UNKNOWN - %s\n", shift;
    exit $ERRORS{'UNKNOWN'};
}

sub die_warn ($) {
    printf "CERTEXP WARNING - %s", shift;
    # exit $ERRORS{'WARNING'};
    return 1;
}

sub die_crit ($) {
    printf "CERTEXP CRITICAL - %s", shift;
    # exit $ERRORS{'CRITICAL'};
    return 2;
}

sub print_usage () {
    print "Usage: $PROGNAME -H host [-p port] [-w warn] [-c crit]" .
    "[-t timeout] [-v]\n";
}

sub print_help () {
print_revision($PROGNAME, '$Revision: 1.1 $');
print "Copyright (c) 2006 Holger Weiss\n\n";
print "Check certificate expiry date.\n\n";
print_usage();
print <<EOF;

-H, --hostname=HOSTNAME
Host name (only)
-p, --port=INTEGER
Port number (default: $PORT)
-w, --warning=INTEGER
WARNING if less than specified number of days until expiry (default: $CRIT)
-c, --critical=INTEGER
CRITICAL if less than specified number of days until expiry (default: $CRIT)
-t, --timeout=INTEGER
Seconds before connection times out (default: $TIMEOUT)
-v, --verbose
Show details for command-line debugging (Nagios may truncate output)

EOF
support();
}

В итоге получаем ответ в Nagios в таком виде:

Status Information:
OK for ip4 - cert expires in 280 days:OK for ip4 - cert expires in 280 days:OK for ip6 - cert expires in 280 days:OK for ip6 - cert expires in 280 days:

unix-way