?? qmail-smtpd.c
字號:
// qmail-smtpd接受遠程主機的郵件并轉交給隊列處理程序qmail-queue來處理
// 由tcp-env.c啟動,完成郵件smtp命令的接收,并調用相應的處理程序
// 只接收郵件內容(mailfrom,mailto)并傳送給qmail-queue,并不對郵件進行轉發
#include "sig.h"#include "readwrite.h"#include "stralloc.h"#include "substdio.h"#include "alloc.h"#include "auto_qmail.h"#include "control.h"#include "received.h"#include "constmap.h"#include "error.h"#include "ipme.h"#include "ip.h"#include "qmail.h"#include "str.h"#include "fmt.h"#include "scan.h"#include "byte.h"#include "case.h"#include "env.h"#include "now.h"#include "exit.h"#include "rcpthosts.h"#include "timeoutread.h"#include "timeoutwrite.h"#include "commands.h"#define MAXHOPS 100unsigned int databytes = 0; //郵件最大長度:0=無限int timeout = 1200; //默認超時20分鐘
// 向網絡寫,超時值為control/timeoutsmtpd指定的值,沒有這個文件則取默認值20分鐘int safewrite(fd,buf,len) int fd; char *buf; int len;{ int r; r = timeoutwrite(timeout,fd,buf,len); if (r <= 0) _exit(1); return r;}char ssoutbuf[512];substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);void flush() { substdio_flush(&ssout); }
// void out(s) char *s 相當于 void out(char* s)void out(s) char *s; { substdio_puts(&ssout,s); }
// 錯誤處理函數void die_read() { _exit(1); }void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }void err_noop() { out("250 ok\r\n"); }void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }stralloc greeting = {0};//end 錯誤處理函數
// 輸出提示信息*codevoid smtp_greet(code) char *code;{ substdio_puts(&ssout,code); substdio_put(&ssout,greeting.s,greeting.len);}void smtp_help(){ out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n");}void smtp_quit(){ smtp_greet("221 "); out("\r\n"); flush(); _exit(0);}char *remoteip; //遠端ip地址char *remotehost; //遠端主機名char *remoteinfo; //遠端信息char *local; //本地主機char *relayclient; //是否檢查rcpthosts文件stralloc helohost = {0};char *fakehelo; /* pointer into helohost, or 0 */void dohelo(arg) char *arg; { if (!stralloc_copys(&helohost,arg)) die_nomem(); if (!stralloc_0(&helohost)) die_nomem();
//fakehelo變量,如果helo參數指定的主機名與TCPREMOTEHOST環境變量中的主機名不同則
//fakehelo的值為helo命令的參數指定的主機名。如果兩者相同則fekehelo為NULL;
//data命令處理程式用到這個變量 fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;}int liphostok = 0;stralloc liphost = {0};int bmfok = 0;
// badmailfrom 用來指定不喜歡的發見人的郵件地址或者是域名
//該地址給主機發送郵件時將得到code 553,告知其是不受歡迎的發件人stralloc bmf = {0}; struct constmap mapbmf;void setup(){ char *x; unsigned long u; if (control_init() == -1) die_control(); //control/me
//讀入歡迎信息greeting,如果不存在則從me文件復制 if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1) die_control();
//讀入localiphost,如果文件不存在則從me文件復制 liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0); if (liphostok == -1) die_control();
//讀control/timeoutsmtpd存入timeout,用于控制超時的情況 if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control(); if (timeout <= 0) timeout = 1; if (rcpthosts_init() == -1) die_control();
//讀入badmailfrom文件存入bmf bmfok = control_readfile(&bmf,"control/badmailfrom",0); if (bmfok == -1) die_control(); if (bmfok) if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
//讀入databytes文件存入databytes,如果該文件不存在,則將databytes的值設為0. if (control_readint(&databytes,"control/databytes") == -1) die_control(); x = env_get("DATABYTES"); if (x) { scan_ulong(x,&u); databytes = u; } if (!(databytes + 1)) --databytes;
//取tcp-environ環境變量,如果環境變量沒有設置,將它的值設置為unknow
//這些信息在tcp-env文件中 remoteip = env_get("TCPREMOTEIP"); if (!remoteip) remoteip = "unknown"; local = env_get("TCPLOCALHOST"); if (!local) local = env_get("TCPLOCALIP"); if (!local) local = "unknown"; remotehost = env_get("TCPREMOTEHOST"); if (!remotehost) remotehost = "unknown"; remoteinfo = env_get("TCPREMOTEINFO");
//從環境變量RELAYCLIENT讀入,如果RELAYCLIENT變量沒有設置那么relayclient將會是NULL relayclient = env_get("RELAYCLIENT"); dohelo(remotehost);}stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
//對命令參數arg進行郵件地址分析,并將分離出的email地址存入全局緩存addr,成功返回值1,
//失敗返回0int addrparse(arg)char *arg;{ int i; char ch; char terminator; struct ip_address ip; int flagesc; int flagquoted;
//分離出郵件地址,例如:arg="",或arg=": email@eg.org"
//執行下面這段程序后arg="email@eg.org" terminator = '>'; i = str_chr(arg,'<'); if (arg[i]) arg += i + 1; else { /* partner should go read rfc 821 */ terminator = ' '; arg += str_chr(arg,':'); if (*arg == ':') ++arg; while (*arg == ' ') ++arg; } /* strip source route */ if (*arg == '@') while (*arg) if (*arg++ == ':') break; if (!stralloc_copys(&addr,"")) die_nomem(); flagesc = 0; flagquoted = 0; for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */ if (flagesc) { if (!stralloc_append(&addr,&ch)) die_nomem(); flagesc = 0; } else { if (!flagquoted && (ch == terminator)) break; switch(ch) { case '\\': flagesc = 1; break; case '"': flagquoted = !flagquoted; break; default: if (!stralloc_append(&addr,&ch)) die_nomem(); } } } /* could check for termination failure here, but why bother? */ if (!stralloc_append(&addr,"")) die_nomem();
//將ip地址轉換為主機名:
//如test@[10.0.6.21]轉換為test@host.mydomain.org
//依據是control/localiphost文件中有host.mydomain.org if (liphostok) { i = byte_rchr(addr.s,addr.len,'@'); if (i < addr.len) /* if not, partner should go read rfc 821 */ if (addr.s[i + 1] == '[') //比較是否是用[]括起來的ip地址 if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)]) if (ipme_is(&ip)) { addr.len = i + 1; if (!stralloc_cat(&addr,&liphost)) die_nomem(); if (!stralloc_0(&addr)) die_nomem(); } } if (addr.len > 900) return 0; //地址太長,出錯返回 return 1; //成功返回}
//簡單的垃圾郵件檢查,檢查全局緩沖區addr中的地址是否有在badmailfrom中定義,如果
//有則返回1,否則返回0.int bmfcheck(){ int j; if (!bmfok) return 0; if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1; j = byte_rchr(addr.s,addr.len,'@'); if (j < addr.len) if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1; return 0;}
//檢查全局緩存addr中的郵件地址是否要進行轉發(依據control/rcpthosts文件)
//可以進行轉發返回1,拒絕轉發返回0int addrallowed(){ int r;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -