spam filtering with transport/router of exim

I used to classify spam mail with procmail, but procmail is excuted only for local users. So when you use the .forward file, spam mail is also forwarded to the other email addresses.
It’s not so quite import but I don’t like this behavior. so I change the exim configuration to run bogofilter with the transport/router of exim.
first let’s configure transport like this.
bogofilter:
driver = pipe
command = /usr/sbin/exim -oMr bogodone -bS
use_bsmtp = true
transport_filter = /usr/bin/bogofilter -d /etc/bogofilter/ -e -p
log_output = true
return_path_add = false
temp_errors = *
home_directory = "/tmp"
current_directory = "/tmp"
message_prefix = ""
message_suffix = ""

after that you need to declare the router which uses this transport. Order is important in router. I put it right after the system_alias router.
bogofilter:
domains = +local_domains
no_verify
condition = ${if !eq {$received_protocol}{bogodone} {1}{0}}
driver = accept
transport = bogofilter

With this configuration, bogofilter will be excuted but it put only an additional header like “X-bogofilter: …” so we need another transport/router to classify the spam mails.
Here’s the transport to do that.
spam_delivery:
driver = appendfile
directory = /home/$local_part/.maildir/.Spam
maildir_format
delivery_date_add
envelope_to_add
return_path_add

With this transport, we can put the spam mails to the .Spam folder within $HOME/.maildir. If you use the IMAP protocol, then you can simply check the spam mails by accessing Spam folder. But with POP3 protocol there’s no way to check it. So if you use POP3 then use the header filtering rules of client software instead.
And we also need to add a router which uses this transport. The order is important in here too. I put it below the bogofilter router.
removingspam:
driver = accept
check_local_user
condition = ${if match {$h_X-Bogosity:} {Spam, tests=bogofilter} {1}{0}}
transport = spam_delivery

Spam mail has the header, X-Bogosity: Spam, test=bogofilter …, so we can classify the spam mail easily.
To confirm it working, check the mail log. I checked /var/log/mail/current because I use metalog but in almosts linux distributions syslogd is included so check the /var/log/messages file.

$ # tail -f /var/log/mail/current |grep R=
Feb 26 16:48:31 [exim] 2008-02-26 16:48:31 1JRkT5-0001pz-Nx => mailaddr R=procmail T=procmail
Feb 26 16:48:35 [exim] 2008-02-26 16:48:35 1JTuY0-00081q-7u => mailaddr R=removingspam T=spam_delivery
Feb 26 16:48:44 [exim] 2008-02-26 16:48:44 1JQWAs-0002po-CR => mailaddr R=bogofilter T=bogofilter
Feb 26 16:48:45 [exim] 2008-02-26 16:48:45 1JTuY5-000826-EK => mailaddr R=removingspam T=spam_delivery

The name of router/transport is located after R= and T= . The name of router appears after R=, and the name of transport appears after T=. According to this log, we can say that removespam or procmail router is used after the bogofilter excuted.

exim 의 transport, router 를 이용한 스팸 필터링

익숙한 걸 사용하려다보니 procmail 을 이용해서 bogofilter 를 수행하는 방법을 사용해 왔지만, procmail 은 로컬 유져에 한해서 실행되게 되므로, alias 나 .forward 를 사용하게 되는 경우 스팸 필터링을 하지 않게 된다.
하여튼 이게 좀 신경쓰여서 transport 와 router 를 이용해서 bogofilter 를 수행하도록 설정해봤다.
우선 transport 를 다음과 같이 설정해보자.
bogofilter:
driver = pipe
command = /usr/sbin/exim -oMr bogodone -bS
use_bsmtp = true
transport_filter = /usr/bin/bogofilter -d /etc/bogofilter/ -e -p
log_output = true
return_path_add = false
temp_errors = *
home_directory = "/tmp"
current_directory = "/tmp"
message_prefix = ""
message_suffix = ""

그리고 이 transport 를 이용하는 router 를 만든다. 참고로 router 는 순서에 민감하므로 삽입할 위치를 잘 조절해야 한다. 나같은 경우는 system_alias 다음에 선언해두었다. (alias 를 사용하는 주소들중 로컬 유져에게 전달되지 않는 건 mailman 과 관련된 것들 밖에 없는데 이거야 뭐 어짜피 인증된 사용자가 보낸 메일만 받으니 상관 없겠다는 마음으로…-_-;; )
bogofilter:
domains = +local_domains
no_verify
condition = ${if !eq {$received_protocol}{bogodone} {1}{0}}
driver = accept
transport = bogofilter

여기까지만 하게 되면 bogofilter 를 수행하기는 하지만 이를 이용해서 메일을 옮긴다거나 하는 동작은 하지 않게 된다. 그러므로 이런 동작을 시키기 위한 transport 와 router 를 또 추가해주자.
역시나 transport 먼저…
spam_delivery:
driver = appendfile
directory = /home/$local_part/.maildir/.Spam
maildir_format
delivery_date_add
envelope_to_add
return_path_add

이렇게 하면 자신의 홈 디렉토리의 .maildir 아래 .Spam 이란 디렉토리를 만들고, 그 디렉토리에 스팸 메일을 저장하게 된다. IMAP 으로 접속하면 Spam 메일들을 확인할 수 있기 때문에 이렇게 했는데, POP3 만 사용하는 거라면 그냥 제목에 [Spam] prefix 를 붙이게 하는 것도 나쁘지 않을 듯…
그 다음엔 이 transport 를 이용하는 router! 역시나 어디다 위치시킬지 잘 생각해야 한다. 나같은 경우엔 bogofilter router 바로 아래에 이걸 위치시켜놓았다.
removingspam:
driver = accept
check_local_user
condition = ${if match {$h_X-Bogosity:} {Spam, tests=bogofilter} {1}{0}}
transport = spam_delivery

스팸 메일은 bogofilter 에 의해 X-Bogosity: Spam, test=bogofilter … 식의 헤더가 추가되기 때문에 이렇게 할 경우 스팸을 쉽게 분류해낼 수 있다.
잘 됐는지 확인은 메일로그를 이용해서 확인하면 된다. 나같은 경우는 metalog 를 사용하니 /var/log/mail/current 를 이용해서 확인해야 했는데 대부분의 경우 syslogd 를 사용할테니 /var/log/message 를 확인하면 될 것 같다.

$ # tail -f /var/log/mail/current |grep R=
Feb 26 16:48:31 [exim] 2008-02-26 16:48:31 1JRkT5-0001pz-Nx => 메일주소 R=procmail T=procmail
Feb 26 16:48:35 [exim] 2008-02-26 16:48:35 1JTuY0-00081q-7u => 메일주소 R=removingspam T=spam_delivery
Feb 26 16:48:44 [exim] 2008-02-26 16:48:44 1JQWAs-0002po-CR => 메일주소 R=bogofilter T=bogofilter
Feb 26 16:48:45 [exim] 2008-02-26 16:48:45 1JTuY5-000826-EK => 메일주소 R=removingspam T=spam_delivery

유심해서 봐야할건 R=, T= 다음에 나오는 것들이다. R= 다음에 나오는 것은 사용된 router 를 의미하고, T= 다음에 나오는건 transport 를 의미한다. 위의 로그를 보면 bogofilter 를 수행한 뒤 removingspam router 를 이용해서 spam_delivery trasport 가 수행되기도 하고 혹은 이를 통과해서 procmail transport 가 수행되기도 하는 걸 확인할 수 있다.
기본으로는 procmail transport 가 없으니 원랜 local_delivery 가 나올 수도 있겠고 뭐 하여튼 router 나 transport 이름은 사용자가 맘대로 지으면 되는거라 상황에 따라 다 다를 듯…
스팸 없는 세상이 올 때까지 ㅠ.ㅠ 오늘도 삽질…

요 며칠 삽질기 -_-! with Exim

어째 요새 관리해야할 서버가 늘어버렸네요. (전 언픽스 하나로 족한데 ㅠ.ㅠ) 하여튼!! 요 며칠 사이 gentoo + exim + procmail + spf + srs + clamav + bogofilter + dovecot 를 시도해봤습니다.

사실 계속 제가 맡아서 할 게 아니라 길어야 일 년 정도 만져줄 서버기 때문에 젠투가 아닌 다른 배포판을 생각했었는데, spf 와 srs 를 지원할 수 있도록 하면서 기본으로 제공되는 패키지를 이용할 수 있는 조합이 몇 가지 되질 않더군요. exim 에서 spf 와 srs 는 experimental 로 되어 있기 때문에 바이너리 배포판에선 기본으로 적용이 되어 있질 않고, postfix + milter 조합에서는 srs 를 제공할 수 없기 때문에 남은 선택은 sendmail + milter 조합 밖에 없는데 sendmail 을 사용하기는 싫었거든요.

하여튼! exim 에 procmail 을 붙이는 방법은 아래와 같습니다.

Continue reading 요 며칠 삽질기 -_-! with Exim

오묘한 procmail 세상…

마이크로 소프트웨어 1월호를 읽던 중 spam 관련된 기사가 몇 개 실렸길래 재밌게 읽어봤습니다. 불량단어 목록을 외부로 빼서 필터링하는 기법이 소개되었더군요. 웹을 통한 관리까지는 도입할 생각이 없지만, 단어 목록을 외부로 빼면 좀 더 관리가 편해질 듯 하더군요.
뭐 하튼 이래저래 해서 오랫만에 procmail 로 구글링을 해봤습니다. 그러다가 맘에 드는 procmail rule 관련 사이트를 찾아냈습니다!
Continue reading 오묘한 procmail 세상…

유용한 procmail 용 rule!!

procmail 관련 해서 검색을 하던 중 아래와 같은 글을 발견했다. 내 스팸 함에 들어있는 메일들과 정상적인 메일들을 대강 훑어보았더니 저 룰만 가지고도 꽤 많은 스팸을 차단 할 수 있겠다는 생각이 들었다.
http://www.itinside.net/tips/045.html
multipart/alternative 방식은 text/plain 과 text/html 이 두 가지를 모두 가지고 있는 방식인데, 스팸 메일러에서 multipart/alternative 라고 선언을 해놓고 text/plain 혹은 text/html 둘 중 한 가지 만을 가지는 요상한 메일들을 보내는 경우가 많다는 점을 이용하는 것! 정상적인 mta 를 사용해서 보낼 경우 저런 잘못된 형식의 메일은 존재하지 않을 것이기 때문에 그냥 스팸이라고 간주해도 문제가 없을 것 같다.
(둘 중 하나만 집어 넣을거면 처음부터 text/plain, text/html 로 해서 보내면 된다. 첨부파일이 있다면 multipart/alternative 가 아닌 multipart/mixed 를 사용해야 하고…)
바로 적용시켜놔봤는데 결과가 어떨지는 자고 일어나 보면 알 수 있지 않을지 😉
p.s) 원본 사이트가 없어져서 rule 을 quote 해놓습니다. 링크도 webarchive 쪽으로…

# This anti-fake method is to detect the format is incorrect.
:0 HB
* ^Content-Type: *multipart/alternative
* !^Content-Type: *text/plain
{
LOG = “[Fake] ”
:0
/dev/null
}
:0 EHB
* ^Content-Type: *multipart/alternative
* !^Content-Type: *text/html
{
LOG = “[Fake] ”
:0
/dev/null
}