Differences between version 2 and previous revision of StopGrind.
Other diffs: Previous Major Revision, Previous Author
| Newer page: | version 2 | Last edited on Wednesday, 3 September 2008 7:31:49 | by CyberLeo | Revert |
| Older page: | version 1 | Last edited on Sunday, 31 August 2008 23:03:16 | by CyberLeo | Revert |
@@ -22,8 +22,16 @@
$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 loadState() {
+ logit("fixme:STUB:loadState()");
+}
+
+function saveState($state) {
+ logit("fixme:STUB:saveState()");
}
function authorizedHost($ip) {
global $ignore_hosts, $ignore_hosts_cache, $ignore_hosts_cache_timeout;
@@ -50,13 +58,21 @@
}
}
}
return FALSE;
+}
+
+function banBadHost($ip) {
+ // Magical Gnomes
+ global $bad_hosts;
+ logit("bad host banned: %s", $ip);
+ $cmd = sprintf("/root/siteban/autoban %s", escapeshellarg($ip));
+ //exec($cmd);
+ unset($bad_hosts[$ip]);
}
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]);
@@ -67,25 +83,15 @@
$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];
}
@@ -106,9 +112,13 @@
fgets($source, 4096);
return $source;
}
-tailLog
($log
);
+function handle
($line) {
+ global $trig_pats;
+ $line = trim($line);
+ array_walk($trig_pats, "matchLine", $line
);
+}
$trig_pats = Array(
"/Failed ([^ ]+) for( invalid user){0,1} ([^ ]+) from ([^ ]+) port ([^ ]+)/",
"/Invalid user ([^ ]+) from ([^ ]+)/",
@@ -130,8 +140,46 @@
);
logit("Starting scanner");
+$state = loadState();
+
+$lines = 0;
+$running = TRUE;
+$buf = "";
+while ($running) {
+ $read = Array(STDIN);
+ $write = NULL;
+ $except = NULL;
+ $timeout = 60;
+ if ($res = stream_select($read, $write, $except, $timeout)) {
+ // Handle incoming data
+ if (0 == strlen($tmp = fread(STDIN, 4096))) {
+ // EOF
+ logit("No more input. Night night.");
+ $running = FALSE;
+ } else {
+ $buf.= $tmp;
+ while (FALSE !== ($pt = strpos($buf, "\n"))) {
+ $lines++;
+ $line = substr($buf, 0, $pt);
+ $buf = substr($buf, $pt + 1, strlen($buf));
+ handle($line);
+ }
+ }
+ } else {
+ // Timeout or interrupt. Die.
+ logit("Timeout. Night night.");
+ $running = FALSE;
+ }
+}
+
+logit("Processed %u lines", $lines);
+saveState($state);
+
+return 0;
+
+tailLog($log);
while ($line = fgets($source, 16384)) {
$line = trim($line);
// Check for newsyslog message
if (preg_match('/newsyslog[^:]+: logfile turned over/', $line)) {
@@ -143,7 +191,8 @@
}
array_walk($trig_pats, "matchLine", $line);
}
+pclose($source);
?>
</verbatim>
version 2
#!/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 loadState() {
logit("fixme:STUB:loadState()");
}
function saveState($state) {
logit("fixme:STUB:saveState()");
}
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 banBadHost($ip) {
// Magical Gnomes
global $bad_hosts;
logit("bad host banned: %s", $ip);
$cmd = sprintf("/root/siteban/autoban %s", escapeshellarg($ip));
//exec($cmd);
unset($bad_hosts[$ip]);
}
function badHost($ip, $line) {
global $bad_hosts, $bad_hosts_timeout, $bad_hosts_limit;
// 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 matchLine($pattern, $key, $line) {
global $trig_vars;
$regs = Array();
if ($res = preg_match($pattern, $line, $regs)) {
$out = Array();
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;
}
function handle($line) {
global $trig_pats;
$line = trim($line);
array_walk($trig_pats, "matchLine", $line);
}
$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");
$state = loadState();
$lines = 0;
$running = TRUE;
$buf = "";
while ($running) {
$read = Array(STDIN);
$write = NULL;
$except = NULL;
$timeout = 60;
if ($res = stream_select($read, $write, $except, $timeout)) {
// Handle incoming data
if (0 == strlen($tmp = fread(STDIN, 4096))) {
// EOF
logit("No more input. Night night.");
$running = FALSE;
} else {
$buf.= $tmp;
while (FALSE !== ($pt = strpos($buf, "\n"))) {
$lines++;
$line = substr($buf, 0, $pt);
$buf = substr($buf, $pt + 1, strlen($buf));
handle($line);
}
}
} else {
// Timeout or interrupt. Die.
logit("Timeout. Night night.");
$running = FALSE;
}
}
logit("Processed %u lines", $lines);
saveState($state);
return 0;
tailLog($log);
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);
}
pclose($source);
?>
