NA-HW3-POSTFIX-自建MAIL服務

NA-hw3 Postfix

HW3 spec

Create virtual machine

mail server

os: CentOS 8.3
username: cychen
passwd:

interfaces:

  1. enp0s3: Intranet(get IP addr 10.113.40.30 from DHCP)
  2. enp0s8: Host-Only(only for ssh)

設置主機名稱:

1
hostname mail.40.nasa

修改 /etc/hosts

1
2
3
127.0.0.1       localhost
10.113.40.30 mail.40.nasa
10.113.40.30 mail

新增使用者:

1
2
$ useradd -d -g mail -s /sbin/nologin ta
$ useradd -d -g mail -s /sbin/nologin cool-ta
1
2
3
4
5
6
$ passwd ta
Enter New UNIX password:
Retype New UNIX password:
$ passwd cool-ta
Enter New UNIX password:
Retype New UNIX password:

DHCP Server

Spec 有說明:You are required to redirect any DNS query within .nasa to this DNS server(10.113.0.254),但這句話講的非常的爛。

你在 judge 的時候要和 judge 機器互相送 mail 來測試,judge 機是 54.nasa,意味著你必須要能解析 54.nasa 這個 domain name 的 records,包括 A、MX、SPF⋯⋯,但依照 Hw2 的 DNS Server,你是沒辦法的。所以需要讓 DHCP 在告知你的電腦們 DNS Server 要是 10.113.0.254,之後你去查詢例如 40.nasa,他就會去遞迴的查詢,所以此時你在 Hw2 架設的 DNS Server 是作為 Authoritative DNS Server 用。

作法在 Hw2 有講過了。

DNS - Add MX Record

你必須要新增 MX record 來告訴別人信件應該要轉發給哪台主機:

1
@  IN   MX  10  mail.40.nasa.    

Spec 強迫我選擇讓它發給 mail.40.nasa. 這個主機,而這裡的 10 意味著 Priority,此值越低表示有越高優先度。接下來我必須要讓 mail.40.nasa 指向到我的 Mail Server:

1
mail  IN   A  10.113.40.30

Mail Server - Postfix 和 Dovecot

Postfix 負責信件轉發、收件的服務,就是 Mail Server(MTA),負責 SMTP。
Dovecot 專門負責給使用者查詢信件的服務,也就是 Mail Receive Agent(MRA),負責 IMAP。

而在這裡 Dovecot 擔任的角色比 MRA 多一點,就是 Postfix 可以直接使用 Dovecot 的認證模塊。SASL(簡單認證與安全層)的設計把認證機制從程式中分離開,所以我們可以把 Postfix 的認證部分交給其他程式來做,這邊因為 Dovecot 本來就必須要對使用者進行認證才能讓他們檢索郵件,所以就一石二鳥,讓 Postfix 使用 Dovecot 的認證機制。

:::danger
所以 Debug 的時候如果發現 SMTP 無法登入,可能是 Dovecot 爛了。
:::

防火牆設定:

你必須允許 SMTP 所需要的 25 port 和 IMAP 所需要的 143 port

先關掉 SELINUX,由於在 Hw2 被他坑了之後,我現在都會先關閉 SELINUX:

1
vim /etc/selinux/config
1
SELINUX=disabled

再關閉防火牆:

1
2
systemctl disable firewalld.service
systemctl stop firewalld.service

Postfix 的安裝、設定:

1
$ dnf install postfix

:::info
dnf(Dandified Yum),顧名思義就是拿來取代 yum 的,是一套效能比較好的套件管理程式,把他當作 yum 的升級版就好。
:::

1
$ vim /etc/postfix/main.cf

修改下面項(在 main.cf 對應項的附近都有比較詳細的參數的參數介紹):

1
2
3
4
5
6
7
8
9
myhostname = mail.40.nasa
mydomain = 40.nasa
myorigin = $mydomain

inet_interfaces = all
inet_protocols = all
mydestination = $myhostname, $mydomain, localhost

mynetworks = 10.113.40.0/24, 127.0.0.0/8

添加到開機啟動項以及啟動它:

1
2
systemctl enable postfix
systemctl restart postfix

Dovecot 的安裝:

1
dnf install dovecot 

讓 Dovecot 為 Postfix SMTP 做 Auth:

1
vim /etc/dovecot/conf.d/10-master.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

service auth {


unix_listener auth-userdb {
#mode = 0666
#user =
#group =
}

# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
}

}

為認證機制做設定:

1
vim /etc/dovecot/conf.d/10-auth.conf
1
auth_mechanisms = plain login

允許 IMAP 登入:

1
vim /etc/dovecot/dovecot.conf
1
protocols = imap

還要設置讓 Dovecot 能有讀取 MailBox 的權限:

1
2
mail_location = mbox:~/mail:INBOX=/var/mail/%u
mail_access_groups=mail

:::info

plain 在登入的時候會把帳號和密碼依照特定格式組合成一行,再做 base64 一併傳送。
login 則會在登入的時候分開傳遞帳號的 base64 編碼 和密碼的 base64 編碼。

這邊同時允許這兩種認證方式,實際上大同小異。

詳見 REF
:::

讓 Postfix 使用 Dovecot 做 Auth

1
vim /etc/postfix/main.cf

添加如下:

1
2
3
4
5
6
# Dovecot Auth
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous

設定 Mailbox 的讀寫權限

1
chmod 600 /var/mail/*

給 Dovecot 讀取 Mailbox 的權限

1
vim /etc/dovecot/conf.d/10-mail.conf
1
2
mail_location = mbox:~/mail:INBOX=/var/mail/%u
mail_privileged_group = mail

添加到開機啟動項以及啟動它:

1
2
systemctl enable dovecot
systemctl restart dovecot

SSL 設定

首先你要會如何使用 openssl 生成私鑰和憑證:

1
openssl req -newkey rsa:2048 -nodes -sha512 -x509 -days 365 -nodes -out public_cert.pem -keyout private_key.pem

這邊的參數都很簡單:

rsa:2048:RSA 演算法,金鑰長度為 2048 bits。
sha512:選定雜湊演算法來產生憑證。
nodes:代表使用時不需要輸入密碼
x509:使用 X.509 這個公鑰憑證的格式標準。

Postfix SSL 設定:STARTTLS

1
vim /etc/postfix/main.cf

追加:

1
2
3
4
5
6
7
smtp_use_tls = yes
smtpd_use_tls = yes
smtp_tls_note_starttls_offer = yes
smtpd_tls_security_level = may
smtpd_tls_key_file = 私鑰位置
smtpd_tls_cert_file = 憑證位置
smtpd_tls_loglevel = 1

Dovecot SSL 設定

1
vim /etc/dovecot/conf.d/10-ssl.conf
1
2
3
4
ssl = yes

ssl_cert = <證書位置
ssl_key = <私鑰位置

:::warning
這個 < 是必要的,我猜測他的意思是在程式啟動的時候從這兩個位置直接讀檔進來。
:::

測試 SMTP 寄件和 IMAP 收件

由於有些資料是用 Base64 編碼傳遞的,所以要先知道怎麼編碼解碼

1
2
3
4
$ echo -n "ta" | base64
dGE=
$ echo -n "dGE=" | base64 -d
ta

:::danger
這個 -n 代表 echo 不要換行,如果換行了,你的 base64 後的結果就會錯掉(多一個 \n 會被加進去編碼內)

1
2
3
4
$ echo "ta" | base64 | base64 -d | wc -c
3
echo -n "ta" | base64 | base64 -d | wc -c
2

wc -c:計算輸入了多少個字符。
:::

用 telnet 測試 SMTP:

登入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ telnet mail.40.nasa 25
220 mail.40.nasa ESMTP Postfix
EHLO mail.40.nasa
250-mail.40.nasa
250-PIPELINING
250-SIZE 102400000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
AUTH LOGIN
334 VXNlcm5hbWU6
dGE=
334 UGFzc3dvcmQ6
K0JIeFd2NUFxM0xxSjcranNuYkIyTFJUMzVZTmNYZEs2QUJXcVJLaGNtOD0=
235 2.7.0 Authentication successful

EHLO mail.40.nasa:ECHO HELLO,和伺服器說 HELLO 以及你是哪位。

他回傳了:

1
2
3
4
5
6
7
8
9
10
11
12
13
250-mail.40.nasa
250-PIPELINING
250-SIZE 102400000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING

AUTH LOGIN:告訴他說我現在要登入,然後使用 LOGIN 這種機制,意味著我要分開打帳號與密碼。

伺服器回傳:334 VXNlcm5hbWU6VXNlcm5hbWU6 用 Base64 解碼後是用戶名稱的意思,所以輸入 Base64 後的用戶名稱。 334 UGFzc3dvcmQ6 告訴我們輸入密碼。

分開輸入後,就得到結果:235 2.7.0 Authentication successful

寄信
1
2
3
4
5
6
7
8
9
MAIL FROM: ta@40.nasa
250 2.1.0 Ok
RCPT TO: cychen@40.nasa
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
This is a test mail.
.
250 2.0.0 Ok: queued as 6C7B610DA8E4

MAIL FROM: ta@40.nasa:寄件者是 ta@40.nasa
RCPT TO: cychen@40.nasa:收件者是 cychen@40.nasa
DATA:接下來開始是信件內容。
.:單獨一行 . 代表資料結束了。
quit:請求結束連線。

用 telnet 測試 IMAP:

實際使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ telnet mail.40.nasa 143
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ STARTTLS AUTH=PLAIN AUTH=LOGIN] Dovecot ready.
A01 login ta +BHxWv5Aq3LqJ7+jsnbB2LRT35YNcXdK6ABWqRKhcm8=
A01 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY LITERAL+ NOTIFY SPECIAL-USE] Logged in
A02 list "" *
* LIST (\HasNoChildren) "/" INBOX
A02 OK List completed (0.004 + 0.000 + 0.003 secs).
A03 SELECT INBOX
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags permitted.
* 32 EXISTS
* 29 RECENT
* OK [UNSEEN 1] First unseen.
* OK [UIDVALIDITY 1620023446] UIDs valid
* OK [UIDNEXT 33] Predicted next UID
A04 SEARCH ALL
* SEARCH 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
A04 OK Search completed (0.002 + 0.000 + 0.001 secs).
A05 FETCH 32 FULL
* 32 FETCH (FLAGS (\Recent) INTERNALDATE "04-May-2021 17:12:49 -0400" RFC822.SIZE 1828 ENVELOPE ("Tue, 4 May 2021 17:12:30 -0400 (EDT)" {6}
陽交 ((NIL NIL "ta" "40.nasa")) ((NIL NIL "ta" "40.nasa")) ((NIL NIL "ta" "40.nasa")) NIL NIL NIL NIL "<20210504211234.339FB10DA8E4@mail.40.nasa>") BODY ("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 0 0))
A05 OK Fetch completed (0.101 + 0.000 + 0.100 secs).
A06 LOGOUT
純指令:
1
2
3
4
5
6
A01 LOGIN ta +BHxWv5Aq3LqJ7+jsnbB2LRT35YNcXdK6ABWqRKhcm8=
A02 LIST "" *
A03 SELECT INBOX
A04 SEARCH ALL
A05 FETCH 32 FULL
A06 LOGOUT
指令格式:
1
COMMAND_NAME COMMAND PARAMETER1, ...
指令列表:

LOGIN NAME PASSWORD:登入某使用者。
LIST "" \*:列出所有收件箱。
SELECT INBOX:選擇收件箱 INBOX
SEARCH ALL:列出所有信件。
FETCH 32 FULL:下載第 32 號信全部。
LOGOUT:登出。

用 openssl 測試 SSL 連線:

1
2
$ openssl s_client -connect mail.{ID}.nasa:25 -starttls smtp
$ openssl s_client -connect mail.{ID}.nasa:143 -starttls imap

建立連線後和 telnet 中的使用方式相同,openssl 會幫你加密解密。

SPF、DKIM 和 DMARC

先知道 SPF、DKIM 和 DMARC 是什麼: 為郵件系統安全把關,新增 SPF, DKIM 和 DMARC 設定以避免有心人士的釣魚攻擊

這邊設定 Outgoing Mails 的 Policy,如果設爛了你的信會被當垃圾信。

:::info
這邊基本上完全參考

某一篇文章
另一篇文章

他們寫的很好,如果設定不起來可以去看他的。我僅針對 Spec 做了一些調整。
:::

Mail Server - 安裝、配置 OpenDKIM

OpenDKIM 是一隻很方便的程式,他可以幫我們:

  1. 產生 DKIM Record
  2. 簽署 Outgoing Mail
  3. 檢查 Incoming Mails 的 DKIM(後面再設)

安裝 OpenDKIM:

1
dnf install opendkim opendkim-tools 

給予 OpenDKIM 的程式權限:

1
gpasswd -a postfix opendkim

配置 OpenDKIM

1
vim  /etc/opendkim.conf
1
2
3
4
5
6
7
8
9
10
11
#  Selects operating modes -> s (sign) and v (verify)
Mode sv

UserID opendkim:opendkim
Socket inet:8891@localhost
Domain 40.nasa

KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts

這兩個文件 KeyTableSigningTable 是用來管理你對不同 Domain 的 DKIM 資料。
我現在要針對 40.nasamail.40.nasa 這兩個 domain name 來生 DKIM 的 Records 和 Key:

1
2
3
4
5
6
7
$ mkdir /etc/opendkim/keys/mail.40.nasa
$ cd /etc/opendkim/keys/mail.40.nasa
$ opendkim-genkey -t -s mail -d mail.40.nasa

$ mkdir /etc/opendkim/keys/40.nasa
$ cd /etc/opendkim/keys/40.nasa
$ opendkim-genkey -t -s mail -d 40.nasa

設定 Permissions:

1
chown -R opendkim:opendkim /etc/opendkim

修改(若不存在則新增)/etc/opendkim/KeyTable

1
2
mail._domainkey.40.nasa 40.nasa:mail:/etc/opendkim/keys/40.nasa/mail.private
mail._domainkey.mail.40.nasa mail.40.nasa:mail:/etc/opendkim/keys/mail.40.nasa/mail.private

:::warning
這裡的 mail 必須要和上面 opendkim-genkey-s mail 的參數相同。
:::

修改(若不存在則新增)/etc/opendkim/SigningTable

1
2
40.nasa mail._domainkey.40.nasa
mail.40.nasa mail._domainkey.mail.40.nasa

啟動並且加入開機啟動項:

1
2
systemctl start opendkim
systemctl enable opendkim

Mail Server - 讓 OpenDKIM 為 Postfix 的信件做簽名

1
vim /etc/postfix/main.cf
1
2
3
4
5
6
7
# milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = $smtpd_milters

# DKIM: inet:localhost:8891

DNS - SPF Policy

在 DNS Server 增加此兩條 Records:

1
2
@       IN	TXT	"v=spf1 a mx ipv4:10.113.40.30 -all"
mail IN TXT "v=spf1 a mx ipv4:10.113.40.30 -all"

意思就是允許我這個 domain name 的 a records、mx records 和 10.113.40.30 這個IP 使用這個 domain name 來寄信,其他全部 REJECT。

DNS - DKIM Records

1
$ cat /etc/opendkim/keys/*/*.txt

會得到

1
2
3
4
mail._domainkey	IN	TXT	( "v=DKIM1; k=rsa; t=y; "
"p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBaohjhJh73YFC6EE9gzPH6MvkFTltrf4ZLs/22AO3Lhhphr18VLeaBxbWdHMDXmfovqDnMIm0jME30c3AG+cuo50vWFWiLUBXY3GTaiRTVxi2LwVSkUZCdHgTR9nFyY9PXG/h4QwINCRHN1wEnorUqBrGBImTpeDbxXi16bVELQIDAQAB" ) ; ----- DKIM key mail for 40.nasa
mail._domainkey IN TXT ( "v=DKIM1; k=rsa; t=y; "
"p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzQ+eVqmFI+KBsCaCqqmWDQiyu7RDumA2/7M966tE/iMTKHaZvnyidQAueoVuTad0K812PU9iRqSMvBFpk1Mcz4Lz7YXeQ2Y5UhqSMl3jiJhpRw1Ccr4LZIpeM0spMBAdePDjLUefAQ6nxQS5SIynmafnNPYUzheyevbdM81RyzQIDAQAB" ) ; ----- DKIM key mail for mail.40.nasa

我們要修改其中 mail.40.nasa 的 DKIM Key Record,滑到行末可以看到,在這裡是下面那一筆。 我們要改成這樣:mail._domainkey.mail,因為是 mail.40.nasa 底下的,原因是因為我們並未額外 mail.40.nasa 寫一個 zonefile。
:::danger
沒改你會爛掉。
:::
所以最後變成這樣,放到 DNS Server 上就好了:

1
2
3
4
mail._domainkey IN      TXT     ( "v=DKIM1; k=rsa; t=y; "
"p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBaohjhJh73YFC6EE9gzPH6MvkFTltrf4ZLs/22AO3Lhhphr18VLeaBxbWdHMDXmfovqDnMIm0jME30c3AG+cuo50vWFWiLUBXY3GTaiRTVxi2LwVSkUZCdHgTR9nFyY9PXG/h4QwINCRHN1wEnorUqBrGBImTpeDbxXi16bVELQIDAQAB" ) ; ----- DKIM key mail for 40.nasa
mail._domainkey.mail IN TXT ( "v=DKIM1; k=rsa; t=y; "
"p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzQ+eVqmFI+KBsCaCqqmWDQiyu7RDumA2/7M966tE/iMTKHaZvnyidQAueoVuTad0K812PU9iRqSMvBFpk1Mcz4Lz7YXeQ2Y5UhqSMl3jiJhpRw1Ccr4LZIpeM0spMBAdePDjLUefAQ6nxQS5SIynmafnNPYUzheyevbdM81RyzQIDAQAB" ) ; ----- DKIM key mail for mail.40.nasa

DNS - DMARC Policy

DMARC 就是看如果 SPF 或 DKIM 的檢查 REJECT 掉一封信之後,收到這封信的郵件伺服器應該做什麼事情,按照 spec,直接 DROP 掉就好。

1
2
_dmarc          IN      TXT     "v=DMARC1; p=reject"
_dmarc.mail IN TXT "v=DMARC1; p=reject"

測試 OpenDKIM 是否有成功的為 Postfix 寄出的郵件簽名

重啟 OpenDKIM 和 Postfix 後,寄一封信給自己,然後查看(可直接用 cat /var/mail/user 來看):

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
From ta@40.nasa  Tue May  4 17:12:49 2021
Return-Path: <ta@40.nasa>
X-Original-To: cychen@40.nasa
Delivered-To: cychen@40.nasa
Received: from localhost (localhost [127.0.0.1])
by mail.40.nasa (Postfix) with ESMTP id 9703C10DA8E5
for <cychen@40.nasa>; Tue, 4 May 2021 17:12:49 -0400 (EDT)
DKIM-Filter: OpenDKIM Filter v2.11.0 mail.40.nasa 9703C10DA8E5
Authentication-Results: mail.40.nasa;
dkim=pass (1024-bit key; unprotected) header.d=40.nasa header.i=@40.nasa header.a=rsa-sha256 header.s=mail header.b=Sgq3za4h
X-Virus-Scanned: amavisd-new at 40.nasa
X-Amavis-Alert: BAD HEADER SECTION, MIME error: error: unexpected end of
header
X-Spam-Flag: NO
X-Spam-Score: 2.093
X-Spam-Level: **
X-Spam-Status: No, score=2.093 tagged_above=2 required=6.2
tests=[ALL_TRUSTED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1,
DKIM_VALID_AU=-0.1, FSL_BULK_SIG=0.001, MISSING_HEADERS=1.207,
PYZOR_CHECK=1.985] autolearn=no autolearn_force=no
Received: from mail.40.nasa ([127.0.0.1])
by localhost (mail.40.nasa [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id vol_chT6ODyA for <cychen@40.nasa>;
Tue, 4 May 2021 17:12:46 -0400 (EDT)
Received: from mail.40.nasa (localhost [IPv6:::1])
by mail.40.nasa (Postfix) with ESMTPA id 339FB10DA8E4
for <cychen@40.nasa>; Tue, 4 May 2021 17:12:30 -0400 (EDT)
DKIM-Filter: OpenDKIM Filter v2.11.0 mail.40.nasa 339FB10DA8E4
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=40.nasa; s=mail;
t=1620162766; bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=;
h=Subject:Date:From:From;
b=Sgq3za4hDGbMAnlX44D+NUoQVB4Oxulw3BAvWgEbyVwlt8IEz7sOfGOceOPyvTNn3
/A+IoF0BXYQJUL2uPn6ysPMHdSkH1Wa5bcoKqx/dsxYRdCwk4xtUiTGYf8oL8JOc5V
GVOpdnAtEKFi7bEaYVUvvqRfaGjQJF3l1J/93Rqs=
Subject: 陽交
Message-Id: <20210504211234.339FB10DA8E4@mail.40.nasa>
Date: Tue, 4 May 2021 17:12:30 -0400 (EDT)
From: ta@40.nasa
X-UID: 32
Status: O

發現的確是有 DKIM-Signature 這個 header field 的,有成功簽名。

進階的 Postfix 設定

防止冒名發信(avoid fake user)

修改 /etc/postfix/main.cf

1
2
3
4
5
smtpd_sender_login_maps = regexp:/etc/postfix/sender_login_map
smtpd_sender_restrictions =
...
reject_sender_login_mismatch
...

:::warning
這邊 smtpd_sender_restrictions... 只是讓你保留原有的資料,不要真的加 ...
:::
修改(若不存在新增)/etc/postfix/sender_login_map

1
/^(.+)@(mail\.)?40\.nasa$/ $1

這個意思就是:

對於所有符合 /^(.+)@(mail\.)?40\.nasa$/ 這個 regex pattern 的使用者,我把這個使用者視為 $1,而這個 $1 就是第一個括號,也就是 $(.+)$ 所匹配到的內容。

:::info
. 在 regex 中代表任意字符,而 + 代表前面一個 pattern 出現 1 次及以上。所以 (.)+ 就是一個可以匹配任意非空字串的正則。
:::

防止 Null 使用者(avoid mail from: )

我們修改 /etc/postfix/main.cf

1
2
3
4
smtpd_sender_restrictions = 
...
check_sender_access hash:/etc/postfix/sender_check
...

接著修改 /etc/postfix/sender_check

1
<>      REJECT  null users are not allowed

之後執行指令將文字檔變成資料庫:

1
postmap /etc/postfix/sender_check

防止 Open Relay

設置 /etc/postfix/main.cf

1
2
3
4
5
6
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination
smtpd_sender_restrictions =
...
reject_non_fqdn_sender
reject_unknown_sender_domain
...

Virtual alias

設置 /etc/postfix/main.cf

1
virtual_alias_maps = hash:/etc/postfix/virtual regexp:/etc/postfix/virtual.regexp

/etc/postfix/virtual 追加一行: NASATA TA

/etc/postfix/virtual.regexp 追加一行:/^.+\|([^@]+)@(.+)$/ $1@$2

1
postmap /etc/postfix/virtual

Sender rewrite

設置 /etc/postfix/main.cf

1
2
local_header_rewrite_clients = permit_mynetworks permit_sasl_authenticated
sender_canonical_maps = regexp:/etc/postfix/sender_canonical_maps

追加 /etc/postfix/sender_canonical_maps 兩行:

1
2
/cool-ta@(mail.)?40.nasa/ notcool-TA@40.nasa
/(.+)@(mail.)?40.nasa/ $1@40.nasa

SPF、DKIM 和 DMARC 的 Incoming Check

參考資料

安裝 opendmarcdnf install opendmarc
修改 /etc/postfix/main.cf

1
2
3
4
5
6
# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters =
...
inet:127.0.0.1:8893

設定 /etc/opendmarc.conf

1
2
3
4
5
6
7
8
9
10
11
Socket inet:8893@localhost
SoftwareHeader true
SPFIgnoreResults true
SPFSelfValidate true
Syslog true
UMask 777
UserID opendmarc:mail
TrustedAuthservIDs mail.40.nasa
RejectFailures true
RequiredHeaders false
IgnoreAuthenticatedClients true

開啟並加入開機啟動項:

1
2
systemctl enable opendmarc
systemctl start opendmarc

Anti Spam Mail

Greylisting

Greylisting 假設正常信都是由 Mail Server 寄出, 所以它們都有著重寄的機制。故此機制會先將信件資料記錄後,拒絕收信,期待對方 mail server 重寄此信才要接受它。因為如果用腳本大量發送垃圾信件時,額外儲存被退件的並等一點時間之後再去寄件是不符合成本的,所以在廣發垃圾信的時候,最大收益將不會是重新寄信。因此 Greylisting 能起到不錯的防垃圾信的功效。

安裝 portgreydnf install postgrey
設定 portgrey 的灰名單時間:

1
vim /etc/sysconfig/postgrey
1
POSTGREY_OPTS="--delay=30"

為 greylist 添加 whitelist:

1
vim /etc/postfix/postgrey_whitelist_clients.local
1
2
40.nasa
mail.40.nasa

修改 /etc/postfix/main.cf

1
2
3
4
smtpd_recipient_restrictions =
...
check_policy_service unix:postgrey/socket
...

重啟 postgrey 並加入啟動項:

1
2
systemctl enable postgrey
systemctl restart postgrey

Spam Filtering and Virus Detection

這裡使用了另外兩個工具:clamavamavis

1
dnf install install clamav clamav-update amavisd-new clamav-scanner-systemd

:::danger
安裝完後需要重新啟動,否則可能會有奇怪的問題。
:::

1
2
sed -i -e "s/^Example/#Example/" /etc/freshclam.conf
freshclam

:::info
實務考量可能要設個 cronjob,定期 freshclam 來更新資料庫。
:::

編輯 /etc/amavisd/amavisd.conf

1
2
3
4
5
6
7
8
9
$mydomain = '40.nasa';
$myhostname = 'mail.40.nasa';
$sa_spam_subject_tag = '*** SPAM *** ';
$sa_spam_modifies_subj = 1;
$final_virus_destiny = D_PASS;
$final_banned_destiny = D_PASS;
$final_spam_destiny = D_PASS;
$final_bad_header_destiny = D_PASS;
$subject_tag_maps_by_ccat{+CC_VIRUS} = [ '*** SPAM *** ' ];

這邊的 D_PASS 代表當他偵測到某個事項之後要做的事情,spec 要求我們讓他過,但是要在標題加一個 “*** SPAM ***”。

可以用這個指令檢查 amavisd 的設定檔:

1
amavisd -u amavis -c /etc/amavisd/amavisd.conf debug

而後編輯 /etc/postfix/main.cf

1
content_filter=amavis:127.0.0.1:10024

再修改 /etc/postfix/master.cf 追加此內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
amavis unix - - - - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
127.0.0.1:10025 inet n - - - - smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_client_restrictions=
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks=127.0.0.0/8
-o strict_rfc821_envelopes=yes
-o receive_override_options=no_unknown_recipient_checks,no_header_body_checks

啟用並且添加到開機啟動項:

1
2
systemctl enable clamd@amavisd amavisd spamassassin
systemctl restart clamd@amavisd amavisd spamassassin postfix

:::danger

如果你有開啟 SELINUX,可能需要先執行:

1
2
setsebool -P antivirus_can_scan_system 1
setsebool -P clamd_use_jit on

:::

Outgoing Mail Filter

編輯 /etc/postfix/main.cf

1
header_checks = regexp:/etc/postfix/header_checks

修改 /etc/postfix/header_checks

1
2
3
4
/^Subject:.*陽交.*/     REJECT
/^Subject:.*=?UTF-8?B?6Zm95Lqk?=.*/ REJECT
/^Subject:.*6Zm95Lqk.*/ REJECT
/^Subject:.*NCTU.*/ REJECT

參考資料

Debug

  1. 如果這些東西裝不起來,你可能要加入 milter-manager_reposEPEL_repo
  2. clamd@amavisd
    :::danger
    我原本是用 clamd@scanner 來做,但後來失敗了,我改用 amavisd。
    但 clamd 一次僅能使用一種服務,所以我很理所當然的 disable/stop 了 scanner,又 enable/start 了 amavisd,但這還沒完。

你還必須要修改:/usr/lib/systemd/system/clamd\@amavisd.service

1
2
[Service]
ExecStart = /usr/sbin/clamd -c /etc/clamd.d/amavisd.conf

這個垃圾 Bug 坑了我好久的時間= =。

參考資料
:::