#!/usr/local/bin/perl

=head1 NAME

ipsec - Plugin to monitor IPsec security associations

=head1 SCOPE

Use the `ipsec status` command to learn about security associations, thanks to
the following format string (src/libcharon/plugins/stroke/stroke_list.c):

  fprintf(out, "Security Associations (%u up, %u connecting):\n", /* ... */);

=head1 CONFIGURATION

This plugin requires access to the control socket, so it should be configured to
run with sufficient privileges (e.g. as root).

To set warning and critical levels, assuming a single 'up' is desired at all
times, let exceptions get raised for all values that aren't the specified one
(or within the specified interval):

  [ipsec]
  user root
  env.up_critical 1
  env.connecting_critical 0

There are no default warning or critical levels.

=head1 AUTHOR

© 2024 Cyril Brulebois <kibi@mraw.org>

=head1 LICENSE

GPLv2

=cut

use warnings;
use strict;

# limits management
my %limits;
foreach my $status (qw(up connecting)) {
    foreach my $level (qw(warning critical)) {
        $limits{$status}{$level} = $ENV{"${status}_${level}"};
    }
}

sub print_limit_if_defined {
    my ($status, $level) = @_;
    if (defined $limits{$status}{$level}) {
        print "$status.$level $limits{$status}{$level}\n";
    }
}

# autoconf
if (defined $ARGV[0] and $ARGV[0] eq "autoconf") {
    print "no\n";
    exit 0;
}

# config
if (defined $ARGV[0] and $ARGV[0] eq "config") {
    print "graph_title IPsec security associations\n";
    print "graph_args --base 1000 -l 0\n";
    print "graph_scale no\n";
    print "graph_vlabel Count\n";
    print "graph_category network\n";
    print "graph_total total\n";
    print "graph_info This graph shows the number of security associations and their status\n";


    print "up.label up\n";
    print "up.draw AREA\n";
    print_limit_if_defined('up', 'warning');
    print_limit_if_defined('up', 'critical');
    print "connecting.label connecting\n";
    print "connecting.draw STACK\n";
    print_limit_if_defined('connecting', 'warning');
    print_limit_if_defined('connecting', 'critical');
    exit 0;
}

# actual work
my ($up, $connecting);
foreach my $line (`ipsec status`) {
    if ($line =~ /^Security Associations [(](\d+) up, (\d+) connecting[)]:$/) {
        ($up, $connecting) = ($1, $2);
    }
}
if (defined $up and defined $connecting) {
    print "up.value $up\n";
    print "connecting.value $connecting\n";
}
else {
    print STDERR "unable to find the expected format string\n";
    exit -1;
}
