OSTRACISM CO.

LinuxのMewでのspam対策


 もういいかげんspamを手作業で削除するのがばかばかしくなっていたのだが、LinuxのEmacs 21でMew 1.94.2でIM 1.4な環境でどうできるのかはかなり調べないとわからないので放置してた。ちなみにLinuxはSlackware 8だか9だか。マシンはCeleron 1.4GHzの廉価なベアボーン。
 で、最近sayo<pal_0807@yahoo.co.jp>ってところからのspamが異様に多いのでようやく対策を調べたところbsfilterというソフトがみつかった(http://bsfilter.org/)。日本製のベイジアンスパムフィルタで、Rubyで動く。まずはRubyをインストール。
 bsfilterをPOP Proxyで動かすようにした。
/etc/rc.d/rc.localに追加
----------
/usr/local/bin/bsfilter --pop --pop-server ポップサーバ --pop-max-size 0 --auto-update --insert-flag --insert-probability --homedir /home/ostra/.bsfilter &
----------
 この場合spamと判定されたメールには X-Spam-Flag: Yes という行が追加される。.emacsの mew-refile-guess-alist に ("X-Spam-Flag:" ("Yes" . "+spam")) を加えることでM-oにてoフラグが立つようになる。まぁ、とりあえずはこんなもんか。IMの設定で直接プロバイダのPOPサーバを記述してある部分はlocalhostのPOP Proxyに変更。

 数日運用。

 やはりメールの自動振り分けまでしたいことに加え、Mewからspamの学習を操作したいので根本的な対策が必要だと判断。で、TLECの記述を参考にした(http://tlec.linux.or.jp/docs/spamassassin.html)。IM(imgetとimput)を捨てるのである。
 メールの受信はfetchmailでPOPサーバから得て、それをprocmailに渡し、procmailがbsfilterで分類されたspamと非spamを分けて配送する。spamはMH方式で~/Mail/spam/ に直接入れて、非spamは/var/spool/mailにmboxとして(旧来のUnix的に)配送する。
~/.fetchmailrc
----------
poll プロバイダのポップサーバ protocol POP3
user プロバイダのサーバのアカウント there password プロバイダのサーバのパスワード is ローカルアカウント here
options fetchall
mda "/usr/bin/procmail -p -f %F"
----------

~/.procmailrc
----------
SHELL=/bin/sh
DEFAULT=$ORGMAIL
SPAM=$HOME/Mail/spam/.

:0 HB
* ? bsfilter --auto-update
$SPAM
----------
 fetchmailはユーザのcronで定期的に動かす。
 これでimgetは排除。
 biffの出力がうるさいので、fetchmailを呼び出すスクリプトに biff n を加える。

 次はMewのバージョンアップ。Mew本家サイト(http://www.mew.org)を見るともうバージョンは4.1になっていた。makeしてインストールして以前のmewを削除したらmewが起動しなくなった。パスが通ってないのである。
.emacs に追加。
----------
(setq load-path (append (list
  (expand-file-name "/usr/local/share/emacs/site-lisp/mew/")) load-path))
----------

.emacs にさらに追加。
----------
(setq mew-mailbox-type 'mbox)
(setq mew-mbox-command "incm")
(setq mew-smtp-server "プロバイダのSMTPサーバ")
----------
 これでimputも排除。

 あとは bsfilter-1.0.4/mua/mew3/mew.el を~/.mew.el としてコピー。bsfilter-1.0.4/mua/mew3/bs_* を /usr/local/bin にコピー。これで学習もMewからできるようになる。

 残る課題は.emacsにプロバイダのSMTPサーバ名を直接書いている部分。できればローカルのSMTPサーバに投げてそこからプロバイダのサーバに投げたいと希望。認証を要求するSMTPサーバの場合、Mewはセキュリティのためパスワードの書かれたファイルを読んでくれたりはしない、すなわちパスワードをその都度要求してくるのである。これはspam以上に迷惑。その対策が必要。
 とりあえずは認証のないSMTPサーバにしている。でもこれ結構遅れたりするのが問題。
 久々に家のメール環境でPop3Biffが有意義に使えるのが嬉しかったりする。実際こういうのが想定環境なのである。imgetだと直接~/Mail/inboxにメールを配信するので、簡単には扱えないのが悔しかったところ。

2004.10.28
 MTAにはsendmailを筆頭にqmail、postfix、exim等いろいろとあるわけだが、どれもこれも襷に長し。牛刀でなくカッターナイフでいいのに。
 ちゃんとしたSMTPサーバはあまりに設定が面倒。日本語のドキュメントが充実してるならまだしもやろうかって気にもなる。sendmailは本まで刊行されていて日本語のドキュメントがある意味充実はしてるようなんだが、あの分厚い本は読む気がしない。いや昔読んだが勘弁してくれな気分になった。
 私はサーバを運用したいのでなく、単にPCをLinuxで使っていて、クライアントとしてメールを扱いたいだけなのである。なんでLinuxなのかというと、家の中のどのパソコンからもメールが読めるようにしたいからだ。各パソコンはtelnetさえ動けばいいのである(MacOS Xでは暫く苦労したが)。メール関連の個人情報はMacintoshやWindowsマシンには入っていない。
 とりあえず、SMTP-AUTHが絡むと面倒そうなので、ねぎ氏のNomail(http://www.ku3g.org/negi/nomail/)を使ってPOP before SMTPでしのぐことにした。
 Nomailは/var/spool/にメールをスプールしておき、ユーザによる任意のタイミングで指定したプロバイダのSMTPサーバに一括で投げるというソフト、というかPerlスクリプト。まさしく私の必要な機能だけがある。
/etc/inetd.conf に追加
----------
smtp stream tcp nowait nomail /usr/sbin/tcpd nomail
----------

.emacs に変更
----------
(setq mew-smtp-server "localhost")
----------
 これでようやくMewではプロバイダ関連の情報は扱わないことになった。もちろんパスワードを請求されることもない。
 Mew-4.1はデフォルトは色がうるさいんで設定を変えなくちゃ。機能を誇示したいのはわかるが、下品すぎ。
.emacs に追加
----------
(setq mew-use-highlight-header nil)
(setq mew-use-highlight-body nil)
(setq mew-use-highlight-url nil)
----------
 bsfilterは結構優秀に判定するようになってきた。
 ところがだ、ついにというかやっと朝日ネットがサービスを開始した。いつ始めるかと待っていたんだが痺れを切らして自力解決したとたんにこれだ。

> 1. 迷惑メールを遮断する「スパムブロック」サービス開始

 まぁ、誤判断を避けるためある程度緩めのブロックだろうから、今回の設定が無駄になるわけではないとは思う。でもちと凹む。

2004.10.28
 nomail/nosendの問題はSMTP-AUTHに対応してないこと、たぶん本人ももう使ってないんじゃないかと思う。そんじゃということででっち上げることにした。
 nomailはそのままで問題ないのでとりあえずいいとして、実際にSMTPサーバと通信するnosend相当の動作を表現しなくてはいけない。たかだか百数十行のPerlなのでママ所蔵の厚さ4cmの「プログラミングPerl」を片手に、片手じゃ重いが、解読した。Perlの構文やPerlの正規表現なんてPerl素人の私には単なる暗号文だ。
 nosendは /var/spool/nomail/ にある数字列のみのファイル名のファイルを読み込み、先頭に羅列してあるアドレスをパラメタにして残りをSMTPサーバに送ってやるという処理をしている。ライブラリを使わずにsocketでやってるのがなぜなのかは知らない。当時なかったのか、はてまたライブラリインストールを指示するのが面倒だったのか。
 以下が「Rubyレシピブック」片手にでっちあげたnosendauth.rbである。nosendが権限のないディレクトリやファイルをどうやって扱っているのか疑問だったが、-Uスイッチという変な技を使っていた。さすがPerlは臭い処理が得意だ。Rubyはまだ臭い処理はできないので、素直に /var/spool/nomail/ の所有者をnomail.usersに、権限を770にした。
 Message-idの削除等使わない機能は実装していない。
nosendauth.rb
----------
#!/usr/bin/ruby
# 2004.11.02 Takeshi Yoneki
require "net/smtp"
$localdomain = "localhost.localdomain" #適当なローカルドメイン名
$internetaddr = "自分のメールアドレス"
$smtphost = "SMTP-AUTH対応のSMTPサーバ"
$account = "アカウント名"
$password = "パスワード"
$smtpport = 25
files = Array.new
Dir.glob("/var/spool/nomail/*").each do |filepath|
  if File.basename(filepath) =~ /^[0-9]+/ then
    files << filepath
  end
end
files.sort!
files.each do |filepath|
  rcptto = Array.new
  maildata = Array.new
  f = File.open(filepath)
  f.flock(File::LOCK_EX | File::LOCK_NB)
  sw = 0
  f.each do |line|
    if sw == 0 then
      if line != "\n" then
        rcptto << line.slice(/^R(.*)/, 1)
      else
        sw = 1
      end
    else
      maildata << line
    end
  end
  done = false
  Net::SMTP.start($smtphost, $smtpport, $localdomain, $account, $password, :cram_md5) do |smtp|
    smtp.send_mail(maildata.join(""), $internetaddr, rcptto)
    print File.basename(filepath) + " OK\n"
    done = true
  end
  f.flock(File::LOCK_UN)
  f.close
  if done then
    File.unlink(filepath)
  end
end
----------
 とりあえずこれで暫く運用。本当はnomailのPerlスクリプトも読んで上記実装が正しいかチェックしなくちゃいけないんだが。

2004.11.02
「ホーム」へ戻る
OSTRACISM CO.
OSTRA / Takeshi Yoneki
2004.11.02