Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
autoban:: Simple, efficient Ruby "fail2ban"-like script
#!/bin/env/ruby
# A more efficient and documented autoban.rb
# Jamie - index.hm. Released under MIT.
# This won't work with binary journal logs - the 'systemd/journal' gem doesn't work universally
$ssh_port = 1234
$network = ["127.0.0.0/8", "10.0.0.0/8", "192.168.0.0/16"]
require "shellwords"
require "etc"
require "ipaddr"
$network.map! { |n| IPAddr.new(n) }
def tail(files)
begin
# Iterate through the supplied log files, open a descriptor, seek to the end of the file
files.map! { |f| File.open(f, "r") }.each { |f| f.seek(0, IO::SEEK_END) }
rescue
abort "Failed to watch logfiles. Are you running me as root? I need this to run iptables!"
end
loop do
# Watch FDs for changes, yield with every new line that appears
select(files, nil, nil, 30)[0].each { |f| line = f.gets; yield line if line.to_s.chomp != "" }
end
end
tail %w(/var/log/secure /var/log/messages) do | line |
puts line
# Is the error from
if result = /(Failed password for (.*)|Invalid user (.*)) from (.*)/.match(line)
ip = result[4]; message = "Possible break-in attempt from #{ip} (#{result[3]}#{result[2]})"
next unless $network.none? { |i| i == ip }
send "system", *%W(ip route add blackhole #{ip}/32) # Get lost
end
if result = /([0-9a-f\.]*) to ([0-9a-f\.]*) ports/i.match(line)
ip = result[1]; message = "Potential port map from IP #{ip}"
next unless $network.none? { |i| i == ip }
send "system", *%W(/sbin/iptables -I INPUT -s #{ip} -p tcp --dport #{$ssh_port} -j REJECT --reject-with tcp-reset)
end
system "send_alert", message if message
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment