#!/usr/bin/env php <?php $log = '/var/log/auth.log'; $ignore_hosts = Array( "yiff.myftp.org" ); $ignore_hosts_cache = Array(); // ip => Array('ip' => <ip>, 'name' => <name>, 'expires' => <time>) $ignore_hosts_cache_timeout = 60; $bad_hosts = Array(); // ip => Array('expires' => <time>, 'evidence' => Array(<evidence>)) $bad_hosts_timeout = 60; $bad_hosts_limit = 10; openlog('StopGrind', LOG_PID|LOG_PERROR, LOG_AUTHPRIV); function logit() { //printf("%s: ", strftime("%Y-%m-%d:%H:%M:%S")); $args = func_get_args(); $line = call_user_func_array('sprintf', $args); syslog(LOG_NOTICE, $line); //printf("\n"); //printf("%s: %s\n", strftime("%Y-%m-%d:%H:%M:%S"), $line); } function authorizedHost($ip) { global $ignore_hosts, $ignore_hosts_cache, $ignore_hosts_cache_timeout; // Expire cache entries $now = time(); foreach ($ignore_hosts_cache as $key => $ignore_host) if ($ignore_host['expires'] < $now) unset($ignore_hosts_cache[$key]); // Now look up a cached entry if (isset($ignore_hosts_cache[$ip])) return TRUE; // Now look up the ignore_hosts one by one until we get a match foreach ($ignore_hosts as $host) { $record = dns_get_record($host, DNS_ANY); foreach($record as $entry) { if ($entry['ip']) { $ignore_hosts_cache[] = Array( 'ip' => $entry['ip'], 'name' => $entry['host'], 'expires' => time() + $entry['ttl'] ); if ($entry['ip'] == $ip) return TRUE; } } } return FALSE; } function badHost($ip, $line) { global $bad_hosts, $bad_hosts_timeout, $bad_hosts_limit; //printf("==> badHost(%s)\n", $ip); // Expire foreach($bad_hosts as $key => $value) if ($value['expires'] < time()) unset($bad_hosts[$key]); // Check if (!is_array($bad_hosts[$ip])) $bad_hosts[$ip] = Array('evidence' => Array()); $bad_hosts[$ip]['expires'] = time() + $bad_hosts_timeout; $bad_hosts[$ip]['evidence'][] = $line; if (count($bad_hosts[$ip]['evidence']) > $bad_hosts_limit) banBadHost($ip); } function banBadHost($ip) { // Magical Gnomes global $bad_hosts; logit("Banning %s for grinding.", $ip); $cmd = sprintf("/root/siteban/autoban %s", escapeshellarg($ip)); exec($cmd); unset($bad_hosts[$ip]); } function matchLine($pattern, $key, $line) { global $trig_vars; $regs = Array(); if ($res = preg_match($pattern, $line, $regs)) { $out = Array(); //printf("[%s]=> (%s) %s \n", $key, $res, $line); foreach($trig_vars[$key] as $index => $name) { if ($name) $out[$name] = $regs[$index]; } if (!authorizedHost($out['ip'])) { badHost($out['ip'], $line); } } } function tailLog($log) { global $source; if (is_resource($source)) pclose($source); $cmd = sprintf("tail -fn 1024 %s", escapeshellarg($log)); //logit("%s", $cmd); $source = popen($cmd, "r"); // Ignore the first line, in case it's a newsyslog message. fgets($source, 4096); return $source; } tailLog($log); $trig_pats = Array( "/Failed ([^ ]+) for( invalid user){0,1} ([^ ]+) from ([^ ]+) port ([^ ]+)/", "/Invalid user ([^ ]+) from ([^ ]+)/", ); $trig_vars = Array( Array( "", "method", "", "username", "ip", "port" ), Array( "", "username", "ip" ) ); logit("Starting scanner"); while ($line = fgets($source, 16384)) { $line = trim($line); // Check for newsyslog message if (preg_match('/newsyslog[^:]+: logfile turned over/', $line)) { //logit($line); logit("Reloading logfile\n"); pclose($source); die(); tailLog($log); } array_walk($trig_pats, "matchLine", $line); } ?>
Note: You are viewing an old version of this page. View the current version.