Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Parse Fail2ban output
#!/usr/bin/env ruby
# ruby fail2ban.rb logfile | sort -rn | head -25
# ruby fail2ban.rb logfile | awk '{print $2}' | sort | uniq -c | sort -rn | head -15
require 'time'
networks = {}
module MBox
class Mail
def self.begin?(line)
if line.unpack('C*').pack("U*") =~ /\AFrom\s([^\s]+)\s(.+)\n/
yield $1, DateTime.parse($2)
return true
end
end
attr_reader :header, :body
def initialize(from, time)
@meta, @header, @body = true, {}, String.new
end
def <<(line)
@meta = false if @meta and line.unpack('C*').pack("U*") =~ /\A\n/
if @meta
case line.unpack('C*').pack("U*")
when /\A([^\s:]+):(.*)\n/ then @queue = @header[$1] = $2.strip
when /\A\s+(.+)\n/ then @queue << ' ' + $1.strip
else raise ArgumentError, 'Header contains inappropriate line'
end
else @body << line.unpack('C*').pack("U*")
end
end
end
extend self
def parse(file, mails = [])
File.open file do |fd|
raise ArgumentError, 'Not a valid mbox format' unless Mail.begin? fd.readline do |from, time|
mails << Mail.new(from, time)
end
fd.each do |line|
case
when Mail.begin?(line) { |from, time| mails << Mail.new(from, time) }
else mails.last << line
end
end
end; mails
end
end
unless !ARGV[0].nil? and File.readable? ARGV[0]
puts 'Usage: fail2ban.rb file'
exit
end
MBox.parse(ARGV[0]).each do |mail|
name = String.new
mail.body.upcase.match /^NETNAME:\s+(.+)\n/ do
if networks[$1].nil? then networks[name = $1] = { count: 0 }
else networks[$1][:count] += 1
end
end
unless name.empty?
mail.body.upcase.scan /^(.+):\s+(.+)\n/ do |key, value|
networks[name][:country] = value if key == 'COUNTRY'
end
end
end
networks.each do |key, value|
puts value[:count].to_s + "\t" +
value[:country] + "\t" +
key
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.