人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Rubyに挑戦中です。Perl歴11年(でも知識はPerl4止まり)の私はどうしてもPerlっぽいRubyを書いてしまうのですが、このスクリプトをRubyっぽく書くには、どうしたらいいのでしょうか。お題は、syslogを監視して、sshdへの不正っぽいアクセスが連続したら/etc/hosts.denyにアクセス拒否リストを追加するスクリプトです。
http://d.hatena.ne.jp/pekeq/20060109/p1

●質問者: pekeq
●カテゴリ:コンピュータ
✍キーワード:ETC Perl Ruby syslog アクセス
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● 櫛ヶ浜やぎ
●25ポイント

http://jp.rubyist.net/magazine/?0011-CodeReview#l41

Rubyist Magazine - あなたの Ruby コードを添削します 【第 2 回】 HexStruct.rb

こちらに応募されるといいのではないでしょうか。

というだけではナンなので、たいしたことは言えませんが少しだけ書いてみます。


print cmd + ”¥n”

は、

puts cmd

と書けます。


@@badHosts = Hash.new

@@badHosts = Hash.new {|hash, key| hash[key] = 0 }

とする(デフォルト値を指定する)ことで、25行目からの

if @@badHosts[host] then

@@badHosts[host] += 1

else

@@badHosts[host] = 1

end

を、

@@badHosts[host] += 1

だけにできます。


45行目からの

x_month = m[1]

x_date = m[2]

x_time = m[3]

……は、

x_all, x_month, x_date, x_time, …… = m

と多重代入できます。……が、これは元のままの方が見やすいですかね。


56行目からの判定部分は同様の処理が連続しているので

[

# Invalid user bgray from ::ffff:82.85.1.1

[x_arg, /^Invalid user .* from (::ffff:)?([-.0-9A-Za-z]+)/, 2],

# User root from 10.10.10.10 not allowed because not listed in AllowUsers

[x_arg, /^User .* from (::ffff:)?([-.0-9A-Za-z]+) not allowed/, 2],

# Did not receive identification string from ::ffff:164.125.1.1

[x_arg, /^Did not receive identification string from (::ffff:)?([-.0-9A-Za-z]+)/, 2],

].each{|arg, re, n|

next if arg !~ re

addBad Regexp.last_match[n]

}

などと、まとめてしまうと良いかも。

もう少し汎用的には

[

# Invalid user bgray from ::ffff:82.85.1.1

proc{

x_arg =~ /^Invalid user .* from (::ffff:)?([-.0-9A-Za-z]+)/ ? $2 : nil

},

# User root from 10.10.10.10 not allowed because not listed in AllowUsers

proc{

x_arg =~ /^User .* from (::ffff:)?([-.0-9A-Za-z]+) not allowed/ ? $2 : nil

},

# Did not receive identification string from ::ffff:164.125.1.1

proc{

x_arg =~ /^Did not receive identification string from (::ffff:)?([-.0-9A-Za-z]+)/ ? $2 : nil

},

].each{|pr|

x_badhost = pr.call

addBad(x_badhost) if x_badhost

}

という感じでしょうか。

◎質問者からの返答

Hashのデフォルト値というのは、こうやって使うんですね!「いったい何に使うんだろう」と思っていました。ありがとうございます。


2 ● rudeboyjet
●25ポイント

http://www.ruby-lang.org/ja/man/

Rubyリファレンスマニュアル - Rubyリファレンスマニュアル

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


Rubyっぽくってことでこんな感じでどうでしょう?

急ごしらえなんで実用レベルのものではないですけど。

◎質問者からの返答

なるほど。1)まずはClassを作り、2)コマンドラインから呼び出された場合はif $0==__FILE__で処理する というのがRubyっぽい構造に見えますね。Class内部もRubyっぽくてステキです

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ