作者 主題: Postfix, Amavisd-new, SpamAssassin, Razor, DCC  (閱讀 42692 次)

0 會員 與 1 訪客 正在閱讀本文。

twu2

  • 管理員
  • 俺是博士!
  • *****
  • 文章數: 5392
  • 性別: 男
    • 檢視個人資料
    • http://blog.teatime.com.tw/1
最近 spam 收了一堆, 老闆一直問有沒有辦法 (他們以前用 exchange server 時並沒有這麼多, 不清楚美國那邊的公司有用什麼軟體擋...), 所以就想把 spamassassin 裝上來用.

這東西的中文說明還真的看不到, 不過有找到一篇英文說明寫的不錯, 除了 OS 用的不一樣外, 其他的東西跟我們用的都一樣.

unix-like 的 OS 有個好處, 同樣的軟體在不同的 OS 上設定都大同小異. 所以同樣的東西要裝在 linux 上面也不是什麼問題. :-)

Fairly-Secure Anti-SPAM Gateway Using OpenBSD, Postfix, Amavisd-new, SpamAssassin, Razor and DCC
http://lawmonkey.org/anti-spam.html

twu2

  • 管理員
  • 俺是博士!
  • *****
  • 文章數: 5392
  • 性別: 男
    • 檢視個人資料
    • http://blog.teatime.com.tw/1
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #1 於: 2003-05-11 12:18 »
自己再來推一下...  :P

前幾天把這整個方案在 Debian 中裝了起來, 除了 chroot 的地方沒有做之外, 其他的功能是很正常的運作, 看起來多數的廣告信都可以攔到, 誤判的情形好像也很少 (我自己是還沒看到過).

文章中提到的信件如果是 spam, 但沒有被偵測到, 而進入你的信箱中, 可以將信再 redirect 到 spam@xxx.com 的信箱, 反之則到  notspam@xxx.com, 讓系統可以由這些信件學習新的 rule 來使用.

不過... 這個 redirect 的功能並不是每一個 mail client 都有, 且我們用的 openwebmail 上面也沒有這個功能. 所以為了方便起見, 我們改用幾乎每個 client 都應該有的 forward as attach 功能.

然後用 php 寫了兩個小程式, 先將 spam@xxx.com, notspam@xxx.com 的信件用 alias 的方式 pipe 到一個收信的程式, 然後再用另一個程式取出信件的  attachment, 再送到真的要分析的信件中. 再改原文中的 my-sa-learn 到真的信箱去檢查.

config.inc.php 設定檔
代碼: [選擇]

<?php

// root path
$root_path "/var/spool/spamfwd/";

// domain
$mydomain "xxx.com";

// smtp server
$smtp_server "localhost";

// smtp port
$smtp_port 10025;

?>



functions.php 一些 functions...
代碼: [選擇]

<?php

require_once "config.inc.php";

function 
writelog&#40;$buf&#41;
&#123;
  
global $root_path;

  
$file $root_path "log/" "gm_" strftime&#40;"%Y%m%d"&#41; . ".log";
  
$fp fopen&#40;$file, "at"&#41;;
  
if &#40;$fp != 0&#41; &#123;
    
$msg sprintf&#40;"%s [%d&#93; %s\n", strftime&#40;"%T"&#41;, getmypid&#40;&#41;, $buf&#41;;
    
fputs&#40;$fp, $msg&#41;;
    
fclose&#40;$fp&#41;;
  
&#125;
  
return;
&
#125;

function chop_newline&#40;$str&#41;
&#123;
  
return chop&#40;preg_replace&#40;"&#40;\r\n|\n|\r&#41;", "", $str&#41;&#41;;
&#125;

function allow_sender&#40;$sender&#41;
&#123;
  
if &#40;allow_user&#40;$sender&#41;&#41; return true;
  
$domain substr&#40;strstr&#40;$sender, "@"&#41;,1&#41;;
  
if &#40;allow_domain&#40;$domain&#41;&#41; return true;
  
return false;
&
#125;

function allow_user&#40;$sender&#41;
&#123;
  
global $root_path;

  
$fp fopen&#40;$root_path . "allow_user", "rt"&#41;;
  
if &#40;$fp == 0&#41; return false; 
  
while &#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;$buf == "*" || $buf == $sender&#41; &#123;
      
fclose&#40;$fp&#41;;
      
return true;
    &
#125;
  
&#125;
  
fclose&#40;$fp&#41;;
  
return false;
&
#125;

function allow_domain&#40;$domain&#41;
&#123;
  
global $root_path;

  
$fp fopen&#40;$root_path . "allow_domain", "rt"&#41;;
  
if &#40;$fp == 0&#41; return false;
  
while &#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$buf "/" chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41; . "/i";
    
if &#40;$buf == "//i"&#41; continue;
    
if &#40;$buf == "/*/i" || preg_match&#40;$buf, $domain&#41;&#41; &#123;
      
fclose&#40;$fp&#41;;
      
return true;
    &
#125;
  
&#125;
  
fclose&#40;$fp&#41;;
  
return false;
&
#125;

function move_error_msg&#40;$file&#41;
&#123;
  
global $root_path;

  
$old_file $root_path "incoming/" $file;
  
$new_file $root_path "errors/" $file sprintf&#40;".%d", getmypid&#40;&#41;&#41;; 
  
rename&#40;$old_file, $new_file&#41;;
  
unlink&#40;$old_file&#41;;
&#125;

?>



spam_recv.php 收信的程式
代碼: [選擇]

#!/usr/bin/php4 -Cq
<?php

require_once "config.inc.php";
require_once 
"functions.php";

$program basename&#40;array_shift&#40;$argv&#41;&#41;;
$user_name array_shift&#40;$argv&#41;;

if &#40;$user_name == ""&#41; &#123;
  
writelog&#40;"no user name!"&#41;;
  
exit&#40;0&#41;;
&#125;

if &#40;posix_getpwnam&#40;$user_name&#41; == 0&#41; &#123;
  
writelog&#40;"User $uid not exist!"&#41;;
  
exit&#40;0&#41;;
&#125;

$incoming_path $root_path "incoming/";
$file_leader sprintf&#40;"spam.%d.", getmypid&#40;&#41;&#41;;

$tempFile tempnam&#40;$incoming_path, $file_leader&#41;;
$fout fopen&#40;$tempFile, "wt"&#41;;
if &#40;$fout == 0&#41; &#123;
  
writelog&#40;"Can't open temp file&#58; " . $tempFile&#41;;
  
exit&#40;0&#41;;
&#125;

fputs&#40;$fout, $user_name . "\n"&#41;;

$fp fopen&#40;"php&#58;//stdin", "rt"&#41;;
if &#40;$fp == 0&#41; &#123;
  
writelog&#40;"Can't open stdin"&#41;;
  
fclose&#40;$fout&#41;;
  
unlink&#40;$tempFile&#41;;
  
exit&#40;0&#41;;
&#125;

while &#40;feof&#40;$fp&#41; == 0&#41; &#123;
  
$buf fgets&#40;$fp, 4096&#41;;
  
fputs&#40;$fout, $buf&#41;;
&#125;
fclose&#40;$fp&#41;;
fclose&#40;$fout&#41;;

chmod&#40;$tempFile, 0660&#41;;
writelog&#40;sprintf&#40;"&#40;%s&#41; incoming %s", $user_name, basename&#40;$tempFile&#41;&#41;&#41;;

exit&#40;0&#41;;

?>



spam_send.php 取出 attachment 再送出的程式
代碼: [選擇]

#!/usr/bin/php4 -Cq
<?php

require_once "config.inc.php";
require_once 
"functions.php";

error_reporting&#40;0&#41;;

$dir $root_path "incoming/";

if &
#40;$dh = opendir&#40;$dir&#41;&#41; &#123;
  
while &#40;&#40;$file = readdir&#40;$dh&#41;&#41; != false&#41; &#123;
    
if &#40;is_file&#40;$dir . $file&#41;&#41; &#123;
      
if &#40;&#40;fileperms&#40;$dir . $file&#41; & 0660&#41; == 0660&#41; &#123;
        
process_file&#40;$dir . $file&#41;;
      
&#125;
    
&#125;
  
&#125;
  
closedir&#40;$dh&#41;; 
&#125;

exit;

function 
process_file&#40;$file&#41;
&#123;
  
global $root_path;
  global 
$smtp_server;
  global 
$smtp_port;
  global 
$mydomain;

  
$total filesize&#40;$file&#41;;

  
$fp fopen&#40;$file, "rt"&#41;;
  
if &#40;$fp == 0&#41; &#123;
    
writelog&#40;"can't open file&#58; " . $file&#41;;
    
return 0;
  &
#125;
  
if &#40;flock&#40;$fp, LOCK_EX + LOCK_NB&#41; == false&#41; &#123;
    
fclose&#40;$fp&#41;;
    
return 0;
  &
#125;;

  // user name
  
$user_name chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;

  
writelog&#40;sprintf&#40;"&#40;%s&#41; processing %s", $user_name, basename&#40;$file&#41;&#41;&#41;;

  
$boundary "";
  while &
#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;$buf == ""&#41; break;
    
if &#40;strncasecmp&#40;$buf, "Content-Type&#58; ", 14&#41; == 0&#41; &#123;
      
while &#40;1&#41; &#123;
        
$p stristr&#40;$buf, "boundary=\""&#41;;
        
if &#40;$p == ""&#41; &#123;
          
if &#40;feof&#40;$fp&#41;&#41; break;
          
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
          
$ch $buf[0&#93;;
          
if &#40;$ch == ' ' || $ch == '\t'&#41; continue;
          
break;
        &
#125;
        
$i 0;
        while &
#40;1&#41; &#123;
          
$ch $p[10 $i&#93;;
          
if &#40;$ch == ""&#41; break;
          
if &#40;$ch == '"'&#41; break;
          
$i++;
        &
#125;
        
$boundary substr&#40;$p, 10, $i&#41;;
        
break;
      &
#125;
      
break;
    &
#125;
  
&#125;

  
if &#40;$boundary == ""&#41; &#123;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; boundary not found!", $user_name&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
move_error_msg&#40;basename&#40;$file&#41;&#41;;
    
return 0;
  &
#125;

  
$found 0;
  
$match "--$boundary";
  while &
#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;$buf != $match&#41; continue;
    
while &#40;feof&#40;$fp&#41; == false&#41; &#123;
      
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
      
if &#40;$buf == ""&#41; break;
      
if &#40;strncasecmp&#40;$buf, "Content-Type&#58; message/rfc822", 28&#41; == 0&#41; &#123;
        
$found 1;
        break;
      &
#125;
    
&#125;
    
if &#40;$found == 1&#41; break;
  
&#125;

  
if &#40;$found == 0&#41; &#123;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; no boundary with type message/rfc822!", $user_name&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
move_error_msg&#40;basename&#40;$file&#41;&#41;;
    
return 0;
  &
#125;

  // return-path
  
$found 0;
  while &
#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$pos ftell&#40;$fp&#41;;
    
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;strncasecmp&#40;$buf, "Return-Path&#58; ", 13&#41; == 0&#41; &#123;
      
$found 1;
      break;
    &
#125;
  
&#125;

  
if &#40;$found == 0&#41; &#123;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; no Return-Path&#58; found!", $user_name&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
move_error_msg&#40;basename&#40;$file&#41;&#41;;
    
return 0;
  &
#125;

  
$sender ereg_replace&#40;"<|>", "", substr&#40;$buf, 13&#41;&#41;;
  
  
fseek&#40;$fp, $pos, SEEK_SET&#41;;

  
$smtp fsockopen&#40;$smtp_server, $smtp_port, $errno, $errstr, 30&#41;;
  
if &#40;$smtp == 0&#41; &#123;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; connect to %s&#58;%d failed&#58; &#40;%d&#41; %s", $user_name,
$smtp_server$smtp_port,
$errno$errstr&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
return 0;
  &
#125;

  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "220"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;220&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
fputs&#40;$smtp, "HELO " . $mydomain . "\n"&#41;;
  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "250"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;250&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
fputs&#40;$smtp, "MAIL FROM&#58;<" . $sender . ">\n"&#41;;
  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "250"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;250&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
fputs&#40;$smtp, "RCPT TO&#58;<" . $user_name . "@" . $mydomain . ">\n"&#41;;
  // server response
  
$ok 1;
  while &
#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "250"&#41; &#123;
      
$ok 0;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;250&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
    
&#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
if &#40;$ok == 0&#41; &#123;
    
fputs&#40;$smtp, "QUIT\n"&#41;;
    
fclose&#40;$smtp&#41;;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; RCPT TO&#58; reject!", $user_name&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
move_error_msg&#40;basename&#40;$file&#41;&#41;;
    
return 0;
  &
#125;

  
fputs&#40;$smtp, "DATA\n"&#41;;
  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "354"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;354&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
$match "--$boundary";
  
$match_end "--$boundary"--";
  while &
#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$msg chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;$msg == $match&#41; break;
    
if &#40;$msg == $match_end&#41; break;
    
if &#40;$msg == "."&#41;
      
fputs&#40;$smtp, "..\n"&#41;;
    
else
      
fputs&#40;$smtp, "$msg\n"&#41;;
  
&#125;

  
fputs&#40;$smtp, ".\n"&#41;;
  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "250"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;250&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
fputs&#40;$smtp, "QUIT\n"&#41;;
  
fclose&#40;$smtp&#41;;

  
flock&#40;$fp, LOCK_UN&#41;;
  
fclose&#40;$fp&#41;;
  
unlink&#40;$file&#41;;

  
writelog&#40;sprintf&#40;"&#40;%s&#41; post from %s, size=%d, member=%d",
               
$user_name$sender$total$cnt&#41;&#41;;
  
return 1;
&
#125;

?>



然後在 /etc/aliases 中加上

# spam
spam: "|/var/spool/spamfwd/spam_recv.php to.spam"
notspam: "|/var/spool/spamfwd/spam_recv.php to.notspam"

將給 spam, notspam 的信都轉到 spam_recv.php 來處理.

然後在 cron 中固定時間去執行 spam_send.php.

這樣子送到 to.spam, to.notspam 這兩個信箱的信件就是我們要的了.

PS1. 原文中的程式, 除了 DCC 之外, 都可以在 Debian 中找到, 只是有些不在 stable 版本中, 可以自己抓  source 回來做一份 .deb 給 stable 版本使用.

PS2. 中文的廣告信, 我們這兒原本就很少收到, 所以不知道效果如何.

PS3. 順便提一下 Debian 的好處, 原本我們想改用 RedHat 來做, 但是... 相關的 rpm 實在很少, 自己要裝一堆東西, 原本在 debian 中, 都只要用用 apt 就可以找到的東西, 在 RedHat 中要找半天...:-(  後來決定還是回到 Debian 上來用比較快一些. :-)

zxcvbn101

  • 懷疑的國中生
  • **
  • 文章數: 70
    • 檢視個人資料
HELP: boundary not found
« 回覆 #2 於: 2003-10-09 15:06 »
謝謝您的程式,解決了使用outlook的痛苦,
但有一個問題想麻煩您:
信件中明明含有boundary這一段,如下

Content-Type: multipart/mixed;
        boundary="----=_NextPart_000_0011_01C38E6B.615A2B50"


Content-Type: multipart/mixed;
        boundary="----=OPENWEBMAIL_ATT_0.0983100150051577"

可是在執行spam_send.php後log的訊息停在 boundary not found
不知有何解決方法,謝謝

twu2

  • 管理員
  • 俺是博士!
  • *****
  • 文章數: 5392
  • 性別: 男
    • 檢視個人資料
    • http://blog.teatime.com.tw/1
Re: HELP: boundary not found
« 回覆 #3 於: 2003-10-09 15:14 »
引述: "zxcvbn101"
謝謝您的程式,解決了使用outlook的痛苦,
但有一個問題想麻煩您:
信件中明明含有boundary這一段,如下

Content-Type: multipart/mixed;
        boundary="----=_NextPart_000_0011_01C38E6B.615A2B50"


Content-Type: multipart/mixed;
        boundary="----=OPENWEBMAIL_ATT_0.0983100150051577"

可是在執行spam_send.php後log的訊息停在 boundary not found
不知有何解決方法,謝謝


這個問題, 後來有改過程式. 試試看這個版本吧.

代碼: [選擇]
#!/usr/bin/php4 -Cq
<?php

require_once dirname&#40;$argv[0&#93;&#41; . "/config.inc.php";
require_once dirname&#40;$argv[0&#93;&#41; . "/functions.php";

error_reporting&#40;0&#41;;

$dir $root_path "incoming/";

if &
#40;$dh = opendir&#40;$dir&#41;&#41; &#123;
  
while &#40;&#40;$file = readdir&#40;$dh&#41;&#41; != false&#41; &#123;
    
if &#40;is_file&#40;$dir . $file&#41;&#41; &#123;
      
if &#40;&#40;fileperms&#40;$dir . $file&#41; & 0660&#41; == 0660&#41; &#123;
        
process_file&#40;$dir . $file&#41;;
      
&#125;
    
&#125;
  
&#125;
  
closedir&#40;$dh&#41;; 
&#125;

exit;

function 
process_file&#40;$file&#41;
&#123;
  
global $root_path;
  global 
$smtp_server;
  global 
$smtp_port;
  global 
$mydomain;

  
$total filesize&#40;$file&#41;;

  
$fp fopen&#40;$file, "rt"&#41;;
  
if &#40;$fp == 0&#41; &#123;
    
writelog&#40;"can't open file&#58; " . $file&#41;;
    
return 0;
  &
#125;
  
if &#40;flock&#40;$fp, LOCK_EX + LOCK_NB&#41; == false&#41; &#123;
    
fclose&#40;$fp&#41;;
    
return 0;
  &
#125;;

  // user name
  
$user_name chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;

  
writelog&#40;sprintf&#40;"&#40;%s&#41; processing %s", $user_name, basename&#40;$file&#41;&#41;&#41;;

  
$boundary "";
  while &
#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;$buf == ""&#41; break;
    
if &#40;strncasecmp&#40;$buf, "Content-Type&#58; ", 14&#41; == 0&#41; &#123;
      
while &#40;1&#41; &#123;
        
$p stristr&#40;$buf, "boundary=\""&#41;;
        
if &#40;$p == ""&#41; &#123;
          
if &#40;feof&#40;$fp&#41;&#41; break;
          
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
          
$ch $buf[0&#93;;
          
if &#40;$ch == 0 || $ch == ' ' || $ch == '\t'&#41; continue;
          
break;
        &
#125;
        
$i 0;
        while &
#40;1&#41; &#123;
          
$ch $p[10 $i&#93;;
          
if &#40;$ch == ""&#41; break;
          
if &#40;$ch == '"'&#41; break;
          
$i++;
        &
#125;
        
$boundary substr&#40;$p, 10, $i&#41;;
        
break;
      &
#125;
      
break;
    &
#125;
  
&#125;

  
if &#40;$boundary == ""&#41; &#123;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; boundary not found!", $user_name&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
move_error_msg&#40;basename&#40;$file&#41;&#41;;
    
return 0;
  &
#125;

  
$found 0;
  
$match "--$boundary";
  while &
#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;$buf != $match&#41; continue;
    
while &#40;feof&#40;$fp&#41; == false&#41; &#123;
      
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
      
if &#40;$buf == ""&#41; break;
      
if &#40;strncasecmp&#40;$buf, "Content-Type&#58; message/rfc822", 28&#41; == 0&#41; &#123;
        
$found 1;
        break;
      &
#125;
    
&#125;
    
if &#40;$found == 1&#41; break;
  
&#125;

  
if &#40;$found == 0&#41; &#123;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; no boundary with type message/rfc822!", $user_name&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
move_error_msg&#40;basename&#40;$file&#41;&#41;;
    
return 0;
  &
#125;

  // return-path
  
$found 0;
  while &
#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$pos ftell&#40;$fp&#41;;
    
$buf chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;strncasecmp&#40;$buf, "Return-Path&#58; ", 13&#41; == 0&#41; &#123;
      
$found 1;
      break;
    &
#125;
  
&#125;

  
if &#40;$found == 0&#41; &#123;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; no Return-Path&#58; found!", $user_name&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
move_error_msg&#40;basename&#40;$file&#41;&#41;;
    
return 0;
  &
#125;

  
$sender ereg_replace&#40;"<|>", "", substr&#40;$buf, 13&#41;&#41;;
  
  
fseek&#40;$fp, $pos, SEEK_SET&#41;;

  
$smtp fsockopen&#40;$smtp_server, $smtp_port, $errno, $errstr, 30&#41;;
  
if &#40;$smtp == 0&#41; &#123;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; connect to %s&#58;%d failed&#58; &#40;%d&#41; %s", $user_name,
$smtp_server$smtp_port,
$errno$errstr&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
return 0;
  &
#125;

  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "220"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;220&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
fputs&#40;$smtp, "HELO " . $mydomain . "\n"&#41;;
  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "250"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;250&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
fputs&#40;$smtp, "MAIL FROM&#58;<" . $sender . ">\n"&#41;;
  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "250"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;250&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
fputs&#40;$smtp, "RCPT TO&#58;<" . $user_name . "@" . $mydomain . ">\n"&#41;;
  // server response
  
$ok 1;
  while &
#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "250"&#41; &#123;
      
$ok 0;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;250&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
    
&#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
if &#40;$ok == 0&#41; &#123;
    
fputs&#40;$smtp, "QUIT\n"&#41;;
    
fclose&#40;$smtp&#41;;
    
writelog&#40;sprintf&#40;"&#40;%s&#41; RCPT TO&#58; reject!", $user_name&#41;&#41;;
    
flock&#40;$fp, LOCK_UN&#41;;
    
fclose&#40;$fp&#41;;
    
move_error_msg&#40;basename&#40;$file&#41;&#41;;
    
return 0;
  &
#125;

  
fputs&#40;$smtp, "DATA\n"&#41;;
  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "354"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;354&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
$match "--$boundary";
  
$match_end "--$boundary"--";
  while &
#40;feof&#40;$fp&#41; == false&#41; &#123;
    
$msg chop_newline&#40;fgets&#40;$fp, 4096&#41;&#41;;
    
if &#40;$msg == $match&#41; break;
    
if &#40;$msg == $match_end&#41; break;
    
if &#40;$msg == "."&#41;
      
fputs&#40;$smtp, "..\n"&#41;;
    
else
      
fputs&#40;$smtp, "$msg\n"&#41;;
  
&#125;

  
fputs&#40;$smtp, ".\n"&#41;;
  // server response
  
while &#40;1&#41; &#123;
    
$msg fgets&#40;$smtp, 256&#41;;
    
if &#40;substr&#40;$msg, 0, 3&#41; != "250"&#41; &#123;
      
writelog&#40;sprintf&#40;"&#40;%s&#41; error &#40;250&#41;&#58; %s", $user_name, chop_newline&#40;$msg&#41;&#41;&#41;;
      
fclose&#40;$smtp&#41;;
      
flock&#40;$fp, LOCK_UN&#41;;
      
fclose&#40;$fp&#41;;
      
return 0;
    &
#125;
    
if &#40;substr&#40;$msg, 3, 1&#41; != "-"&#41; break;
    // multi-line response
  
&#125;

  
fputs&#40;$smtp, "QUIT\n"&#41;;
  
fclose&#40;$smtp&#41;;

  
flock&#40;$fp, LOCK_UN&#41;;
  
fclose&#40;$fp&#41;;
  
unlink&#40;$file&#41;;

  
writelog&#40;sprintf&#40;"&#40;%s&#41; post from %s, size=%d",
               
$user_name$sender$total&#41;&#41;;
  
return 1;
&
#125;

?>


zxcvbn101

  • 懷疑的國中生
  • **
  • 文章數: 70
    • 檢視個人資料
謝謝您
« 回覆 #4 於: 2003-10-09 15:57 »
您提供一個非常好的解決方案,不用outlook(2002之前的版本 and express)的人,可以直接redirect到spam信箱,用openwebmail或outlook則可以轉寄到aliases!在網路上找了好幾天,除了那個redirect for outlook add-in之外,好像都沒有比較好的解決方式,沒參考到這篇文章的網友,真是太可惜了。

對了,我曾在英文網站上看到類似 mailto: spam@xxx.com with att in html的東西,我想如果能在subject 或內容中塞入像yahoo e-mail的LINK(這是廣告信),user只要一按,就可以將信送到spam信箱,這樣就更完美了!不知您有無解決方法?好像太貪心了一點,anyway, thanks a lot!

梁楓

  • 俺是博士!
  • *****
  • 文章數: 6220
    • 檢視個人資料
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #5 於: 2003-10-09 17:40 »
spamassassin 我也很喜歡
不過因為怕誤判就不敢用...

twu2兄在SPAM-FLAG 幾個*的時候會ban掉信?

twu2

  • 管理員
  • 俺是博士!
  • *****
  • 文章數: 5392
  • 性別: 男
    • 檢視個人資料
    • http://blog.teatime.com.tw/1
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #6 於: 2003-10-09 18:15 »
引述: "梁楓"
spamassassin 我也很喜歡
不過因為怕誤判就不敢用...

twu2兄在SPAM-FLAG 幾個*的時候會ban掉信?


和上面的文章設定一樣. 超過 6.3 就不收進來.
剛開始當然不會馬上就擋, 只是 subject 加個記號, 然後看看那些不符合的條件就修改...

應該一兩個月後就很少誤判了.

a6530466

  • 可愛的小學生
  • *
  • 文章數: 7
    • 檢視個人資料
    • http://a6530466.idv.st/
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #7 於: 2004-06-10 15:36 »

garry

  • 可愛的小學生
  • *
  • 文章數: 2
    • 檢視個人資料
請問, 執行 spam_send.php 有問題
« 回覆 #8 於: 2004-07-01 09:44 »
請問,  因為我沒有 php4 所以把程式開頭的
#!/usr/bin/php4 -Cq 改成 #!/usr/bin/php -Cq 了 ,
寄信進 spam 帳號時執行 spam_recv.php 好像沒問題 , 信有到 incoming 裡,
但是執行 spam_send.php 卻好像什麼事也沒發生 , incoming 裡的信也還在 ,
後來發現問題是出在下面這幾行
  if (flock($fp, LOCK_EX + LOCK_NB) == false) {
    fclose($fp);
    return 0;
  };
程式沒辦法把檔案Lock, 結果就跳出去了, 請問該如何解阿.

Jesse_Liao

  • 可愛的小學生
  • *
  • 文章數: 22
    • 檢視個人資料
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #9 於: 2004-07-02 16:41 »
看到這個這麼棒的功能後,好想也在我的系統上試一試....
可是架構上,我的anti-spam 是一台純粹的Gateway 而已 ...
怎麼辦 ?

twu2

  • 管理員
  • 俺是博士!
  • *****
  • 文章數: 5392
  • 性別: 男
    • 檢視個人資料
    • http://blog.teatime.com.tw/1
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #10 於: 2004-07-02 17:42 »
引述: "Jesse_Liao"
看到這個這麼棒的功能後,好想也在我的系統上試一試....
可是架構上,我的anti-spam 是一台純粹的Gateway 而已 ...
怎麼辦 ?


你確定看過上面連結的文章了嗎? 那文章就是說明怎麼做一個 anti-spam 的 gateway.

usa

  • 憂鬱的高中生
  • ***
  • 文章數: 111
    • 檢視個人資料
    • http://www.ipnt.org
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #11 於: 2004-07-29 22:24 »
請問學長,
在 /var/spool/spamfwd/log/ 的 log 檔裡看到如下的錯誤訊息, 但 maillog 的訊息是沒有錯誤的, temp file 在哪呢? 哪裡要設定嗎?

代碼: [選擇]
22:14:52 [37661] Can't open temp file:

twu2

  • 管理員
  • 俺是博士!
  • *****
  • 文章數: 5392
  • 性別: 男
    • 檢視個人資料
    • http://blog.teatime.com.tw/1
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #12 於: 2004-07-29 23:06 »
引述: "usa"
請問學長,
在 /var/spool/spamfwd/log/ 的 log 檔裡看到如下的錯誤訊息, 但 maillog 的訊息是沒有錯誤的, temp file 在哪呢? 哪裡要設定嗎?

代碼: [選擇]
22:14:52 [37661] Can't open temp file:


檢查一下 /var/spool/spamfwd 下面是否有 incoming, log, errors, spool 等目錄.
然後看看這些目錄的權限, 你執行 spam_recv.php 的使用者必需要有寫入的權限.

usa

  • 憂鬱的高中生
  • ***
  • 文章數: 111
    • 檢視個人資料
    • http://www.ipnt.org
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #13 於: 2004-07-30 20:00 »
學長,
這些目錄都有, 權限也都是 777
但錯誤依然存在, 是否還注意哪些地方呢

usa

  • 憂鬱的高中生
  • ***
  • 文章數: 111
    • 檢視個人資料
    • http://www.ipnt.org
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #14 於: 2004-07-31 15:49 »
還有一個問題, 就是執行 sa-learn 時會有如下的錯誤訊息  :cry:
代碼: [選擇]
Cannot open bayes databases /usr/local/etc/mail/.spamassassin/bayes_* R/O: tie failed: Inappropriate file type or format
Cannot open bayes databases /usr/local/etc/mail/.spamassassin/bayes_* R/W: tie failed: Inappropriate file type or format

cw_3388

  • 可愛的小學生
  • *
  • 文章數: 15
    • 檢視個人資料
[問題]
« 回覆 #15 於: 2004-09-03 22:25 »
然後用 php 寫了兩個小程式, 先將 spam@xxx.com, notspam@xxx.com 的信件用 alias 的方式 pipe 到一個收信的程式, 然後再用另一個程式取出信件的 attachment, 再送到真的要分析的信件中. 再改原文中的 my-sa-learn 到真的信箱去檢查.


然後在 /etc/aliases 中加上

# spam
spam: "|/var/spool/spamfwd/spam_recv.php to.spam"
notspam: "|/var/spool/spamfwd/spam_recv.php to.notspam"

將給 spam, notspam 的信都轉到 spam_recv.php 來處理.



我的server是用postfix+amavisd-new+spamassassin+sophie,spamassassin的設定也是照上面說的這樣來設,但是我將判為spam的信以附檔寄到spam這個信箱的時候,會出現以下的錯誤訊息:(信被退回來)

  The Postfix program

<spam@xxx.xxx.tw>: Command died with status 1:
   "/var/spool/spamfwd/spam_recv.php realspam"

Final-Recipient: rfc822; spam@xxx.xxx.tw
Action: failed
Status: 5.0.0
Diagnostic-Code: X-Postfix; Command died with status 1:
   "/var/spool/spamfwd/spam_recv.php realspam"

請問一下,sa-learn的部份還要改那個地方嗎?還是那個部份沒有注意到呢?
謝謝大家的幫忙 :D

ntntnt

  • 懷疑的國中生
  • **
  • 文章數: 32
    • 檢視個人資料
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #16 於: 2004-11-04 11:19 »
感謝大大post這麼好的一篇文章
請教各位大大這一篇應該是針對postfix
請教如果是sendmail的話應該修改哪一個地方??
小弟是使用sendmail8.9版的
再使用aliases時就出現了
   ----- The following addresses had permanent fatal errors -----
"|/var/spool/spamfwd/spam_recv.php realspam"
    (reason: service unavailable)
    (expanded from: <spam@partner.com.tw>)

   ----- Transcript of session follows -----
smrsh: spam_recv.php not available for sendmail programs (stat failed)
554 5.0.0 Service unavailable
這個錯誤訊息
感謝大大的解答

shadow

  • 活潑的大學生
  • ***
  • 文章數: 365
    • 檢視個人資料
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #17 於: 2006-08-21 18:30 »
真是不好意思
把這麼久的文章還挖出來

不知道有沒有人現在還在試這個程式
小弟今天去抓回來使用
發現幾個問題
1. 在 freebsd 要把 php 的路徑改一下才行
2. send_recv.php 裡把下列程式 mark 起來
不然沒辦法執行
代碼: [選擇]

if (posix_getpwnam($user_name) == 0) {
writelog("User $uid not exist!");
exit(0);
}

我只會到這裡
再接下去完全沒辦法了
不知道有沒有人知道哪裡有更新版的程式可以用

我的系統是:
FreeBSD 6.1
php 4.4.3

shadow

  • 活潑的大學生
  • ***
  • 文章數: 365
    • 檢視個人資料
Postfix, Amavisd-new, SpamAssassin, Razor, DCC
« 回覆 #18 於: 2006-08-22 15:35 »
引述: "shadow"
真是不好意思
把這麼久的文章還挖出來

不知道有沒有人現在還在試這個程式
小弟今天去抓回來使用
發現幾個問題
1. 在 freebsd 要把 php 的路徑改一下才行
2. send_recv.php 裡把下列程式 mark 起來
不然沒辦法執行
代碼: [選擇]

if (posix_getpwnam($user_name) == 0) {
writelog("User $uid not exist!");
exit(0);
}

我只會到這裡
再接下去完全沒辦法了
不知道有沒有人知道哪裡有更新版的程式可以用

我的系統是:
FreeBSD 6.1
php 4.4.3


今天設定好
系統會自動學習了
YA!!