Files
sshbruted/sshbruted.rb
T

82 lines
1.4 KiB
Ruby

#!/usr/bin/env ruby
require 'time'
require 'thread'
LOG_COMMAND = "/usr/bin/tail -F /var/log/auth.log"
BLACKLIST = "/etc/hosts.blacklist"
MAX_FAILURES = 3
TIME_LIMIT = 30 * 60 # 30 minutes
class Blacklister
def initialize
@iplog = Hash.new([])
@iplog_lock = Mutex.new
end
def add_hit(ip,time)
@iplog_lock.synchronize do
@iplog[ip] += [time]
end
end
def list
badlist = []
@iplog_lock.synchronize do
# clean up stale entries
@iplog.reject! { |ip,times| stale_entry(times) }
# create our blacklist
@iplog.each { |ip,times| badlist << ip if fresh_count(times) > MAX_FAILURES }
end
badlist.sort
end
private
def fresh_count(times)
fresh_times = times.select { |t| (Time.now - t) < TIME_LIMIT }
fresh_times.size
end
def stale_entry(times)
fresh_count(times) == 0
end
end
blacklister = Blacklister.new
input_thread = Thread.new do
regexp = /(.+) [^\s]+ sshd\[\d+\]: Failed ([^\s]+) for ([\w\s]+?) from ([\d\.]+) port (\d+) ssh2/
logfile = IO.popen(LOG_COMMAND)
while line = logfile.gets
match = regexp.match(line)
if match
time = Time.parse(match[1])
ip = match[4]
blacklister.add_hit(ip,time)
end
end
end
output_thread = Thread.new do
list = []
loop do
sleep 2
new_list = blacklister.list.join("\n")
if new_list != list
File.open(BLACKLIST,"w") { |f| f.puts(new_list) }
#puts "[#{Time.now}]\n#{new_list}"
list = new_list
end
end
end
input_thread.join