-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
414 lines (321 loc) · 16.8 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
smtp_wrapper-0.5 -- SMTP filtering support daemon
Copyright (C) 2006 Masahiko Ito
These programs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
These programs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with these programs; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Mail suggestions and bug reports for these programs to
"Masahiko Ito" <[email protected]>
History
=======
2005/11/25 Develop started
2006/01/23 Ver. 0.1 release (1st)
2006/05/15 Ver. 0.2 release
2006/05/24 Ver. 0.3 release
2006/10/02 Ver. 0.4 release
2007/??/?? Ver. 0.5 release
What's this ?
=============
主にspam対策としてsmtp serverと自作のspamチェックスクリプトを連係さ
せるためのデーモンプログラムです。
spam対策としては既にいくつかの定番的手法が確立しています。クライアン
ト側からのアプローチとしてはベイズ理論を利用したフィルタプログラム +
procmailの組合せであったり、サーバ側からのアプローチとしてはMILTER対
応した同様のフィルタ + sendmailの組合せであったりするようです。
ベイズ理論を利用したフィルタは実際、非常に効果があります。ただし、学
習効果を積み重ねて行くうちにデータベースが肥大化していき、徐々に動き
が重くなって来るような気がします。そんなおり、ウェブ上で以下の情報を
見つけました。
o 阻止率99%のスパム対策方式の研究報告
(Selective SMTP Rejection (S25R)方式)
- http://www.gabacho-net.jp/anti-spam/
o spam
- http://moin.qmail.jp/spam
上記のページ内容を自分なりに要約した結果、
o 接続元IPがDNSの逆引出来なければ拒否
-> 逆引出来ないSMTPサーバからのメールの多くはspamである。
o 接続元IPがDNSの逆引結果(FQDN)から動的IPと類推される場合は拒否
-> 動的IPを持ったSMTPサーバからのメールの多くはspamである。
o 接続要求に対して、一定時間接続を遅延させる
-> spamを送信するSMTPサーバの多くは大量かつ高速にメール配信するこ
とを第一目的としており、応答の鈍いサーバに対しては早々に配信を
諦めて接続を切断する傾向に有る。
という3手法のみでも、かなり高い確立でspamを排除できるのではないかと
考えました。しかも、上記の方法はメール内容そのものは判断しないので、
チェックにかかる負荷も非常に軽いことが予想されます。
で、実際にどのように実装するかということになると、上記のページではMTA
がpostfixまたはqmailである事が前提となる説明がされていて、sendmailと
の組合せとなると自力でなんとかしなければならないようです。
正攻法で行くなら、MILTERを利用したフィルタを作成するべきでしょう。お
そらく最も高いパフォーマンスでspamチェックをこなしてくれると思います。
MILTERを利用するにはlibmilterを利用してC言語でフィルタを作成します。
ドキュメントはsendmailのソースディレクトリ中のlibmilter/docs/以下に
有りますので、それを参考に作業します.....が、ごめんなさい。私には
MILTERを理解してフィルタを書くことが出来ません、というかドキュメン
トを読解する気力がありませんでした(^_^;。ですので別のアプローチで
実装することにしました。
実装するに当たって以下の点に留意しました。
o フィルタはそこいらのスクリプト言語(sh, perl, ruby ...)で書きたい。
o どうせならspamチェック以外の機能も簡単に盛り込めるようにしておき
たい。
o フィルタは「フィルタ」ちゅうぐらいですから標準入力を読んで、結果
を標準出力に出力するだけで機能するようにしたい。
とりあえず志は低く、上記の3点を実現するためにsmtp proxy的なデーモン
を作ってみました。
Install
=======
o cd /usr/local/
o tar xvzf smtp_wrapper-0.5.tar.gz
o ln -sf smtp_wrapper-0.5 smtp_wrapper
o cd smtp_wrapper
o cc -o smtp_wrapper smtp_wrapper.c
o vi smtp_filter1.sh # フィルタは各自で用意して下さい(for ip_filter)
o vi smtp_filter2.sh # フィルタは各自で用意して下さい(*必須*)(for contents_filter)
o chmod +x smtp_filter[12].sh
o smtp_wrapper -h
Usage : smtp_wrapper [-mh hostname] [-mp port] [-q backlog]
[-sh smtpserver_hostname] [-sp smtpserver_port]
[-t timeout_sec] [-d delay_sec] [-if ip_filter]
[-f contents_filter] [-cm child_max] [-i minimum_interval_sec]
[-F]
-mh hostname : my hostname [ANY]
-mp port : my port [25]
-q backlog : socket queue number [5]
-sh smtpserver_hostname : real smtp hostname [localhost]
-sp smtpserver_port : real smtp port [8025]
-t timeout_sec : timeout second [no timeout]
-d delay_sec : delay second for initial connection [0]
-if ip_filter : filter program for IP check [/usr/local/smtp_wrapper/smtp_ip_filter]
-f contents_filter : filter program for contents check [/usr/local/smtp_wrapper/smtp_contents_filter]
-cm child_max : max number of connection to real smtp daemon [10]
-i minimum_interval_sec : minimum interval second of connection from same ip address [0]
-nsc : no sequence error check
-F : run in foreground
sendmailの設定
==============
o vi sendmail.mc
以下の定義を追加
DAEMON_OPTIONS(`Port=8025, Name=MTA')dnl
o vi submit.mc
以下の定義を追加
DAEMON_OPTIONS(`Port=8025, Name=NoMTA, Addr=127.0.0.1, M=E')dnl
o sendmail.cf, submit.cfを更新
sendmail.cfに以下の行が追加されている事を確認
---------------------------------------------
O DaemonPortOptions=Port=8025, Name=MTA
submit.cfに以下の行が追加されている事を確認
-------------------------------------------
O DaemonPortOptions=Port=8025, Name=NoMTA, Addr=127.0.0.1, M=E
起動
====
o vi /etc/rc.d/rc.local
if [ -x /usr/local/smtp_wrapper/smtp_wrapper ]
then
/usr/local/smtp_wrapper/smtp_wrapper \
-t 60 \
-d 10 \
-if /usr/local/smtp_wrapper/smtp_filter1.sh \
-f /usr/local/smtp_wrapper/smtp_filter2.sh \
-cm 10 \
-i 5
echo ' smtp_wrapper'
fi
o reboot
Figure
======
+-----------------------------------------------------------+
| |
| |
+-----+ command +------------------+ command +----------------+ |
| |--------->|(1) [2]|----------->| | |
| MTA |SOCKET(25)| smtp_wrapper |SOCKET(8025)| MTA | |
|(MUA)|<---------|[1] (2)|<-----------| (sendmail etc) | |
| | response | | response +----------------+ |
+-----+ | | (3) [3] | |
| +------+----+------+ |
| A P | |
| | I | |
| | P | |
| | E | |
| (stdout) | V (stdin) |
| +--------+ |
| | IP |--------+ |
| | FILTER |CONTENTS| |
| | | FILTER | |
| +--------+ | |
| +---------+ |
| |
+-----------------------------------------------------------+
o smtp_wrapper(親)が本来のMTAに代ってsmtp(25)ポートへの接続を監視します。
o 接続を受けたsmtp_wrapper(親)は、今現在稼働しているsmtp_wrapper(子)の
数が`-mc'オプションで指定した数を越えている場合、その数が`-mc'オプショ
ンの指定値の2分の1以下になるまで`-d'オプションで指定した秒数のsleepを
繰り返します。
o 同一IPからの連続した接続に対して、その接続間隔が`-i'オプションで指定
した秒数よりも短い場合は、その接続に対して一時エラー(421)を返し接続を
閉じます。
o smtp_wrapper(親)は子プロセス(smtp_wrapper(子))を生成し、以降の接続元
との通信を子プロセスにまかせ、再度smtp(25)ポートの監視を繰り返します。
o smtp_wrapper(子)は`-d'オプションで指定した秒数sleepした後に接続元と
の通信を開始(greeting message送出)します。
o smtp_wrapper(子)は接続元のIPアドレスを環境変数`SW_FROM_IP'に設定した
のち`-if'オプションで指定したフィルタプログラムをfork&execします。こ
のフィルタプログラムには環境変数`SW_FROM_IP'の情報を元にしたチェック
を行わせます。その際、このフィルタプログラムの標準入力に対しては一切
データは渡されないので、コンテンツの内容を利用したチェックは出来ませ
ん。
フィルタプログラムには、正当な接続に対しては`OK'または`ok'または`'(空
文字列)を標準出力に出力させ、不正な接続に対しては`OK',`ok'以外のメッセー
ジを標準出力に出力させ、終了させます。
フィルタプログラム実行中に接続元からの通信が切断された場合、フィルタプ
ログラムの終了を待たず、直ちにsmtp_wrapper(子)に制御が戻ります。S25Rに
該当するMTAに対して遅延(sleep)をかけるようなスクリプトを効率良く運用で
きるようになります。
参考 : Starpitでほぼ誤検出無く98%のスパムを排除 (S25R+tarpittingによるスパム対策)
http://d.hatena.ne.jp/stealthinu/20060706/p5
o smtp_wrapper(子)はフィルタプログラムからのメッセージが`OK',`ok'以外の
文字列で始まっていた場合、それを不正な接続とみなし、接続元に`450'で始
まる一時エラー応答を返します。フィルタプログラムのチェックを通過した後、
本来のMTAに対して接続を開始し、`-f'オプションで指定したフィルタプログ
ラムをfork&execします。
o smtp_wrapper(子)は接続元からのメッセージのうち`HELO'、`MAIL FROM:'、
`RCPT TO:'等の`DATA'コマンドまでのメッセージを本来のMTA(上図では、待ち
受けポートを8025に変更)とフィルタプログラムに渡し、MTAからの応答メッセー
ジを接続元に渡します。その後`DATA'から`.'までをフィルタプログラムのみ
に渡した後、フィルタプログラムからの応答(チェック結果)を待ちます。
o フィルタプログラムには標準入力から受け渡されたメッセージ本文から正当な
メッセージか不当なメッセージかを判断し、正当なメッセージと判断した場合
は受け渡されたメッセージのうち`DATA<CR><LF>'から`.<CR><LF>'までを標準出
力に出力させます。また不正メッセージと判断した場合は直ちに終了するか、
`DATA<CR><LF>'以外で始まるメッセージを標準出力に出力した後、終了させま
す。
o smtp_wrapper(子)はフィルタプログラムからのメッセージが`DATA<CR><LF>'で
始まっていた場合、それを正当なメッセージとみなし、本来のMTAに受け渡しま
す。またメッセージが`DATA<CR><LF>'以外で始まっていた場合、それを不正な
メッセージ(spam)とみなし、接続元に`450'で始まる一時エラー応答を返します。
o 以降、smtp_wrapper(子)は接続元から`QUIT<CR><LF>'を受け取るまで、または
接続元<->smtp_wrapper(子)間のコネクションが切断されるまで、または
smtp_wrapper(子)<->本来のMTA間のコネクションが切断されるまで上記の動作
を繰り返します。
spam対策機能(のまとめ)
======================
o `-i'オプションで指定した秒数未満の間隔での、同一IPからのアクセスを拒否する。
接続元には以下のメッセージを返す。
421 Service not available, closing transmission channel(rejected by rapidly access. IP=%s)(SW01)\r\n
o `-if'オプションで指定したフィルタにより不正と判断された場合、アクセスを拒否
する。
接続元には以下のメッセージを返す。
450 This message was rejected according to site policy(rejected by ip_filter. IP=%s)(SW02)\r\n
o SMTPコマンドの送受信順序を無視したアクセスを拒否する。`-d'オプション指定に
より遅延させたgreeting messageを待ち切れずに、おそらく多くのspammerがメッ
セージを送り付けて来る。これを撃退する。
接続元には以下のメッセージを返す。
450 This message was rejected according to site policy(rejected by seq error. IP=%s)(SW05)\r\n
o `-f'オプションで指定したフィルタにより不正と判断された場合、受信を拒否する。
接続元には以下のメッセージを返す。
450 This message was accepted partly, but it was rejected according to site policy(rejected by contents_filter. IP=%s)(SW09)\r\n
450 This message was accepted all, but it was rejected according to site policy(rejected by contents_filter. IP=%s)(SW10)\r\n
Filter
======
`-if'で指定するフィルタの基本的な構造は以下のように作成してください。
---------------------------------------------------------------------
o 主に接続元のIPアドレスに対するチェックを行います(S25R)。
o 環境変数`SW_FROM_IP'に設定されている接続元のIPおよびIPから
逆引したFQDNをチェックし、正当な接続と判断したならstdoutに
何も出力せずにexitして下さい(明示的に正当である事を示したい
場合は`OK'または`ok'を出力しexitする事も可能)
不正な接続と判断したなら、stdoutに`OK', `ok'以外で始まるメッ
セージを出力しexitして下さい。このstdoutに出力したメッセージ
はsyslog経由(mail.info)で記録されます。
o 要約
正当な接続時 : stdoutには何も出力せずに終了する(`OK', `ok'を
出力する事も可能)。
不正な接続時 : `OK', `ok'以外で始まるメッセージをstdoutに出
力して終了する。
`-f'で指定するフィルタの基本的な構造は以下のように作成してください。
--------------------------------------------------------------------
o 主にコンテンツ内容に対するチェックを行います(第三者リレーチェック)。
o *必ず*、一旦stdinからの入力を全てテンポラリファイルに書き出
して下さい。通常stdinからは
`HELO ...<CR><LF>'または`MAIL FROM: ...<CR><LF>'
-> いくつかのSMTPコマンド
-> `DATA<CR><LF>'
-> メール本文
-> `.<CR><LF>'
の順でデータが入って来るでしょう...。
o テンポラリファイルに書き出したデータをチェックし、不正接続
と判断したならexitしてください。また、exit直前にstdoutに出
力した内容の最初の1行がsyslog経由(mail.info)で記録されます。
その際の出力には`DATA<CR><LF>'を含めないで下さい(smtp_wrapper
が正当なメールと誤判断してしまうので)。
o *必ず*、上述のテンポラリファイル中の`RCPT TO:'の内容と環境
変数`SW_FROM_IP'の内容から不正リレー(第三者リレー)をチェッ
クし、不正接続と判断したならexitしてください。
smtp_wrapperを利用すると(おそらく)sendmailでの/etc/mail/access
等を用いた第三者リレーチェックが効かなくなります。sendmail
から見ると接続して来るサーバは全て自分自身(smtp_wrapper)な
ので判断のしようが無いためです :-P
o 必要に応じて、その他のチェック(spam,virus etc)を行い、不正
接続と判断したならexitしてください。
o 必要に応じて、その他の必要な処理(ヘッダー挿入、内容改竄、
極秘保存等)を行って下さい B-)
o 最終的に、正当な接続と判断されたなら、上述のテンポラリファ
イルから
`DATA<CR><LF>'
-> メール本文
-> `.<CR><LF>'
をstdoutに出力しexitしてください。
o 要約
正当な接続時 : `DATA<CR><LF>' -> メール本文 -> `.<CR><LF>'
を標準出力に出力し終了する。
不正な接続時 : `DATA'以外で始まるメッセージを標準出力に出力
し終了する。
※ 本フィルタ(`-f')は*必ず*設置しなければなりません。最低限、
標準入力から`DATA<CR><LF>' -> メール本文 -> `.<CR><LF>'を
標準出力に出力する機能を実装して下さい(see sample/smtp_null_filter.sh)。
※ 従来(Ver. 0.2.x以前)と同様に`-f'オプションで指定するフィル
タプログラムに全てのチェックを行わせることも可能です。その
場合は`-if'オプションを指定する必要はありません。
非力なサーバで運用される場合は`-if', `-f'を使い分けた方が
負荷が軽減されるでしょう。ちなみに、うちのサーバは
MMX166MHz + Memory 64MB ;)
BUGS
====
o とりあえず、フィルタスクリプトを自分で書かないと、あまり意味
がありません。一応、smtp_wrapperだけでも`-i'オプションによる
速射spam対策と`-d'オプションによる`greet pause'効果
(sendmail-8.13.x系でも同様の機能を導入)は見込めるのですが...。
o fetchmailで取り込むメールを重複して受信することがあるようで
す(-_-;。
まず、fetchmailで取り込むメールはフィルタの検査対象にしては
なりません。なぜなら、複数のメッセージを取り込んでいる途中
でspamと判定されるメッセージが有った場合、fetchmailの動作が
その時点で終了してしまう(ようだ)からです。この場合、手動で
POPサーバ側からspamメールを削除しない限り、永久に先に進めな
いのではないかと思われます。
また、仮にフィルタ側で常にspamでないと判断させ、smtp_wrapper
をスルーさせても、システムのロードアベレージが10を越えて
sendmail自身がメッセージの受付を拒否し始めた場合に重複して受
信することがあるようです。
ですので結局のところfetchmailに関しては、
fetchmail -S localhost/8025 ほにゃらら
みたいにして、smtp_wrapperをすっ飛ばして受信したほうが良さそ
うです。
fetchmailを使って(個人で)取り込むメールのspam対策は、procmail
と上述のフィルタの応用版、もしくはベイズ系フィルタとの組合せ
でもって、クライアント側で対応するのが吉かと...。
o sampleディレクトリ以下のスクリプトに関してはセキュリティに甘
い部分があります。一時ファイルを無頓着に/tmpや/var/tmpに作成
しているので、root以外のユーザによるシンボリックリンク攻撃に
さらされる可能性があります。運用するサーバのローカルユーザが
実質的にrootしか存在しない場合は、問題にならないと思いますが、
あまり褒められたものではありません :<
その辺り、本番運用で利用される場合はくれぐれも御自身で検討し、
必要な修正を施した上で利用してください。