ここのところimapの調子が悪く、気づくとimapdプロセスが10個以上暴走していたり、Thunderbirdで多め(200個以上ぐらい)のメールを一気に削除すると戻ってこなかったり。いったんその状態になるとすべてのメールボックスの操作が遅くなるので、いろいろ見てみるけどどうにも原因がわからず、1月ほどサーバを再起動してしのいでました。
で、やっと原因と思しき箇所が判明。~/Maildir/.Trash/tmp/ の下にファイルが81万個 _| ̄|○
rm実行してから3時間以上経ってますが、まだ終わらない。むしろこんなになるまでよく頑張ってたなと。
この辺が原因かとも思ったけど、同じ設定の(はずの)別アカウントの方では同じ~/Maildir/.Trash/tmp/の下にファイルが溜まっている様子も無く、謎。まあ届くSPAM数が比じゃなく、問題が無い方のアカウントでは溜まったSPAMを千単位で一括削除とかやってないので、たぶんその差かな。
溜まる原因の方をなんとかすべきだろうけど、とりあえず以下のコマンドをcronで回すという後ろ向きな解決で。
find ~/Maildir/.Trash/tmp -type f ! -newerct '2 days ago' -exec rm {} \;
これで解決してほしいなあ。
追記:
やっと終わった。うおー、サクサクだー。
水無月ばけらのえび日記の「安全なテンプレートシステムはあるのか」を読んでふと思いついたアイデア。
require 'erb'
include ERB::Util
class Object
def clarify
raise SecurityError.new("Object is tainted.") if self.tainted?
@clarified = true
self
end
def unclarify
@clarified = false
self
end
def clarified?
@clarified || false
end
end
class ERB
module Util
public
def h(s)
if s.tainted? || ! s.clarified?
html_escape(s)
else
s.to_s
end
end
end
end
########## test ##########
SCRIPT = <<EOS
a.tainted?: <%= a.tainted? %>
a.clarified?: <%= a.clarified? %>
h a: <%=h a %>
EOS
a = '<SCRIPT>alert("!")</SCRIPT>'
print "-----\n"
print ERB.new(SCRIPT).result(binding)
print "\n-----\n"
a.clarify
print ERB.new(SCRIPT).result(binding)
print "\n-----\n"
a.taint
print ERB.new(SCRIPT).result(binding)
print "\n-----\n"
a.unclarify
print ERB.new(SCRIPT).result(binding)
print "\n-----\n"
a.clarify
実行結果はこちら
-----
a.tainted?: false
a.clarified?: false
h a: <SCRIPT>alert("!")</SCRIPT>
-----
a.tainted?: false
a.clarified?: true
h a: <SCRIPT>alert("!")</SCRIPT>
-----
a.tainted?: true
a.clarified?: true
h a: <SCRIPT>alert("!")</SCRIPT>
-----
a.tainted?: true
a.clarified?: false
h a: <SCRIPT>alert("!")</SCRIPT>
-----
t.rb:6:in `clarify': Object is tainted. (SecurityError)
from t.rb:60
解説すると、Objectクラスに「汚染」フラグとは別に「浄化済み」フラグを設け、そのObjectが汚染されておらず、かつ浄化済みであれば変数の内容をエスケープせずに出力するようERB::Util::hを再定義しただけ。エスケープを抑制する条件を単に tainted? == false としないのは、事の発端であったプログラマにセキュリティを意識させるための工夫のつもり。
taintも再定義して中で @clarified = false したいんですが、そこまでは腕がありません。あと、clarified?の「|| false」とかも@clarifiedの初期化の仕方がわからず、ひよった結果です。
あと、名前はsanitizeにしようかとも思ったのですが、さすがに自重。
なぜかここ数日で急激にSPAMが増え、私一人で1日1万通を超えるようになってしまったので、いまさらながらサーバサイドでSPAM対策。
SPAMの送信元を調べると、見事に分散していて手動登録ではとても間に合いそうに無いが、単純なrbl方式では誤登録が怖い。かといってS25Rやgreylistingのような再送要求系の手法はタイムラグが怖くてちょっと採用できない。で、妥協点として考え出したのが以下のような設定。
まずは、Postfixのmain.cf
smtpd_client_restrictions =
permit_mynetworks
check_client_access hash:/usr/local/etc/postfix/pass0
reject_rbl_client all.rbl.jp
check_client_access hash:/usr/local/etc/postfix/pass1
check_client_access regexp:/usr/local/etc/postfix/white-list.txt
reject_rbl_client bl.spamcop.net
permit
/usr/local/etc/postfix/pass0には、必ず受信を許可するサーバやドメインを列挙する。
###.### OK
xxx.com OK
yyy.org OK
/usr/local/etc/postfix/pass1は、次の1行のみ。
.jp OK
/usr/local/etc/postfix/white-list.txtは、こちらのページから入手できる、S25Rスパム対策方式で誤って阻止される正当なメールサーバを許可するためのホワイトリスト情報を加工して、.jpドメインのサーバを抜いたもの。
これで、ルールとしては以下のようになる。
要するに、jpドメインのホストについてはrbl.jpの登録情報だけを、それ以外のドメインのホストについては追加でspamcop.netの情報を採用する方針。gTLDとかがちょっと怪しくなるので、確実に受け取りたいものはpass0に登録するか、white-list.txtを使って誤登録対策とすると。spamcop.net採用の理由は調査したSPAM送信元の登録状況が良かったため。それだけ誤登録もありそうだけど、jpドメイン+ホワイトリストで国内のサーバをある程度外せるので、これで引っかかるサーバはしょうがないと割り切ることに。
とりあえずしばらくこれで様子見。
「ネットワークにお詳しいんですよね」
「はあ、まあそれなりには」
「そういえば、こんなネットワークご存知ですか」
「どんなのですか?」
「なんか、普通のとは違って1本の線を繋いで作るネットワークなんですよ」
「ほう」
「その途中に機器をぶら下げていくんです」
「ふむふむ」
「その途中に繋ぐ機器も良くできていて、自分宛の通信だけ受け取って、それ以外のものは素通しするんです。一種のフィルタ機能を備えてるんですよ」
「……へぇ、面白いですね」
「そうなんですよ。工場とかでセンサーを多数並べるときには線の引き回しとか効率よく出来て便利なんです」
「ああ、そういう場面では確かにそうかもしれませんね」
どうやら世界のどこかにはいまだにネズミにケーブルかじられてネットワーク全体が落ちたり、穴あけに失敗しただけで基幹ネット張りなおしというしゃれにならない事態を引き起こしたり(私じゃありませんよ)、終端抵抗の接触不良で謎の速度低下に見舞われたりしているネットワークが現存するらしい。
それとも、試された?
ちょっと探しても見つからなかったのでmongrel_rails の自動起動スクリプトを自作。確認したのは6.1の環境。使い方は上のリンクから取得したスクリプトを/usr/local/etc/rc.d/rails という名前で(実行ビットを立てて)保存し、/etc/rc.confに以下のような記述を追加する(reils_port以下は省略可)。
rails_enable="YES" # Rails 有効 rails_port="3000" # ポート番号 rails_user="rails" # mongrel_railsを実行するアカウント rails_chdir="/home/www/rails" # Rails がインストールされているディレクトリ rails_pidfile="${rails_chdir}/log/rails.pid" # PIDファイル(ディレクトリは$rails_userアカウントに対して書き込み許可する必要あり)
apacheのProxyを使う場合、apacheでProxyの設定をした後、/usr/local/etc/rc.d/apach22 等のapacheの起動スクリプト内のREQUIRE行を以下のように書き換える。
# REQUIRE: LOGIN cleanvar rails
これで、Mongrelが起動した後、apacheが起動するようになる。こうしないと手元の環境ではMongrelの起動前に転送するURLにアクセスがあった時に、へんなキャッシュが効いて2度と(しばらく?)アクセスできなくなってしまったので。
作ってみて分かったのは、rcスクリプトとmongrelの相性がやけに悪いということ。原因はmongrel_railsがstart,stop等をオプションで指定する制御型のコマンドであることと、Rubyスクリプトなのでプロセス名がmongrel_railsにならないこと。後者については一般的なスクリプト系コマンドに対する対策はしてあるっぽいんだけど、なぜかcommand_interpreterを指定しないとうまくいかなかった。ruby18の絶対パスが埋め込みというのはカッコ悪いので、原因と対策が分かる人がいたら教えてください。