Linux 2.4 NAT HOWTO 簡體中文版(轉)

post0發表於2007-08-10
Linux 2.4 NAT HOWTO 簡體中文版(轉)[@more@]

Rusty Russell, mailing list netfilter@lists.samba.org

$Revision: 1.3 $ $Date: 2002/06/05 13:21:56 $

簡體中文:洋鬼鬼·NetSnake

感謝 網中人netmanforever@yahoo.com 提供的繁體參照

此文件說明如何進行偽裝、透明代理、埠轉發,和基於Linux 2.4核心其他型別的 網路地址轉換(Network Address Translations)。

1. 簡介

2. 官方站點及列表

2.1 什麼是NAT?

2.2 我為什麼需要NAT?

3. NAT的兩種型別

4. 從2.0和2.2核心的快速轉換

4.1 我只想偽裝!救命!

4.2 關於ipmasqadm

5. NAT可以控制什麼

5.1 用iptables做簡單的選擇

5.2 關於應當挑選哪些包來拆分(mangle)的要點

6. 說說如何拆分包吧

6.1 源地址NAT

6.1.1 偽裝

6.2 目的地址NAT

6.2.1 重定向

6.3 深層次的對映

6.3.1 一個範圍內多地址的選擇

6.3.2 建立空的NAT對映

6.3.3 標準NAT行為

6.3.4 內部源埠對映

6.3.5 如果NAT失敗會怎樣?

6.3.6 多重對映,重疊和衝突

6.3.7 修改本地生成的連線的目標地址

7. 特定的協議

8. 關於NAT的警告

9. 源地址NAT和選路

10. 同一網路內的目標地址NAT

11. 感謝

1. 簡介

歡迎,親愛的讀者。

你將要深入迷人的(有時是令人厭煩的)NAT世界:網路地址轉換,這篇HOWTO可以成為你的Linux2.4核心及其以後的準確指南。

在Linux2.4(核心版本),引入了一個叫“netfilter”的部分,專門用於拆分(mangling) (IP)包的。他上一層提供NAT,是完全依靠以前的核心製作的。

(譯者注:mangle實在找不出什麼合適的翻譯,抱歉)

(C) 2000 Paul `Rusty' Russell. Licensed under the GNU GPL.

2、 官方站點及列表位置

這裡有三個官方站點:

o Thanks to Filewatcher

o Thanks to The Samba Team and SGI

o Thanks to Harald Welte

你可以透過以下站點訪問全部相關站點。

and

以下是netfilter官方郵件列表

/contact.html#list.

2、1 什麼是網路地址轉換(Network Address Translation)?

通常,,網路中的(IP)包從他們的源(地址)出發(比如你家的電腦),到他們的目的地(比如),會經過很多不同的連線(links):例如我所在澳大利亞就有19個。這些連線不會真去修改你的包:他們只是照原樣傳出去。

(譯者注:這裡的links應當認為是所有網路節點,包括主機、路由器等。通常,路由器並不是原樣傳送包,它至少會修改其中一點:TTL)

如果這些連線有一個做NAT,那麼它(們)就會修改透過它們的包的源或者目標(地址)。正如你猜象的那樣,這並非系統設計成那樣的,而是NAT做了一些事情。通常進行NAT的連線(主機、伺服器、路由器)會記住它是如何拆分包的,而當另一頭響應的包透過時,它會對響應的包做相反的拆分,所以世界仍在運轉。

(譯者注:這一段的mangle應該想象為修改更合適)

2、2 我為什麼要NAT?

在完美的世界裡,你不需要。同時,主要的理由是:

用調變解調器連線Internet

在你撥號上網時,大部分ISP只會給你一個IP地址,你可以傳送你想傳送的任何源地址包,但是隻有響應這個(ISP給你的)地址的包才會返回。如果這種情況下你想有多臺不同的機器上網(比如一個家庭網路),你就需要NAT。

這是現在NAT用得最多的功能,Linux世界的"masquerading"(偽裝)非常出名,我稱之為SNAT(SNAT即Source NAT,源地址轉換),因為你改變了第一個包的源地址。

(譯者:關於IP資料包的第一個包等內容,請參見各TCP/IP書籍)

多(重)伺服器

有時你想改變進入網路中的包的目標地址(路由)。經常的,這是因為(就像上面的例子),你只有一個IP地址,但是你希望大家可以透過到那個“真實”的IP地址進入內部。如果你重寫了進入包的目標地址,這樣就沒問題了。這種NAT在以前的Linux版本中被稱為埠轉發。

一個常見的變種是負載均衡,在一組機器上做對映。如果你要進行嚴格的比例限制, 可能需要參考Linux Virtual Server。

透明代理

有時你可能想要經過你的Linux的包被送往本機的一個程式。這就需要用到透明代理了:代理是位於你的網路和外部世界之間的一個程式,幫助二者進行通訊。之所以稱為透明,是你的網路根本不知道他在和代理交談,當然直到代理沒有正常工作。

Squid可以配置為幹這項工作,在以前Linux版本中它被稱作重定向或者透明代理。

3、 NAT的兩種型別

我把NAT分為兩種不同的型別:源NAT(SNAT)和目標NAT(DNAT)。(譯者注:以下不再翻譯SNAT和DNAT,直接用Source NAT和Destination NAT)

Source NAT是指修改第一個包的源地址:也就是說,改變連線的來源地。Source NAT會在包送出之前的最後一刻做好post-routing(動作),偽裝是SNAT的一種特殊形式。

Destination NAT 是指修改第一個包的目標地址:也就是說,改變連線的目的地。Destination NAT 總是在包進入以後(馬上)進行before routing(動作)。埠轉發、負載均衡和透明代理都屬於DNAT。

4、 從2.0和2.2核心的快速轉換

如果你還在為從2.0(ipfwadm)到2.2(ipchains)的轉換手忙腳亂的話,很抱歉。不過這也算是個喜憂半參的訊息。

首先,你可以輕鬆的使用ipchains和ipfwadm,就像從前一樣。不過你需要安裝最新發布的netfilter中的“ipchains.o”或者“ipfwadm.o”核心模組。它們是互斥的(你會被警告),而且不能和任何其他netfilter模組結合。

一旦這其中某個模組被載入,你可以像以前一樣使用ipchains和ipfwadm,不過仍有以下區別:

用ipchains -M -S,或者用ipfwadm -M -s設定偽裝超時不再有效。因為超時已經轉移到新的NAT構架中,所以這不能做任何事。

在詳細的偽裝列表中,init_seq、delta和previous_delat欄位始終為零。

歸零和列表計數器的 -Z -L不再有效:計數器不能被歸零。

這類向後相容的部分可能和大部分連線都不能有效配合:不要在你的公司閘道器中使用

開發者們還要注意:

無論是否使用偽裝,現在可以繫結61000 - 65095之間的埠。以前的偽裝程式碼佔用了這部分埠,因此不能使用。

尚未成文的“getsockname”,透明代理程式可以用來發現那些已不再工作的連線的真實目的地址。

尚未成文的“bind-to-foreign-address”同樣還未啟用:這個用於完整透明代理的設想。

4、1 我只想偽裝!救命!

這是絕大部分人想要的。如果你用PPP撥號上網來動態得到IP (如果你不知道,那應該就是的)你可能只想告訴你的機器,所有來自內部網路的包,要看上去同PPP連線伺服器上的包一樣。

# 裝載NAT模組(這取代了其他的)

modprobe iptable_nat

# 在NAT表中(-t nat),路由後 POSTROUTING 加入一條規則(-A)

# 所有由ppp0送出的包(-o ppp0) 會被偽裝( -j MASQUERADE)。

iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

# 開啟IP轉發

echo 1 > /proc/sys/net/ipv4/ip_forward

注意這時你沒有做任何的包過濾:如果需要,參見 the Packet Filtering HOWTO。

4、2 那麼ipmasqadm呢?

這個完全取決於使用者,所以我不擔心向後相容的問題。你可以簡單的使用“iptables -t nat”做埠轉發。例如,在Linux2.2你要做:

# 在2.2核心,把指向1.2.3.4 8080埠的TCP包轉到192.168.1.1的80埠

ipmasqadm portfw -a -P tcp -L 1.2.3.4 8080 -R 192.168.1.1 80

現在你可以這樣:

# 2.4核心,在NAT(-t nat)表中加入一條規則,在路由之前(-A PREROUTING)指向

# 1.2.3.4(-d 1.2.3.4)8080埠(--dport 8080)的TCP包(-p tcp)目標地址(-j DNAT)

# 被重定向到 192.168.1.1的80埠(--to 192.168.1.1:80)。

iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 8080 -j DNAT --to 192.168.1.1:80

5、NAT可以控制什麼

你需要建立NAT規則,以告訴核心哪些連線將被改變和如何改變。要做到這一點,我們要用到一個用處很多的iptables工具,並告訴它用指定的“-t nat”選項修改NAT表。

NAT規則表包含三個稱為“鏈”的列表:每個規則都按順序檢查包,直到有一個匹配。其中兩個被稱為PREROUTING(用於 Destination NAT,當包進入時檢查),POSTROUTING(用於Source NAT,包離開時檢查),第三個叫OUTPUT,這裡可以忽略。

如果我有足夠的藝術天分的話,下面的見圖會準確的說明上述概念:

_____ _____

/ /

PREROUTING --&gt[Routing ]-----------------&gtPOSTROUTING-----&gt

D-NAT/ [Decision] S-NAT/

| ^

| |

| |

| |

| |

| |

| |

--------&gt Local Process ------

上述每一點,當我們檢視連線(中)的包時,如果是一個新的連線,我們檢視 NAT表中相對應的鏈,看看需要做些什麼。其結果就會作為對這個連線後面所有包 的反應。

(譯者注:此處的連線是指一個HTTP會話之類的連線,而非物理上的線路、節點)

5、1 用iptables做簡單的選擇

下面列出了iptables的一些標準選項。所有雙橫槓(--)的選項都是可以縮寫的。只要iptables可以將它們與其他選項區分開來就夠了。如果你的核心是以模組方式支援iptables的,你需要先用命令:insmod ip_tables來載入ip_tables.o

這是最重要的選項表格選擇,“-t”。對所有NAT操作,你都需要使用'-t nat'以指定NAT表。其次重要的是'-A',新增一個新的規則到鏈的末尾(例如'-A POSTROUTING'到POSTROUTING鏈),或者'-I'從最開始插入一個規則(例如'-I PREROUTING')。

你可以指定你想要進行NAT的包的源(地址)('-s' 或者'--source')和目的(地址)('-d' 或 '--destination')。這兩個選項可以跟單個IP地址(例如192.168.1.1),一個名字(例如),或者一個網路地址(例如192.168.1.0/24或192.168.1.0/255.255.255.0[譯者:這二者是等價的,只是表示方法不同])。

你可以指定進入或送出的匹配介面。不過能否指定取決於你想要寫入規則的那個鏈:PREROUTING鏈你只能選擇進入介面,POSTROUTING你只能選擇送出介面。如果用錯了,iptables會給出一個錯誤。

5、2 關於應當挑選哪些包來拆分(mangle)的要點

我上面說了你可以指定源地址和目標地址。如果忽略源地址選項,那麼所有源地址都會被匹配,同樣,如果忽略目標地址,所有目標地址都將被匹配。

你還可以標出一個指定的協議('-p'或'--protocol'),諸如TCP或者UDP;那麼只有這類協議的包會被匹配。這麼做的主要原因是指定了協議,就可以增加額外的選項:指定'--source-port'源埠和'--destination-port'目的埠選項(可縮寫為'-sport'和'-dport')。

這些選項讓你可以只匹配那些特定源埠及目標埠的包。這些對於重定向Web請求(TCP 80或8080埠)而不影響其他包非常有用。

這些選項必須跟在'-p'選項後面(這可能會對載入該協議的連線庫有一定影響)。你可以使用埠號,或者來自/etc/serverices檔案的(埠)名。

所有這些你可以對一個包作出的不同選擇都詳細的列在那詳細得可怕的使用手冊中了(man iptables)。(譯者注:參見iptables man page中文版)

6、說說如何拆分包吧

現在我們知道如何選擇我們想要拆分的包了。為完成我們的規則,我們需要準確的告訴核心我們想要它如何做。

6、1 Source NAT

你想要進行Source NAT,改變連線的源地址。這在POSTROUIING鏈中完成,就在它將送出去的最後一刻。這是一個重要的細節,所有Linux本機上的其他任何東西(路由、包過濾)都會看見那個尚未改變的包。也意味著'-o'(送出介面)選項可用了。

用指定'-j SNAT'來進行Source NAT,'--to-source'選項指定一個或一段IP地址,(加上)一個或一段可選的埠號(只能用於UDP和TCP協議)。

# 改變源地址為1.2.3.4

# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4

# 改變源地址為1.2.3.4、1.2.3.5或者1.2.3.6

# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6

# 改變源地址為1.2.3.4,埠1-1023

# iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023

6、1、1 偽裝

Source NAT的一個特例被稱作偽裝。它只能被用於動態分配IP地址的情況。例如標準撥號服務(靜態IP地址請用SNAT)。

你無需為IP偽裝明確指定源地址。它會使用包送出的那個介面(地址)作為源地址。不過更重要的是,如果那個線路關閉了的話,連線(無論如何都會丟失了)會被忘掉,意味著啟用新的IP後返回的包就會有點問題了(指那些響應掉線前發出的包的包)。

# 偽裝所有由ppp0送出的東西

# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

6、2 Destination NAT

用於PREROUTING鏈,包剛剛進入的時候。意味著本機上的任何東西看見的都是“真正”的目的地(譯者注:即已修改過的目的地址)。也意味著'-i'(進入介面)可用了。

用指定'-j DNAT'來進行Destination NAT,'--to-destination'選項指定定一個或一段IP地址,(加上)一個或一段可選的埠號(只能用於UDP和TCP協議)。

# 改變目標地址為5.6.7.8

# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8

# 改變目標地址為5.6.7.8、5.6.7.9或5.6.7.10

# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8-5.6.7.10

# 改變Web傳送的目標地址為5.6.7.8,8080埠

# iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT --to 5.6.7.8:8080

6、2、1 重定向

Destination NAT的一個特例被稱為重定向。它相當於對進入介面進行DNAT的簡單方便的一種形式。

# 傳送進入的80埠的Web傳輸到我們的Squid(透明)代理

# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 3128

注意Squid需要被配置為透明代理。

6、3 深層次的對映

還有一些可能大部分人不會用到的NAT的細節。

6、3、1 一個範圍內多地址的選擇

如果指定了IP地址的範圍,那麼機器會選擇當前使用最少的那個IP地址。這就實現了最儉樸的負載均衡。

6、3、2 建立空的NAT對映。

你可以使用 '-j ACCEPT' 目標讓連線透過,不需要NAT參與。

6、3、3 標準NAT行為

預設行為是根據使用者給定的內在約束規則,對連線作最小的改動。也就是除非必要 不要進行埠重對映。

6、3、4 內部源埠對映

如果其他的連線覆蓋了一個連線,即使這個連線不需要使用NAT,源地址轉換仍會發生。考慮IP偽裝,這種情況就非常普遍。

1、一個從192.168.1.1 1024埠到 80埠的Web連線已建立

2、它被偽裝成IP偽裝伺服器的IP地址(1.2.3.4)

3、IP偽裝伺服器試圖建立一個從 80埠到1.2.3.4 1024埠的Web連線(它自己的外部介面IP地址)

4、NAT程式碼會修改第二個連線的源地址到1025,這樣兩個(連線)就不會衝突了。

當這種內部源地址對映發生時,埠分為三級:

512以下的埠

512至1023之間的埠

1024以上的埠

內部埠對映決不會被對映到(除此之外的)其他種類。

6、3、5 如果NAT失敗會怎樣?

如果無法按照使用者請求的那樣,為連線建一個單獨的對映,(包)會被刪除。這也適用於那些無法被歸為任何連線的包,因為它們是畸形的,或者是主機記憶體溢位了。

6、3、6 多重對映,重疊和衝突

你的NAT規則可以把包對映到相同的範圍。NAT程式碼聰明到可以避免它們的衝突。因此,兩條規則把192.168.1.1和192.168.1.2的源地址對映都對映到1.2.3.4是沒有問題的。

而且,你可以對映到真實的、已在使用的IP地址,只要那些地址也透過這個伺服器。所以如果你分配到一個網路(1.2.3.0/24),但有一個內部網路使用了這些地址,另一個使用的是私有地址192.168.1.0/24,你可以簡單的NAT 192.168.1.0/24的源地址 到1.2.3.0網路,不必擔心衝突。

# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0/24

相同的邏輯也適用於NAT伺服器本身的地址。這就是得以偽裝工作的原因(由偽裝後的包和來自本身的“真實”的包共享一個介面地址)。

甚至,你可以對映相同的包到許多不同的目標,它們會被共享。例如,如果你不希望對映任何東西到1.2.3.5,你可以這樣做:

# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0-1.2.3.4 --to 1.2.3.6-1.2.3.254

6、3、7 修改本地生成的連線的目標地址

NAT程式碼允許你插入DNAT規則到OUTPUT鏈,不過這在2.4中尚未完全支援(可以使用,但必須用新的配置選項,某些測試中的程式碼。所以除非有人在瘋狂的寫這部分程式碼,我不相信它會很快實現)。

當前的限制是你只能修改目標地址到本機(例如'-j DNAT --to 127.0.0.1'), 不能到任何其他機器,否則相應可能不能夠被正確轉換。

7、 特定的協議

有些協議不希望被NAT。這些協議,兩種延伸必須指明:一個是協議的連線跟蹤,一個是真實NAT。

在釋出的netfilter中,有可用的FTP模組:ip_conntrack_ftp.o和ip_nat_ftp.o。如果你載入了任一種模組到你的核心(或者編譯進去),那麼任何關於FTP連線的NAT都是可行的。如果沒有,那麼只能使用被動FTP(passive ftp),而且如果做了一些Source NAT,它(指FTP)也許不能可靠的工作。

8、 關於NAT的警告

如果你對連線做NAT,所有雙向傳送的包(進入和送出網路的)必須透過NAT伺服器,否則NAT伺服器的工作可能不可靠。特別是,連線跟蹤程式碼重組了分片,也就意味著不光是連線跟蹤不能可靠工作,甚至所有包都無法透過,因為分片被丟棄。

9、 Source NAT 和路由

如果你要做SNAT,你必須注意所有機器被SNAT的包的回應都將傳送到NAT伺服器。例如,如果你對映了一些送出的包的源地址為1.2.3.4,那麼外部的路由器必須知道傳送回應包的地址到NAT伺服器。可以這樣做:

1、如果你對本機地址做SNAT(路由等所有事情都正常),你不需要做任何事。

2、如果你在本地LAN上做SNAT到未用地址(例如,你對映為1.2.3.99,你的1.2.3.0/24網路中未用的IP),你的NAT伺服器需要像那個地址(99)一樣正確響應ARP請求。最簡單的辦法是建立一個IP別名,例如:

# ip address add 1.2.3.99 dev eth0

3、如果你對完全不同的地址做SNAT,你必須保證被SNAT的包到達的機器會返回NAT伺服器。如果NAT伺服器是它們的預設閘道器,那麼就已經行了,否則你需要釋出一個路由(如果執行了路由協議)或者對每個機器手工新增路由。

10、 同一個網路內的Destination NAT。

如果你要對同一個網路做埠轉發,你需要確認所有以後的包和回應包都透過NAT伺服器(這樣它們才能被修改)。NAT程式碼現在(自2.4.0-test6),會遮蔽掉同組的被NAT的包送出的ICMP重定向,不過收到的伺服器會繼續嘗試直接響應客戶。(不會理解這個回應)

經典的情況是,內部人員試圖訪問你的“公用”Web伺服器,而它實際上從公用地址(1.2.3.4)被DNAT到內部機器(192.168.1.1),例如:

# iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j DNAT --to 192.168.1.1

一種辦法是執行一臺內部DNS伺服器,它知道你的公用(外部)Web伺服器的真實的(內部)IP地址,並轉發所有其他請求到外部DNS伺服器。也就是說你的Web伺服器能夠記錄真實的內部IP地址。

另一種辦法是讓NAT伺服器對映那些連線的源地址到它自己,讓伺服器透過它發出響應。例如,我們可以這樣做(假設NAT伺服器內部IP地址是192.168.1.250):

# iptables -t nat -A POSTROUTING -d 192.168.1.1 -s 192.168.1.0/24 -p tcp --dport 80 -j SNAT --to 192.168.1.250

因為PREROUTING規則會首先執行,對內部Web伺服器來說,包的去向早已確定。我們可以確定好源IP地址。

11. Thanks

Thanks first to WatchGuard, and David Bonn, who believed in the netfilter idea enough to support me while I worked on it. And to everyone else who put up with my ranting as I learnt about the ugliness of NAT, especially those who read my diary.

首先感謝在我工作期間相信netfilter設想並支援我的WatchGuard和David Bonn。以及所有對NAT提出指正的朋友,尤其是讀過了我的日記的。

Rusty

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-940768/,如需轉載,請註明出處,否則將追究法律責任。

相關文章