直到去年公司組織結構調整為止,Mail Server 產品的開發都是我們 Team 上的一大業務,其中我接觸較多的是和 Mail Auditing, Security 相關的功能,今天想先和大家分享前者,也算是幫自己做過的功能留下一些文件和筆記。
What is Mail Log?
所謂 Mail Log 或許定義很廣泛,不過在這篇文章中泛指 MTA, MDA 支援郵件相關協議而產生的相應 Log,今天會主要介紹和 Postfix 相關的部分,Log 範例如下:
1 | postfix/smtpd[27616]: connect from unknown[10.17.41.26] |
可以看到 Log 是由 postfix/smtpd
、postfix/cleanup
、postfix/qmgr
、postfix/local
這些 Process 所產生 ,在進一步詳細介紹前,我們可以先參考 Postfix Architecture Overview 大致暸解 Postfix 的架構。
Note: 如果是有良好設置過的 Mail Server,產生的 Log 應該會比上面的範例 Log 多很多,除了 Postfix 內的其他 Process 如 postscreen,還有更多像是 Milter, Policy delegation 的 Extension 用來補足 Postfix 原生沒有提供的功能,未來可能會再進一步介紹其中的 milter。
Postfix: Receive Mail from Network
以下為 Postfix 透過 Network 收到 Mail 的處理流程:
graph LR; Network --> smtpd; smtpd --> cleanup; cleanup -->|"queue"|qmgr; qmgr --> local; local -->|dovecot-lda|Mailbox;
流程圖中各節點的功能如下:
smtpd
: 監聽 SMTP Port 的 Server,接收來自 Client 的請求,依 SMTP Protocol 的不同命令 (如EHLO
,MAIL
,RCPT
,DATA
) 進行相應的處理。cleanup
: 對收到的郵件進行清理和格式化,確保郵件的格式符合 Protocol 的要求,以將其放入郵件佇列等待進一步處理。qmgr
: 管理 Mail Queue 的 Queue Manager,任務如將 Active Queue 中的 Mail 取出,並根據 Mail 的目的地不同進行相應處理 (可能送至本地的local
或透過smtp
轉發至下一個 Server)。local
: 負責 Local Delivery,範例 Log 中透過dovecot-lda
來將 Mail 送至對應 Mailbox。
Note: 流程圖參考官方文件,看起來是單向且獨立的,但就我的理解這邊的意思是在
DATA
Stage 結束時smtpd
會將 Mail 送至cleanup
處理,再送進 Queue。但由於整個 SMTP Session 還沒有結束,smtpd
同時還是會處理 Client 在同一個 Session 中的其他 Command (直到QUIT
)。
Mail Log Interpretation
大致理解上述 Postfix 架構後,我們再回到範例 Log 來逐行進行解讀:
smtpd
接收到連線。- 大致同上,不過多了 Queue ID (4D0897C8AD),這是 Postfix 用來識別 Mail 的 Identifier。
cleanup
正在處理 Mail,可以看到Message-ID
的 Header,相較於 Queue ID 是針對 Postfix Server 內部的 Identifier,Message ID 是對整個 Mail System 的 Identifier,也就是說即使 Mail 在不同 Mail Server 間傳遞也不會改變 (只會在一開始發現還沒有這個 Header 時產生)。qmgr
從 Active Queue 中取出信件進行處理,可以觀察到cleanup
已經完成所以能顯示正確 Mail Size。smtpd
連線結束。- 紀錄
local
的 Mail Delivery Result,這邊透過dovecot-lda
的 Command 配信到信箱。 - 表示 Mail 已處理完畢,
qmgr
將其從 Mail Queue 中移除。
在瞭解 Log 的意義之外,由於 Postfix 同時運行多個 Process,常常會看到多個 Session 的 Log 交錯,在這種情況下要如何追蹤同一個 Session 的 Log 呢?其實主要就是以上面介紹的 Identifier 去串連:
- Queue ID
- Message ID
Issues for Postfix Logging Feature
依照目前為止所介紹到的內容,我們其實已經有能力從 Mail Log 中找到自己想追蹤的 Session 並進行解讀了。不過在流量較大的 Server 中 (Log 也增長的很快) 這終究不是一件輕鬆的事,因此 Mail Server Production 通常會提供整理過資訊的 Log Viewer 來增加 Log 的可讀性,更進一步則會將同個 Session 的 Log 組織在一起呈現,這也是這個部分主要想要討論的內容。以下紀錄了一些開發時處理較久的議題。
How to Organizing the Logs of the Same Session
答案其實在上面介紹的內容就有提到,也就是 Postfix 中用來識別 Mail 的 Queue ID,不過還有許多可以進一步討論的議題:
Q: Queue ID 產生前就被退信的 Log (如封鎖的寄件人) 該如何處理?
A: 額外處理,由於沒有資訊串連 Log,因此整個 Session 只能記一筆 Log。
Q: Queue ID 一定唯一嗎?
A: 理論上設定 enable_long_queue_ids 後就不會重複,不過如果 Server 有多個 Postfix Instance 則不一定。
Q: Forwarded Mail 是否能整合?
A: Forwarded Mail 其實是被 Postfix 視為新的 Mail 來處理,由原始 Mail 經
local
直接送給cleanup
並產生新的 Queue ID。因此要整合的話需要在local
,cleanup
間的溝通多傳遞原本的 Queue ID 資訊。Q: 非 Postfix Process 如何整合?
A: 以我開發的產品來說,大部分都是前面稍微提到的 Milter 和 Policy Delegation,他們與 Postfix Process 溝通時有傳 Queue ID 可以用來整合,不過如果是像前面 Log 中的
dovecot-lda
Command 的確沒有,需要額外加。
Statistic and Monitoring
Log 常常會有用來進行統計、數據分析的需求,去年剛好有讀到 DDIA ,其中有一章介紹到 OLAP, ETL, Data Warehouse 這些概念,受益很多,之後應該會做這本書的讀書筆記。不過我們的產品並沒有串這些,因此在 Log 量很多的情況,定期的搜集這些資訊會吃到一定的資源,進而影響到功能本身,我想這是之後開發類似功能可以再多考慮的點。
Log Rotation and Archiving
流量大的 Mail Server 不太可能讓 log 無限制的增長,因此需要實作類似於 logrotated
的 Log 輪替功能,但又要避免使用者覺得資料莫名其妙遺失的情況,因此讓他們有方式能定期的進行 Archive,這部分的實作不難,但像是如何提示使用者去定期 Archive、是否讓他們能客製化 Rotation 條件,這些問題都是 Feature Spec 中需要討論的事項,否則哪天無緣無故掉資料可能事情就大條了…。