There are two ways to do this.
One is have firewall chains that progressively change list that an ip address is in - it works reasonably well, but I believe this results in a CF disk write for every change (works out 3-4 writes per ip) - Unfortunatly this one only counts rapid succession of reconnects on port 22, not specificly login failures
If you're interested, I'll post this solution.
The other way (and for those who use CF cards, this is probably the better way) is to set up a remote syslog, use syslog-ng on the box and a little perl script. syslog-ng can pipe entry's that match a pattern to a program/script.
Example syslog configuration
source s_remote { udp(); tcp(); };
filter f_sshworm { facility(user) and level(notice) and match("login failure for user"); };
destination d_sshworm {
program("/sshworm.pl"
template("$SOURCEIP $MESSAGE\n") );
};
log {
source(remote);
filter(f_sshworm);
destination(d_sshworm);
};
now for me /sshworm.pl puts an entry into my scheduler database (I already have a script on another machine that routinely does things on the mikrotiks - like kicking users off, changing their speeds, checking the
ip accounting and
ip accounting web-access settings (they sometimes disable...)
My scheduler logs in with ssh and adds the ip address to the 'SSHWorms' address list, which has input and forward port 22 reject with tcp-reset (better to reset then just drop, it's the proper way to do it)
#!/usr/bin/perl
use Net::IP::Match::Regexp qw( create_iprange_regexp match_ip );
use strict;
# These addresses have been changed...
my $whitelist = create_iprange_regexp(
"192.168.47.0/24",
"172.16.0.0/16",
"10.254.2.242/32"
);
$SIG{CHLD} = sub { wait };
# It's a constant pipe open from syslog-ng so we just read indefinitely
while (<>) {
if (/^((?:\d+.){3}\d+).*?((?:\d+.){3}\d+)/) {
# Match against our whitelist
next if (match_ip($2,$whitelist));
# Because many requests might come in at once, we want to get back to reading stdin as soon as possible or we'll miss something, so we fork here
if (fork() == 0) {
# Sumbit to the scheduler
exec('/usr/bin/wget',"--post-data=ac=$1&ip=$2",'-q','-o/dev/null','-O/dev/null','http://scheduler.host/sshworm.php');
exit;
}
}
}
You don't need a scheduler, but you might have concurrency issues if you don't use one (You could use lockfiles to get around this)
If anyone wants a full solution, feel free to pm me, I can knock something up - having said that, there's a great detail of information already on this forum