#!/usr/bin/php
<?php
# Plugin to monitor the number of invalid access to sshd per country
#
# Require read permitions for SYSLOG
#    ref) ls -l /var/log/secure
# Require PEAR library Net_GeoIP
#    ref) http://pear.php.net/package/Net_GeoIP/redirected
# Require GeoIP-database to find out the geolocation from ip or host
#    ref) http://www.maxmind.com/app/geoip_country
#
# Parameters:
#       config   (required)
#       autoconf (optional - used by munin-config)
#
# $Log$
# Revision 1.0  2010/12/23 23:55:01 hirata yoshiyuki
#     released.
#
# Magick markers (optional):
#%# family=auto
#%# capabilities=autoconf
#
# config example for /etc/munin/plugin-conf.d/munin-node
#[sshd_invalid_countries]
#user root
#group root
#env.logfile /var/log/secure
#env.geoip /home/you/GeoIP.dat
#env.peardir /usr/share/pear/

require (isset($_SERVER['peardir']) && $_SERVER['peardir'] != '' ? $_SERVER['peardir'] : '') . 'Net/GeoIP.php';

define('SYSLOG',   isset($_SERVER['syslog']) && $_SERVER['syslog'] != '' ? $_SERVER['syslog'] : '/var/log/secure');
define('GEOIP_DB', isset($_SERVER['geoip'])  && $_SERVER['geoip']  != '' ? $_SERVER['geoip']  : 'GeoIP.dat');
define('AWK_CMD', 'awk \'/sshd\[.*Did not receive identification string/{print $12} ' .
                        '/sshd\[.*Failed password for (root|ROOT)/{print $11} ' .
                        '/sshd\[.*Invalid user/{print $10}a\' < ' . SYSLOG);

if (isset($argv[1]) && $argv[1] == 'autoconf') {
    $fh = @fopen(SYSLOG, 'r');
    if ($fh) {
        echo "yes\n";
        fclose($fh);
        exit(0);
    } else {
        echo "no\n";
        exit(1);
    }
}
if (isset($argv[1]) && $argv[1] == 'config') {
    echo 'graph_title SSHD invalid countries from ' . SYSLOG . "\n";
    echo 'graph_args --base 1000 -l 0' . "\n";
    echo 'graph_vlabel number of invalid access per country' . "\n";
    echo 'graph_category system' . "\n";
    echo 'graph_info This graph shows the countries of invalid access to sshd.' . "\n";
    foreach (get_sshd_invalid_countries() as $country => $cnt) {
        echo $country . '.label ' . $country . "\n";
    }
    exit(0);
}

foreach (get_sshd_invalid_countries() as $country => $cnt) {
    echo $country . '.value ' . $cnt . "\n";
}

function get_sshd_invalid_countries() {
    $countries = array();
    exec(AWK_CMD, $wholeips, $ret);

    if ($ret != 0) return $countries;

    $uniqueips = array_count_values($wholeips);
    $GeoIP = Net_GeoIP::getInstance(GEOIP_DB);
    foreach ($uniqueips as $ip => $cnt) {
        try {
            $country = $GeoIP->lookupCountryName($ip);
            $countries[$country] = isset($countries[$country]) ? $countries[$country] + $cnt : $cnt;
        } catch (Exception $e) {
            $countries['Unknown'] = isset($countries['Unknown']) ? $countries['Unknown'] + $cnt : $cnt;
        }
    }
    ksort($countries);

    return $countries;
}
