qmail の動作
back
(改装中です)
このドキュメントは qmail の動作をおおまかに説明し、運用の助けと
なるために書かれました。
インストールの方法を書いたものではありません。インストールの
方法については、www.jp.qmail.org
から「qmail 付属文書」→「インストール」をたどってください。
公式サイト(英文)は
http://cr.yp.to/qmail.html
にあります。
私がなぜ qmail を導入したか、その経過については
qmail 導入記を参照。
qmail の特徴
- qmail は sendmail に比べて安全であり、堅牢であり、
設定が楽である。しかも、体感できるほど軽い。
- sendmail と違い、いつ kill -TERM してもメールが失われる
ことがない。そのため安心して停止・再開ができる。
- qmail のセキュリティホールは、発表当時からいまだに
発見されていない。sendmail のように、しょっちゅう穴がみつかって
バージョンアップする必要が生じたりはしない。
- よいシステム管理は、管理者がそのシステムの動作をきちんと
理解していなければできない。qmail は、sendmail のように
1つの「主役」プログラムがすべての機能を担っているわけでは
なく、複数の単純なプログラム群が連携して動いている。
そのため、中でなにがどうなっているのかがわかりやすい。
qmail の動作
はじめに、メイル管理に関する基礎知識をおさらいします:
- メールを扱うプログラムには、フロントエンドをうけもつ
MUA (Mail User Agent) と、実際のメール転送をおこなう
MTA (Mail Transport Agent) がある。qmail は MTA の一種である。
これに対し /bin/mail, MH, Mew などは MUA である。
- すべてのメールは転送の際に表書きというものがつけられていて、
MTA はすべてのメールを
この表書きに従って転送する。表書きはメールの一部ではないので、
ふつうにメールを読み書きしていても見えない
(むしろメールの封筒のようなものだ)。これに対して To: などの
ヘッダはメールの一部である。
- メールの「真の宛て先」は表書きアドレスだから、メールのヘッダ
部分に書かれている To: とは必ずしも一致しないこともある。これを
一致させ、ただしい From: や To: を書くのは MUA の仕事である。
MTA は基本的にメールの表書きしか見ない。
- MTA がおこなうメールの配送には「ローカルな」配送と
「リモートな」配送の 2種類がある。
これらはさらに受信と送信に分けられる。
- あるアドレス宛てのメールを受けとるホストは、
DNS の MX レコードによって決まっている。
- 世の中には悪いやつ (spam をする) がいる。ひどいやつになると、
他人のサーバにメールをばらまかせる。これをメールの不正中継という。
これらについてより詳しく学習したい方は、jp.qmail.org サイトの
メイル管理入門
を読んでください。
MTA のローカル配送とリモート配送について、
もうすこし詳しく説明しておきます。
あるホスト上から 1通のメールを送るとします。メールの視点から
見ると、このメールは次のように処理されます:
- まず MUA によってヘッダとメッセージが作成される。
- そのホスト上で動いている MTA に渡される
(MTA はそのメールを「ローカル受信」したことになる)。
- MTA はそのメールの表書きアドレスを見る。
- そのアドレスが同一ホスト上のユーザであるとき:
MTA はそのメールを
宛て先ユーザのメールスプールに追加するだけ
(MTA はそのメールを「ローカル配信」したことになる)。
- そのアドレスが別のホストのものであるとき:
MTA はまずそのドメイン名を mx で引き、
宛て先の受けつけホストを調べる。
つぎにそのホストに向かって SMTP でメールの表書きを告げ、
ヘッダおよびメッセージを送信する。
つまり「リモート送信」である。
受けつけホスト上で動いている MTA はそのメールを
「リモート受信」したことになる。つぎにその MTA は
表書きアドレスのユーザのメールスプールに受けとった
メールを追加する。つまり「ローカル配信」する。
- どちらの場合も、最終的にメールスプールにたまった
メールを、宛て先のユーザが MUA を使って読む。
いっぽう、あるホスト上で動いている MTA から見ると、
メールの配信とは次の 4つの操作のどれかをやっていることになります:
- ローカル受信して、ローカル配信
(そのホストのユーザが同一ホストのメールスプールに配信、
ファイルのコピーと似たようなもの)
- ローカル受信して、リモート配信
(そのホストのユーザが他のホストにメールを送る)
- リモート受信して、ローカル配信
(他のホストからくるメールをそのホストのメールスプールに配信)
- リモート受信して、リモート配信
(他のホストからくるメールをさらに他のホストに転送、
いわゆるメールの中継)
- qmail はいくつものプログラムからなっている。
- それぞれのプログラムは独自のユーザ権限 (root とは限らない) で
動いている。
- デーモンとして常時生きているプロセスは 4つ。
図1 をみよ。
ここには qmail がどのようにメールを処理するかの流れが書いてある。
赤く記されているのがそのプログラムの動作を決定する
設定ファイルである。これらは /var/qmail/control/ に置かれている。
図1. qmail の動作
例として、ローカルからメールを出す場合を考えてみよう。
図1 の左上をみよ。まずユーザが MH あるいは Mew などの MUA で
メッセージを作る。MUA は qmail-inject を起動し、この
メッセージを渡す。qmail-inject は 2つの設定ファイル
defaultdomain と
defaulthost を見て、このメッセージの
ヘッダを書き換える。つまり、
- From: のドメイン名が省略されていたら、
defaulthost の値をつけ加える。
- To: のドメイン名が省略されていたら、
defaultdomain の値をつけ加える。
といったことをする。これでメッセージは完璧になった。
このメッセージには表書きがつけられ、
図1 の中心にある qmail-queue に渡されて送信キューにためられる。
さて、qmail の一番の中心はキューである。
来たメールは (ローカルにせよリモートにせよ)
いったんキューにためられ、それが qmail-send によって配送される。
qmail-send はキューのメッセージをひとつ取り、その表書きを見て
ローカル宛のものであるかリモート宛かを判断する。このとき
設定ファイル locals が使われる。
このファイルには一行ずつドメイン名が書いてあり、
qmail-send はこのファイル中にあるドメイン宛のメールは
ローカル配信だと判断する。
- メールがローカル配信である場合、そのメッセージは
qmail-lspawn を通して qmail-local に渡される。このとき
メッセージは一瞬だけ root 権限をへて、qmail-local が
その相手先ユーザの権限で起動する。このプロセスはそのユーザの
dot-qmail を読み、それに応じた動きをする。
たいていはメールの forward か、メールスプール (そのユーザの
home directory 上にある) に書きこむかのどちらかだ。
- メールがリモート配信である場合、そのメッセージは
qmail-rspawn を通して qmail-remote に渡される。このとき、
設定ファイル smtproutes が使われる。
smtproutes には、どのドメイン名宛の
メールがどのホストに転送されるべきかが記されている。
では次に、リモートからメールがきた場合。SMTP によるメールは
まず inetd によりとりつがれ、tcpd をへて qmail-smtpd に渡される。
qmail-smtpd は設定ファイル rcpthosts
に書いてある宛先以外のメールは一切受けとらない。これは不正な
メール中継を防ぐためである。しかしこれではゲートウェイにおける、
ふつうの (研究室内ホストからの) 中継ができない。
そのため、つぎのような方法が用意されている。qmail-smtpd は起動時に
環境変数 RELAYCLIENT を調べる。もし起動時にこの RELAYCLIENT フラグが
立っていると qmail-smtpd は rcpthosts
の内容を無視してすべてのメールを受けとる。したがって
研究室内の他のホストからメールを転送するには、研究室内の
ホストから接続されたときだけ RELAYCLIENT が立っているようにすればよい。
これは tcpd を使うとできる。tcpd は相手先のアドレスを見て、
必要に応じてこの変数を立ててくれる。これは tcpd の設定ファイル
/etc/hosts.allow を書き換えることによって行う。
qmail-smtpd を通過したメールは qmail-queue によってキューに入り、
あとはローカルからきたメールと同じ道をたどる。
sendmail の動作
さて、プロセスと設定ファイルという面から同じように
sendmail を見てみると 図2 のようになる。
sendmail デーモンひとつがつねに動いているし、設定ファイルも
sendmail.cf だけなのでシンプルである。
じつに単純 (外側から見れば)。
しかしプログラムはさぞかし複雑だろう。バグがあっても不思議なし。
図2. sendmail の動作
(3/23 追記 - Satoh Wataru さんから情報をいただきました。ありがとう
ございます。実際にはローカル配送は sendmail が直接やっているのでは
なくて、binmail (/bin/mail や mail.local) がやっているようです。また、
「mailer との情報伝達が、smtp 以外は一方向の pipe なので、
配送エラーが起こった際の処理が脆弱だし、1通毎に MDA を
fork -> exec してるので処理が重いです(MDA の return
status が 75 なら rollback するはずだけどしばしば忘れ
られている)。」とのこと)
(6/20 前野 年紀さんより、sendmail はメール送信時にも
ユーザによって起動されるため、sendmail.cf はそのときにも
読まれるというご指摘をいただきました。ありがとうございます)
田中・徳永研究室のメール環境
図3 参照。ここでは
いくつかの条件下で qmail の設定ファイル (とくに
rcpthosts,
locals,
smtproutes)
をどのように設定すべきかを解説する。
なお、control/ 以下のファイルを書きかえたときは
kill -HUP ではなく、qmail-send を上げ直すこと (ただし locals と
virtualdomains は別)。
- 田中・徳永研ドメイン (cl.cs.titech.ac.jp) は古いドメイン名
(cs.titech.ac.jp) が分割されたその一部である。現在は移行期間中のため、
ここでは @cl.cs.titech.ac.jp および @cs.titech.ac.jp 両方のドメイン
宛のメールをうけとることになっている。
- また、研究室内の IPアドレス をすべてプライベート化するという
目的のため、メールは送信・受信ともすべて田中・徳永研のゲートウェイ
cl0.cs.titech.ac.jp を介して行うことにする。
- すべてのユーザのホームディレクトリは
研究室のファイルサーバ snow が管理している。
よって、田中・徳永研メンバー宛のメールは
最終的には snow に来て、そこで qmail-lspawn によって
ホームディレクトリ上のメールスプールに配送されるのが
望ましい。
- 現在のところ(移行期間内) cs内のすべてのユーザはまだ
koudai.cs.titech.ac.jp が一元管理している。
最終的にはどの研究室も独自のドメインを持つことになるが、
いまのところ cs内の他研究室にメールを出すときは
koudai に投げて、koudai が転送してくれるのにまかせることにする。
- koudai は宛先 @cs.titech.ac.jp のメールがくると、
そのユーザの研究室を調べ、それ用にドメイン名を書き直して
各研究室の mx へ送る。ちなみに田中・徳永研の場合、
mx は tanaka.mail.cs.titech.ac.jp あるいは cl.cs.titech.ac.jp が
ゲートウェイである cl0.cs.titech.ac.jp に対応するようになっている。
- そのため、cl0 は @cs 宛のメールは koudai に投げ、@cl 宛の
メールは研究室内行きと判断して snow に投げるようにしたい。
それ以外のメールは外部行きとして自分で mx を引いて相手先ホストに
直接送りつけること。
- snow と cl0 以外の研究室内のホストは、外部へのメールであれば
cl0 に投げ、内部へのメールであれば直接 snow に投げるようにする。
図3. 田中・徳永研究室のメール配送
各マシンの設定ファイル:
- cl0, cl0i (田中・徳永研究室ゲートウェイ)
- まず、研究室外のホストはこれに対して @cs(.titech.ac.jp) 宛か
@cl(.cs.titech.ac.jp) 宛のメールしか送らないはずだ
(そうでないとしたら不正中継だ)。だから
rcpthosts はこの 2つ。
さらに来たメールが @cs 宛のものだったらこれは外向きだから
koudai へ転送し (田中・徳永研メンバー宛であってもいったん
koudai でアドレスを書き換えてもらわねばならない)、
@cl 宛だったら内向きとみなして snow へ転送する。
また、研究室内のホストを中継しているのでまったくの外部行きも
ここを通るはずだ。そういうのは直接相手に送信。したがって
smtproutes にはこの 3つのルール
(実際には直接送信は書く必要がないので 2つ) を書く。
rcpthosts:
(実際は .cs.titech.ac.jp が cl を含んでいるのでこれだけでよい)
localhost
cs.titech.ac.jp
.cs.titech.ac.jp
smtproutes: (ホスト名がついてたときに
備えて 2つずつにしてある)
cl.cs.titech.ac.jp:snow.cs.titech.ac.jp
.cl.cs.titech.ac.jp:snow.cs.titech.ac.jp
cs.titech.ac.jp:koudai.cs.titech.ac.jp
.cs.titech.ac.jp:koudai.cs.titech.ac.jp
- snow (田中・徳永研究室ファイルサーバ)
- これも rcpthosts は cl0 と同じ理由。
ただ、このマシンはメールスプールだから、@cl 宛のメールはここで
ローカル配信する。したがって locals に
このドメインを 1つ書く。それ以外のメールはもう外向けと
わかりきっているので、すべて cl0 に転送する。よって
smtproutes にはそのルールが 1つ。
rcpthosts:
(cl0 と同じ)
locals:
cl.cs.titech.ac.jp
.cl.cs.titech.ac.jp
smtproutes:
:cl0i.cs.titech.ac.jp
(ハマリ記録: snow から研究室外にいくメールが、はじめ
拒否された。これは smtproutes の行き先を
研究室の内側の口である cl0i (131.112.20.2) ではなく、
外側の口 cl0 (131.112.16.208) にしていたことが原因。
snow も外側の口 wons (131.112.16.198) を持っているため、
cl0 に転送するときはそっちを使ってしまい、cl0 の
tcpd が「こいつは研究室の外のやつだ」と判断してしまうため
である)
- その他の研究室内のマシン
- これも rcpthosts は同じ。
smtproutes は、@cl 宛なら
わざわざ cl0 に送る必要もなので直接 snow に転送。
それ以外なら snow と同様に cl0 へ。
rcpthosts:
(cl0 と同じ)
smtproutes:
cl.cs.titech.ac.jp:snow.cs.titech.ac.jp
.cl.cs.titech.ac.jp:snow.cs.titech.ac.jp
:cl0i.cs.titech.ac.jp
無断リンク集
MUA の設定
qmail についてくる「にせ sendmail」の機能:
- -t
- ほかのオプションを無視する。
- -f差出人
- sender を変える。
- -F差出人の名前
- sender のフルネーム。
- -bp
- キューを表示。
- -bs
- 標準入出力から SMTP で通信。
- MH
- メールを出す場合、MH の send コマンドは
/usr/(local/)lib/mh/post を呼び出す。しかしこれは
ローカルホストにわざわざ SMTP で投げるので、ローカルに
tcp_wrapper を入れておかねばならず面倒。直接 qmail-inject で
キューに入れてほしい場合、この post を同じディレクトリにある
spost に置き変えれば OK。
あと、/usr/(local/)lib/mh/mtstailor を、
mmdfldir:
mmdflfil: Mailbox
sendmail: /var/qmail/bin/sendmail
としておけば各人の ~/.mh_profile は書きかえる必要なし。
- Mew
- Maildir を使う場合はいろんなページに書いてある。
$HOME/Mailbox の場合、~/.im/Config の Imget.Src を
Imget.Src=local:${HOME}/Mailbox
にすれば OK か。あるいは im の共有設定ファイル
/usr/local/lib(share?)/im/SiteConfig を書きかえる。
Last modified: Fri Sep 28 13:36:24 2001
Yusuke Shinyama