本文上篇先從單機Mail Server收發郵件開始談起,進而提到使用客戶端收信相關的設定與調整,以及郵件安全相關的議題。本次中篇將延續上一期的內容繼續說明。
以下將從Mail Server之間遞送信件開始介紹,並說明sendmail設定、郵件RELAY概念。首先,介紹郵件遞送相關問題與設定方法,之後再講解進一步的設定。
郵件遞送相關問題與設定方法
這裡將會從A郵件主機傳送信件給B郵件主機,需求和測試環境介紹如下:
●範例中,B主機IP為172.18.0.108(承接上一期的相關資訊)。
●B主機將會設定成接收郵件地址為@foo.com.tw結尾的信件,例如接收寄給foo@foo.com.tw的信件。
●A主機將會寄送@foo.com.tw結尾的測試信件,例如寄給foo@foo.com.tw的信件。
上述信件最終應該要被B主機收下來,接著派送到foo收件匣「/var/spool/mail/foo」。
要完成上述的測試,最好須具備設定與測試DNS Client/Server基本能力。底下就針對可能阻礙信件傳遞的錯誤訊息以及相關處理方法進行說明。
郵件傳遞時優先查詢MX紀錄
在A主機使用指令「mail foo@foo.com.tw」寄信給foo@foo.com.tw時,不久後會收到退信,寄信的動作在上一集已經介紹過,示範如下圖:
收到的退信顯示以下的內容,這主要是因為foo.com.tw沒有MX紀錄,也沒有A紀錄的關係。
郵件傳遞優先使用MX紀錄來找出目標主機,假如要寄給foo@gmail.com,則會優先查出gmail.com的MX紀錄,這MX紀錄後面會有一個數字,緊接著是一個主機名稱,這個主機名稱解析出來的IP才是送信出去的目標主機。
使用指令「dig gmail.com mx」查出Gmail有五筆MX紀錄,MX紀錄後面的數字,較小的優先存取,其中以gmail-smtp-in.l.google.com數字最小(數字是5),如下圖所示。這個gmail-smtp-in.l.google.com解析出來的IP是209.85.201.114,才是我們送信出去的目標主機。
NOTE |
若沒有MX紀錄而使用A紀錄,可能也能傳送,但強烈建議使用標準MX紀錄方式。 |
有了以上的觀念之後,當A主機寄信給foo@foo.com.tw時,希望執行指令「dig foo.com.tw mx」能夠正確地解析,例如:
foo.com.tw. 86400 IN MX 10 mail.foo.com.tw.
mail.foo.com.tw. 86400 IN A 172.18.0.108 |
172.18.0.108是B主機IP。為簡化測試環境,筆者讓A、B這兩台主機都詢問同一台名稱解析伺服器,接著要能提供上述的解析,此伺服器須管理foo.com.tw這個zone,並編寫上述相關紀錄,由於Linux DNS Server的架設方法筆者曾經介紹過,故簡介如下:
編寫「/etc/named.conf」加入以下的內容,管理foo.com.tw這個zone:
並且編寫「/var/named/foo.com.tw.db」檔案的內容:
重點在於mail相關的那兩行,其中第一行開頭的空格要記得空,如此才代表同樣是上一行的開頭,也就是上上一行的@代表這個zone為foo.com.tw.,這一行的意思是foo.com.tw.有個MX紀錄,此MX紀錄為數字10指到mail這個名稱;接著第二行的mail有個A紀錄指到B主機的IP是172.18.0.108。請留意,這裡的mail都沒有.結尾,所以補上這個zone成為mail.foo.com.tw.。
重新啟動named後,就可以在A主機使用「dig foo.com.tw mx」查詢到原先希望得到的結果(也就是下述這兩筆紀錄),如下圖所示:
傳遞時被B主機防火牆阻擋
處理好名稱解析後,於A主機再度寄信給foo@foo.com.tw後,就不會收到退信,而且B主機也沒收到信件,這時候信件是佇列(Queue)在A主機這邊,使用指令「mailq」觀察到原因是「Deferred: mail.foo.com.tw.: No route to host」,如下圖。
TIPS |
使用指令「telnet mail.foo.com.tw 25」應該也是得到類似「Unable to connect to remote host: No route to host」的訊息。 |
此時,應該是被B主機防火牆擋到的關係,在B主機使用指令「system-config-securitylevel」開啟Mail(SMTP)即可。
sendmail預設僅聆聽127.0.0.1這個本地IP
處理好防火牆之後,執行指令「telnet mail.foo.com.tw 25」得到訊息已由原先「No route to host」成為「Connection refused」。下圖為處理B主機防火牆之前與之後,在A主機執行「telnet mail.foo.com.tw 25」的情況。
至於寄測試信的狀況也很類似,在執行指令「mailq」後會看到一則訊息「(Deferred: Connection refused by mail.foo.com.tw.)」,如下圖所示。
此時,信件應該已經要送往B主機但拒絕連線,所以到B主機觀察sendmail運作情況。先執行指令「chkconfig --list sendmail」,觀察出sendmail開機預設是「啟動」(on)。接著,使用指令「/etc/init.d/sendmail status」,發現sendmail現在是正在運作的狀態(running)。此外,在Process內也會看到sendmail的蹤影,執行指令「ps ax | grep sendmail」後,將顯示訊息「sendmail: accepting connections」。
重點來了!指令「netstat -na | grep -E -w '25|Foreign'」觀察到聆聽的Local Address欄位值是127.0.0.1:25,這樣的結果說明了只有在B主機上存取自己IP為127.0.0.1的25埠時才會通,其他來自於外部主機存取這台的25埠則不通(Connection refused)。
NOTE |
上述grep指令的關鍵字Foreign是為了顯示出執行指令「netstat -na」時Active Internet connections(servers and established)的欄位名稱(詳情請參考指令「netstat -na less」的輸出資料)。 |
想讓B主機能夠接收外來的信件,簡單地說,就是要把上述「127.0.0.1:25」處理成「0.0.0.0:25」即可,這樣就可以被其他外部主機存取這台的25埠,要完成這項設定,建議先學會sendmail較為特殊的設定方式。
sendmail較為特殊的設定方式
sendmail設定之所以特殊,是因為它不去直接修改設定檔案(sendmail.cf),反而是先編輯mc檔(sendmail.mc),再使用m4程式依照sendmail.mc的設定產生出sendmail.cf檔案。
若要直接編輯sendmail.cf也可以,但通常是極小幅度的修改;異動幅度大的設定,採用直接編輯的方式很難辦到。所幸,近年的Linux(也包括RHEL5)已經有做好配套措施,讓使用者不必再死記m4指令以及應該搭配哪些參數,取而代之的是make這個指令,依照系統提供的Makefile去執行相關指令,來簡化設定難度。
接著就以「將127.0.0.1改成0.0.0.0」為例來做示範。先使用指令「cd /etc/mail」切換到「/etc/mail」目錄內,然後編輯sendmail.mc檔案內容,找到以下這一行:
DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1,
Name=MTA')dnl |
改成(將127.0.0.1改成0.0.0.0):
DAEMON_OPTIONS(`Port=smtp,Addr=0.0.0.0,
Name=MTA')dnl |
沒有意外的話,改好之後執行make指令就會產生sendmail.cf檔案。
在執行make指令之後,若出現警告須利用sendmail.mc產生sendmail.cf還缺少sendmail-cf套件,則使用指令「yum install -y sendmail-cf」補裝套件即可,提示的訊息如下:
補裝sendmail-cf套件之後,二度執行make就不會出現警告訊息。接著,在執行指令「make restart」的前後,使用先前介紹的netstat指令就可以觀察到已經由先前127.0.0.1:25改變成後來0.0.0.0:25。
NOTE |
在「/etc/mail」目錄下執行指令「make restart」等同於執行指令「/etc/init.d/sendmail restart」。 |
若使用指令「ls -l」仔細觀察「/etc/mail/sendmail.cf」檔案的修改時間,就會發現它是在執行make時被修改的。將sendmail設定成會聆聽所有介面之後,回到A主機再度寄信測試,這次得到的訊息是:
之所以出現這個訊息,以測試環境來說有兩個狀況:情況一是由A主機發測試信給B主機,但「兩台主機擁有同樣的主機名稱」所造成;情況二則是直接在B主機發測試信給自己,此時已經避開「兩台主機擁有同樣的主機名稱」問題,真正的問題在於B主機並不覺得這封信件應該由自己主機收下來。接著,針對以上這兩個狀況分別說明。
兩台主機名稱相同所造成的問題
Red Hat系列的Linux預設主機名稱是「localhost.localdomain」,也因此兩台測試主機都是這個名字,所以選擇改動其中一台的主機名稱使之錯開,就可以繼續測試下去。在此,選擇將A主機的主機名稱修改成「mail.foo2.com.tw」。
想要變更Red Hat系列Linux的主機名稱,是修改「/etc/sysconfig/network」和「/etc/hosts」檔案內容,改完之後記得執行指令「reboot」重新開機使其生效(或是把所有運作中的Process都重新啟動)。詳細的操作過程說明如下:
編輯檔案「/etc/sysconfig/network」,將由原先的:
HOSTNAME=localhost.localdomain |
改成
HOSTNAME=mail.foo2.com.tw |
接著,編輯「/etc/hosts」,將原先的:
127.0.0.1 localhost.localdomain localhost |
「增加」為:
127.0.0.1 mail.foo2.com.tw mail localhost.
localdomain localhost |
NOTE |
在「/etc/hosts」時,若不小心把localhost覆蓋掉,會影響到主機運作,例如連線到localhost將出現無法解析成127.0.0.1的錯誤訊息。 |
郵件RELAY概念
修改好主機名稱再次寄送測試信之後,出現「reason: 550 5.7.1 ... Relaying denied. IP name lookup failed [172.18.0.191]」訊息,其重點在於Relaying denied(拒絕轉遞)以及何謂RELAY這個部分,解說如下:
A主機將信件依照流程送到B主機,B主機按照我們的需求「應該」要將信件視為這台郵件主機的且收下來才對。
但是在這個「應該」做的動作還沒調整之前,B主機會覺得這封信件不是給它的而將其轉出去,這個幫忙轉遞信件的動作就是RELAY,而預設郵件主機僅允許RELAY來自127.0.0.1的信件,至於來自於外部IP的轉遞信件預設不允許RELAY,例如由B主機發送過來的信件。
RELAY預設都不開放給外部主機,主要是因為垃圾信(廣告信、釣魚信)猖獗的關係,如果主機遇到被當成廣告信件(釣魚信件)發送的跳板時,很有可能就是RELAY設定不當所造成。
關於RELAY的部分,此處先行介紹觀念,設定的部分留到後續再做完整的介紹。
B主機「接受」以@foo.com.tw結尾的信件
要讓B主機認為@foo.com.tw結尾是他的信件,須設定B主機的「/etc/mail/local-host-names」,加入「foo.com.tw」即可,設定好了之後,記得重新啟動sendmail,才會生效。
NOTE |
local-host-names若以功能面來看,可以輸入許多行(例如多加一行「yahoo.com.tw」),這樣一來,寄給foo@yahoo.com.tw郵件若是經過這台來遞送,會被這台主機視為是它的信件而收下來。 |
至此,由A主機寄給B主機的foo@foo.com.tw信件終於傳到B主機foo收信匣「/var/spool/mail/foo」。
事實上,整個郵件遞送的流程是固定且有邏輯的,照這樣來看,要查出一封寄不到對方信箱的信件似乎不難,而若想查出寄出去卻石沉大海的信件也應該很簡單才對,其實困難的部分在於,能否取得遞送之間所有的郵件主機相關紀錄。
若發生由A公司寄給B公司信件不通或是消失不見,建議兩方都須協助調查,結果才會圓滿,例如提供相關的那幾行maillog(如果是sendmail則在「/var/log/」目錄)。
給雙方互相檢視也是一種處理方法,筆者在此主要是將重點放在郵件傳遞不通時的問題處理與故障排除、郵件遞送之間的觀念釐清等等。
上述都是使用指令直接在Linux主機上發送信件,但實務上,一般用戶大多是開啟圖形郵件軟體(例如Outlook)來收發信件,這個部分的解說將會在下集內介紹。