Postfixのぺーじ | ||
− Postfixでの正規表現のススメ | ||
更新: 2005年2月19日 |
ホーム >オリジナルドキュメント >Postfixでの正規表現のススメ
注意: このページの記述は私がよくわかって ない部分をかなり含んでいます。特に全てのユーザ名を表す正規表現は 正確でないかもしれません。実際にこのページをみて正規表現を利用する 際には、洩れるアドレスはないか、余分なアドレスがマッチしないか 十分に確認してから実際に利用して下さい。
また、何かお気づきの点がありましたら 私 までお知らせ下さい。 便利な正規表現の使い方もお待ちしています。
Postfix で様々な条件が絡んだ細かい設定を必要とするとき、正規表現を 使った設定が役に立つかもしれません。特に sendmail で使ってきた設定を Postfix に持ち込むには、正規表現による制御が必要になるでしょう。
しかし、通常の db/dbm などのマップと異なり、アクセスの負荷が大きいため、 流量の多いサイトでこれを使うと問題が起こるかも知れません。しばらくは トラブルを避けるためにもログなどの監視が必須です。
Postfix では POSIX 互換正規表現と PCRE (PERL-compatible regular expression) をサポートしていますが (regexp は 19990316版以降、PCRE は 19990307 版以降)、 一部のシステムでは POSIX 互換正規表現は使えません。 BSD 系や Linux などではデフォルトで POSIX 互換の正規表現が 使えるようになっていますが、一部のシステムではこれが使えません。
正規表現とは?
正規表現とは、簡単にいうと、ある文字列の中から特定のパターンを
探し、見つかった場合にはそれに対してなんらかの処理をすることを
指します。これを使うと、abc で始まるメールアドレスとか、
途中に xyz を含むドメイン名を探して、そのメールを
受け入れないようにしたり、ある特定のユーザに転送したりすることが
できます。
デフォルトでは *BSD、Linux、HP-UX などでは regexp が組み込まれますが、 PCRE はどのシステムでもデフォルトでは組み込まれないので、 コンパイル時に PCRE ライブラリをリンクする必要があります。
PCRE を Postfix で使うには、まず Postfix のダウンロードサイトから PCRE version 2.08 を取得します。これを Postfix のソースアーカイブと同じディレクトリに置き、 両方とも展開します。
% tar xvzf pcre-2.08.tar.gz % tar xvzf postfix-19991231-pl09.tar.gz
先に PCRE のライブラリを構築します。
% cd pcre-2.08 % vi Makefile (AR, CC, CFLAGS, RANLIB をシステムに合わせて設定します。 インストールまでするのであれば、BINDIR, INCDIR, LIBDIR, MANDIR も設定します。) % make % cd ../
次に Postfix の構築です。PCRE のライブラリをリンクするように Makefile を作ってコンパイルします。
% cd release-20010228 % make tidy (以前に make したことがあれば必須です) % make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE \ -I../../../pcre-2.08' 'AUXLIBS=../../../pcre-2.08/libpcre.a' (19991231 版など、ソースが src 以下にないものは次のようにします: % make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE \ -I../../pcre-2.08' 'AUXLIBS=../../pcre-2.08/libpcre.a') % make
インストールされた Postfix が regexp や PCRE を使えるかを チェックするには、
% postconf -m
コマンドを使います。
正規表現の基本文法は Riueちゃんの正規表現講座 などをみて下さい。
Postfix で正規表現を使う場合には、
正規表現 返すテキスト
の形式である必要があり、
$myhostname などの変数をセットしたり使うことは出来ません。
変数としてセットできるのは ( ) で囲んだ部分だけです
((?!...) などは除く)。これは前から順に $1、
$2... のようになり、 2つめのフィールドで使うことが出来ます。
また、アドレスやホスト・ドメイン名、ヘッダなどをマッチさせる場合には、
/^...$/ のように最初と最後を必ず指定するようにしましょう。
これがないと思わぬものがマッチしてしまう可能性があります。
正規表現によるマップを作ったら、それをテストしてみましょう。
Postfix にはマップのチェック用プログラムがあり、これを使って
実際に特定の処理を行ないたい文字列を正規表現にマッチするかチェック
できます(このプログラムは db など他のマップにも使えます)。
チェック用プログラムは次のように作成します。まず、Postfix のコンパイル 直後 (PCRE ライブラリをチェックする場合には PCRE 付きでコンパイルした 直後) に Postfix のトップディレクトリに行き、そこで、
% cd util % make dict_open
とします。アーカイブ展開直後や make tidy で Makefile を消してしまった場合には、トップディレクトリで
% make makefiles (PCRE 使用の場合は % make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE -I../../pcre-2.08' \ 'AUXLIBS=../../pcre-2.08/libpcre.a')
とした後で上の make dict_open を実行します。
チェックのしかたはマップファイルを用意して、
% ./dict_open maptype:/etc/postfix/mapfile read
としてマップを読み込ませて、あとはマッチするかチェックしたい文字列 (例えばメールアドレスやホスト名、ヘッダなど)を入力します。 標準入力から読み込むので、単に上のコマンドを実行した場合には、 終了時に ^D (or ^C) を使って抜ける必要があります。
単に一つ、もしくは少数のアドレス宛のメールを受けないようにするには db/dbm によるマップファイルが楽ですが、例えば user???@domain (??? は任意の数字)宛のメールは 全て受けたくないなどの場合には、全て羅列するのは面倒です。 こんな時には正規表現を使って簡単に書くのがベスト。いかにも 練習問題っぽいですが...
まず main.cf に
smtpd_recipient_restrictions = ... regexp:/etc/postfix/recipient_check smtpd_recipient_restrictions = ... pcre:/etc/postfix/recipient_check
のように regexp または pcre のファイルを読むように追加して (デフォルトで permit_mynetworks,check_relay_domains が $smtpd_recipient_restrictions に入っているので、 これも記述する必要があるでしょう)、 recipient_check ファイルに regexp の場合は
/^user[0-9]{3}@.+$/ 550 user unavailable temporarily.
pcre の場合は
/^user\d{3}@.+$/ 550 user unavailable temporarily.
と記述すればよいでしょう。
ヘッダに特定の文字列、例えば I Love You ウィルスのように サブジェクトが
Subject: ILOVEYOUになっているメールを全て拒否する
には、main.cf に
header_checks = regexp:/etc/postfix/header_checks header_checks = pcre:/etc/postfix/header_checks
のどちらかを加えて、header_checks に次のように記述します。
/^Subject: ILOVEYOU$/i REJECT
これは regexp, PCRE ともに共通です。最後の i は大文字・
小文字の区別をすることを意味します。
ただし、この方法ではオリジナルのウィルスしか拒否できませんし、
誰かが ILOVEYOU というサブジェクトのメールを送っても、それを
拒否してしまうということは考えておく必要があります。
MIME で拡張子が vbs ファイルが添付されているメールを全て拒否 するように設定するには、main.cf に
body_checks = regexp:/etc/postfix/body_checks body_checks = pcre:/etc/postfix/body_checks
のどちらかを加えて、body_checks に次のように記述します。
/^content-type:.*name.*\.vbs.*/ REJECT
これも regexp, PCRE ともに共通です。
例えば majordomo で作られたメーリングリストの配送用アドレスに 外部から直接メールを送ることを禁止するために、 (ML名)-outgoing@domain.name 宛のメールを禁止したいが、 owner-(ML名)-outgoing@domain.name 宛のメールは受け取りたい、 しかも間違ったアドレスに送った人には正しいアドレスに送るように 案内したい場合には、main.cf に
smtpd_recipient_restrictions = ... regexp:/etc/postfix/recipient_check smtpd_recipient_restrictions = ... pcre:/etc/postfix/recipient_check
のように regexp または pcre のファイルを読むように追加して (デフォルトで permit_mynetworks,check_relay_domains が $smtpd_recipient_restrictions が入っているので、 これも記述する必要があるでしょう)、 recipient_check ファイルに regexp の場合は
/^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead
のように記述します。これは前の /.../ に一致したものから !/.../ に一致したものを除いたものがマッチし、(...) の中身が前から順に $1、$2 という変数に代入 されます。これを応答メッセージに埋め込んで 550 エラーメッセージで smtpd がクライアントに応答します。
PCRE の場合は
/^(?!owner-)(.*)-outgoing@(connect.com.au)$/ 550 Use ${1}@${2} instead
のように記述します。これは (?!owner-) の部分が owner- を含まないものにマッチした上で変数に ( ) 内がセットされず、その結果2つ目と3つ目の ( ) の中身が それぞれ $1 と $2 にセットされます。
これは sendmail の CF でいうところの RELAY_LOCAL_TO_HUBHOST に相当する機能を Postfix に組み込む方法です。すなわち、ローカルで user@domain 宛ではなく user 宛に送られたメールをローカルで処理 するのではなく、ハブホストに全て投げたい場合には、次のように 設定します。まず main.cf で
$append_at_myorigin = no
をセットし、 $virtual_maps に pcre:/etc/postfix/virtual を加えて、virtual ファイルには次のように記述します。
/^([\w+\-\.]+)$/ ${1}@hubhost.domain
これにより、@ を含まないアドレス宛のメールは
user@hubhost.domain に転送されます。
(regexp:/etc/postfix/virtual とした場合には、
virtual ファイルに
/^([a-z0-9_+\-\.]+)$/ ${1}@hubhost.domain
と記述します。)
なお、$append_at_myorigin = no を設定すると、root 宛のメールなども全て root@hubhost として処理されて しまうので、alias データベースにあるローカルユーザは virtual に登録しておく必要があるかもしれません。