人力検索に応えてみた。

question:1136813234の質問に答えてみた。

class Observation
  def Observation.start(arg)
    Observation.new.start(arg)
  end

  def initialize
    @blacklist = Hash.new{|hash,key| hash[key] = 0}
    @judgement = 10
  end
  
  def start(target)
    pipe = IO.popen(”tail -f #{target}”,’r’)
    loop do
      if (input = pipe.gets)
        result = analyze(input)
        if result[’protocol’] =~ /ssh/ && result[’success?’] == false
          add_black(result[’ip’])
        end

        add_deny(result[’ip’]) if @blacklist[result[’ip’]] > @judgement
      end
    end
  end

  def analyze(str)
    flag = true
    ary = str.split
    date = ary.slice!(0..2).join(’ ’)
    host  = ary.shift
    protocol = ary.shift
    if pos = ary.index(’from’)
      ip = ary.slice!(pos + 1)
    end
      flag = false if ary.include?(’not’||’invalid’)

    return {’date’ => ”#{date}”, ’host’ => ”#{host}”, ’protocol’ => ”#{protocol}”,
    ’ip’ => ”#{ip}”, ’success?’ => ”#{flag}”}
  end

  def add_black(ip)
    @blacklist[ip] += 1
  end

  def add_deny(ip)
    file = File.open(”/etc/hosts.deny”,’a+’)
    file.flock(File::LOCK_EX)
    file.puts(ip)
    file.flock(File::LOCK_UN)
    file.close
  end
end

if $0 == __FILE__
  Observation.start(’/var/log/messages’)
end

こんな感じ。

analyzeメソッドで解析してハッシュを返すってやり方はけっこう気に入ってるけど今になって思えばstartメソッドで判定するんじゃなくてjudgeメソッドを作ればよかったかなぁと思ったり思わなかったり。動かしてないけどこれちゃんと動くのかなぁ?