DNAT(Destination Network Address Translation,目的地址轉(zhuǎn)換) 通常被叫做目的映謝。而SNAT(Source Network Address Translation,源地址轉(zhuǎn)換)通常被叫做源映謝。
這是我們?cè)谠O(shè)置Linux網(wǎng)關(guān)或者防火墻時(shí)經(jīng)常要用來(lái)的兩種方式。以前對(duì)這兩個(gè)都解釋得不太清楚,現(xiàn)在我在這里解釋一下。
首先,我們要了解一下IP包的結(jié)構(gòu),如下圖所示:
在任何一個(gè)IP數(shù)據(jù)包中,都會(huì)有Source IP Address與Destination IP Address這兩個(gè)字段,數(shù)據(jù)包所經(jīng)過(guò)的路由器也是根據(jù)這兩個(gè)字段是判定數(shù)據(jù)包是由什么地方發(fā)過(guò)來(lái)的,它要將數(shù)據(jù)包發(fā)到什么地方去。而iptables的DNAT與SNAT就是根據(jù)這個(gè)原理,對(duì)Source IP Address與Destination IP Address進(jìn)行修改。
然后,我們?cè)倏纯磾?shù)據(jù)包在iptables中要經(jīng)過(guò)的鏈(chain):
圖中正菱形的區(qū)域是對(duì)數(shù)據(jù)包進(jìn)行判定轉(zhuǎn)發(fā)的地方。在這里,系統(tǒng)會(huì)根據(jù)IP數(shù)據(jù)包中的destination ip address中的IP地址對(duì)數(shù)據(jù)包進(jìn)行分發(fā)。如果destination ip adress是本機(jī)地址,數(shù)據(jù)將會(huì)被轉(zhuǎn)交給INPUT鏈。如果不是本機(jī)地址,則交給FORWARD鏈檢測(cè)。
這也就是說(shuō),我們要做的DNAT要在進(jìn)入這個(gè)菱形轉(zhuǎn)發(fā)區(qū)域之前,也就是在PREROUTING鏈中做,比如我們要把訪問(wèn)202.103.96.112的訪問(wèn)轉(zhuǎn)發(fā)到192.168.0.112上:
iptables -t nat -A PREROUTING -d 202.103.96.112 -j DNAT --to-destination 192.168.0.112
這個(gè)轉(zhuǎn)換過(guò)程當(dāng)中,其實(shí)就是將已經(jīng)達(dá)到這臺(tái)Linux網(wǎng)關(guān)(防火墻)上的數(shù)據(jù)包上的destination ip address從202.103.96.112修改為192.168.0.112然后交給系統(tǒng)路由進(jìn)行轉(zhuǎn)發(fā)。
而SNAT自然是要在數(shù)據(jù)包流出這臺(tái)機(jī)器之前的最后一個(gè)鏈也就是POSTROUTING鏈來(lái)進(jìn)行操作
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j SNAT --to-source 58.20.51.66
這個(gè)語(yǔ)句就是告訴系統(tǒng)把即將要流出本機(jī)的數(shù)據(jù)的source ip address修改成為58.20.51.66。這樣,數(shù)據(jù)包在達(dá)到目的機(jī)器以后,目的機(jī)器會(huì)將包返回到58.20.51.66也就是本機(jī)。如果不做這個(gè)操作,那么你的數(shù)據(jù)包在傳遞的過(guò)程中,reply的包肯定會(huì)丟失。
注意,DNAT target只能用在nat表的PREOUTING 和 OUTPUT 鏈中,或者是被這兩條鏈調(diào)用的鏈里。但還要注意的是,包含DNAT target的連不能被除此之外的其他鏈調(diào)用,如POSTROUTING。
Table 6-16. DNAT target
Option --to-destination
Example iptables -t nat -A PREROUTING -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10
Explanation指定要寫(xiě)入IP頭的地址,這也是包要被轉(zhuǎn)發(fā)到的地方。上面的例子就是把所有發(fā)往地址15.45.23.67的包都轉(zhuǎn)發(fā)到一段LAN使用的私有地址中,即192.168.1.1到192.168.1.10。如前所述,在這種情況下,每個(gè)流都會(huì)被隨機(jī)分配一個(gè)要轉(zhuǎn)發(fā)到的地址,但同一個(gè)流總是使用同一個(gè)地址。我們也可以只指定一個(gè)IP地址作為參數(shù),這樣所有包都被轉(zhuǎn)發(fā)到同一臺(tái)機(jī)子。我們還可以在地址后指定一個(gè)或一個(gè)范圍的端口。比如:--to-destination 192.168.1.1:80或192.168.1.1:80-100。SNAT的語(yǔ)法和這個(gè)target的一樣,只是目的不同罷了。要注意,只有先用--protocol指定了TCP或UDP協(xié)議,才能使用端口。
因?yàn)镈NAT要做很多工作,所以我要再啰嗦一點(diǎn)。我們通過(guò)一個(gè)例子來(lái)大致理解一下它是如何工作的。比如,我想通過(guò)Internet連接發(fā)布我們的網(wǎng)站,但是HTTP server在我們的內(nèi)網(wǎng)里,而且我們對(duì)外只有一個(gè)合法的IP,就是防火墻那個(gè)對(duì)外的IP——$INET_IP。防火墻還有一個(gè)內(nèi)網(wǎng)的IP——$LAN_IP,HTTP server的IP是%HTTP_IP(當(dāng)然這是內(nèi)網(wǎng)的了)。為了完成我們的設(shè)想,要做的第一件事就是把下面這個(gè)簡(jiǎn)單的規(guī)則加入到nat表的PREROUTING鏈中:
iptables -t nat -A PREROUTING --dst$INET_IP -p tcp --dport 80 -j DNAT / --to-destination $HTTP_IP
現(xiàn)在,所有從Internet來(lái)的、到防火墻的80端口去的包都會(huì)被轉(zhuǎn)發(fā)(或稱作被DNAT)到在內(nèi)網(wǎng)的HTTP服務(wù)器上。如果你在Internet上試驗(yàn)一下,一切正常吧。再?gòu)膬?nèi)網(wǎng)里試驗(yàn)一下,完全不能用吧。這其實(shí)是路由的問(wèn)題。下面我們來(lái)好好分析這個(gè)問(wèn)題。為了容易閱讀,我們把在外網(wǎng)上訪問(wèn)我們服務(wù)器的那臺(tái)機(jī)子的IP地址記為$EXT_BOX。
包從地址為$EXT_BOX的機(jī)子出發(fā),去往地址為$INET_IP的機(jī)子。
包到達(dá)防火墻。
防火墻DNAT(也就是轉(zhuǎn)發(fā))這個(gè)包,而且包會(huì)經(jīng)過(guò)很多其他的鏈檢驗(yàn)及處理。
包離開(kāi)防火墻向$HTTP_IP前進(jìn)。
包到達(dá)HTTP服務(wù)器,服務(wù)器就會(huì)通過(guò)防火墻給以回應(yīng),當(dāng)然,這要求把防火墻作為HTTP到達(dá)$EXT_BOX的網(wǎng)關(guān)。一般情況下,防火墻就是HTTP服務(wù)器的缺省網(wǎng)關(guān)。
防火墻再對(duì)返回包做Un-DNAT(就是照著DNAT的步驟反過(guò)來(lái)做一遍),這樣就好像是防火墻自己回復(fù)了那個(gè)來(lái)自外網(wǎng)的請(qǐng)求包。
返回包好像沒(méi)經(jīng)過(guò)這么復(fù)雜的處理、沒(méi)事一樣回到$EXT_BOX。
現(xiàn)在,我們來(lái)考慮和HTTP服務(wù)器在同一個(gè)內(nèi)網(wǎng)(這里是指所有機(jī)子不需要經(jīng)過(guò)路由器而可以直接互相訪問(wèn)的網(wǎng)絡(luò),不是那種把服務(wù)器和客戶機(jī)又分在不同子網(wǎng)的情況)的客戶訪問(wèn)它時(shí)會(huì)發(fā)生什么。我們假設(shè)客戶機(jī)的IP為$LAN_BOX,其他設(shè)置同上。
包離開(kāi)$LAN_BOX,去往$INET_IP。
包到達(dá)防火墻。
包被DNAT,而且還會(huì)經(jīng)過(guò)其他的處理。但是包沒(méi)有經(jīng)過(guò)SNAT的處理,所以包還是使用它自己的源地址,就是$LAN_BOX(譯者注:這就是IP傳輸包的特點(diǎn),只根據(jù)目的地的不同而改變目的地址,但不因傳輸過(guò)程要經(jīng)過(guò)很多路由器而隨著路由器改變其源地址,除非你單獨(dú)進(jìn)行源地址的改變。其實(shí)這一步的處理和對(duì)外來(lái)包的處理是一樣的,只不過(guò)內(nèi)網(wǎng)包的問(wèn)題就在于此,所以這里交代一下原因)。
包離開(kāi)防火墻,到達(dá)HTTP服務(wù)器。
HTTP服務(wù)器試圖回復(fù)這個(gè)包。它在路由數(shù)據(jù)庫(kù)中看到包是來(lái)自同一個(gè)網(wǎng)絡(luò)的一臺(tái)機(jī)子,因此它會(huì)把回復(fù)包直接發(fā)送到請(qǐng)求包的源地址(現(xiàn)在是回復(fù)包的目的地址),也就是$LAN_BOX。
回復(fù)包到達(dá)客戶機(jī),但它會(huì)很困惑,因?yàn)檫@個(gè)包不是來(lái)自它訪問(wèn)的那臺(tái)機(jī)子。這樣,它就會(huì)把這個(gè)包扔掉而去等待“真正”的回復(fù)包。
針對(duì)這個(gè)問(wèn)題有個(gè)簡(jiǎn)單的解決辦法,因?yàn)檫@些包都要進(jìn)入防火墻,而且它們都去往需要做DNAT才能到達(dá)的那個(gè)地址,所以我們只要對(duì)這些包做SNAT操作即可。比如,我們來(lái)考慮上面的例子,如果對(duì)那些進(jìn)入防火墻而且是去往地址為$HTTP_IP、端口為80的包做SNAT操作,那么這些包就好像是從$LAN_IP來(lái)的了。這樣,HTTP服務(wù)器就會(huì)把回復(fù)包發(fā)給防火墻,而防火墻會(huì)再對(duì)包做Un-DNAT操作,并把包發(fā)送到客戶機(jī)。解決問(wèn)題的規(guī)則如下:
iptables -t -nat -A POSTROUTING -p tcp --dst$HTTP_IP --dport 80 -j SNAT / --to-source $LAN_IP
要記住,按運(yùn)行的順序POSTROUTING鏈?zhǔn)撬墟溨凶詈笠粋€(gè),因此包到達(dá)這條鏈時(shí),已經(jīng)被做過(guò)DNAT操作了,所以我們?cè)谝?guī)則里要基于內(nèi)網(wǎng)的地址$HTTP_IP(包的目的地)來(lái)匹配包。
警告:我們剛才寫(xiě)的這條規(guī)則會(huì)對(duì)日志產(chǎn)生很大影響,這種影響應(yīng)該說(shuō)是很不好的,因?yàn)閬?lái)自Internet包在防火墻內(nèi)先后經(jīng)過(guò)了DNAT和SNAT處理,才能到達(dá)HTTP服務(wù)器(上面的例子),所以HTTP服務(wù)器就認(rèn)為包是防火墻發(fā)來(lái)的,而不知道真正的源頭是其他的IP。這樣, 當(dāng)它記錄服務(wù)情況時(shí),所有訪問(wèn)記錄的源地址都是防火墻的IP而不是真正的訪問(wèn)源。我們?nèi)绻敫鶕?jù)這些記錄來(lái)了解訪問(wèn)情況就不可能了。因此上面提供的“簡(jiǎn)單辦法”并不是一個(gè)明智的選擇,但它確實(shí)可以解決“能夠訪問(wèn)”的問(wèn)題,只是沒(méi)有考慮到日志而已。
其他的服務(wù)也有類似的問(wèn)題。比如,你在LAN內(nèi)建立了SMTP服務(wù)器,那你就要設(shè)置防火墻以便能轉(zhuǎn)發(fā)SMTP的數(shù)據(jù)流。這樣你就創(chuàng)建了一個(gè)開(kāi)放SMTP的中繼服務(wù)器,隨之而來(lái)的就是日志的問(wèn)題了。
一定要注意,這里所說(shuō)的問(wèn)題只是針對(duì)沒(méi)有建立DMZ或類似結(jié)構(gòu)的網(wǎng)絡(luò),并且內(nèi)網(wǎng)的用戶訪問(wèn)的是服務(wù)器的外網(wǎng)地址而言的。(譯者注:因?yàn)槿绻⒌腄MZ,或者服務(wù)器和客戶機(jī)又被分在不同的子網(wǎng)里,那就不需要這么麻煩了。因?yàn)樗性L問(wèn)的源頭都不在服務(wù)器所在的網(wǎng)里,所以就沒(méi)有必要做SNAT去改變包的源地址了,從而記錄也就不是問(wèn)題了。如果內(nèi)網(wǎng)客戶是直接訪問(wèn)服務(wù)器的內(nèi)網(wǎng)地址那就更沒(méi)事了)
比較好的解決辦法是為你的LAN在內(nèi)網(wǎng)建立一臺(tái)單獨(dú)的DNS服務(wù)器(譯者注:這樣,內(nèi)網(wǎng)客戶使用網(wǎng)站名訪問(wèn)HTTP服務(wù)器時(shí),DNS就可以把他解析成內(nèi)網(wǎng)地址??蛻魴C(jī)就可以直接去訪問(wèn)HTTP服務(wù)器的內(nèi)網(wǎng)地址了,從而避免了通過(guò)防火墻的操作,而且包的源地址也可以被HTTP服務(wù)器的日志使用,也就沒(méi)有上面說(shuō)的日志問(wèn)題了。),或者干脆建立DMZ得了(這是最好的辦法,但你要有錢哦,因?yàn)橛玫脑O(shè)備多?。?br /> 對(duì)上面的例子應(yīng)該考慮再全面些,現(xiàn)在還有一個(gè)問(wèn)題沒(méi)解決,就是防火墻自己要訪問(wèn)HTTP服務(wù)器時(shí)會(huì)發(fā)生什么,能正常訪問(wèn)嗎?你覺(jué)得呢:)很可惜,現(xiàn)在的配置還是不行,仔細(xì)想想就明白了。我們這里討論的基礎(chǔ)都是假設(shè)機(jī)子訪問(wèn)的是HTTP服務(wù)器的外網(wǎng)地址,那客戶機(jī)就會(huì)看到頁(yè)面內(nèi)容,不過(guò)這不是它想看到的(它想要的在DNAT上了),如果沒(méi)有HTTP服務(wù),客戶就只能收到錯(cuò)誤信息了。前面給出的規(guī)則之所以不起作用是因?yàn)閺姆阑饓Πl(fā)出的請(qǐng)求包不會(huì)經(jīng)過(guò)那兩條鏈。還記得防火墻自己發(fā)出的包經(jīng)過(guò)哪些鏈吧:) 我們要在nat表的OUTPUT鏈中添加下面的規(guī)則:
iptables -t nat -A OUTPUT --dst$INET_IP -p tcp --dport 80 -j DNAT / --to-destination $HTTP_IP
有了最后這條規(guī)則,一切都正常了。和HTTP服務(wù)器不在同一個(gè)網(wǎng)的機(jī)子能正常訪問(wèn)服務(wù)了,和它在一個(gè)網(wǎng)內(nèi)的機(jī)子也可以正常訪問(wèn)服務(wù)了,防火墻本身也可以正常訪問(wèn)服務(wù)了,沒(méi)有什么問(wèn)題了。 我想大家應(yīng)該能明白這些規(guī)則只是說(shuō)明了數(shù)據(jù)包是如何恰當(dāng)?shù)谋籇NAT和SNAT的。除此之外,在filter表中還需要其他的規(guī)則(在FORWARD鏈里),以允許特定的包也能經(jīng)過(guò)前面寫(xiě)的(在POSTROUTING鏈和OUTPUT鏈里的)規(guī)則。千萬(wàn)不要忘了,那些包在到達(dá)FORWARD鏈之前已經(jīng)在PREROUTING鏈里被DNAT過(guò)了,也就是說(shuō)它們的目的地址已經(jīng)被改寫(xiě),在寫(xiě)規(guī)則時(shí)要注意這一點(diǎn)。