Internet的最初設(shè)計,并沒有考慮到需要支持目前這樣龐大的互聯(lián)網(wǎng),因此在IPv4的設(shè)計當中,IP地址僅使用了32bit來標識網(wǎng)絡(luò)中的一個節(jié)點設(shè)備,雖然這很好地解決了IP數(shù)據(jù)報的對齊問題,但隨著Internet的迅猛發(fā)展,加上一些不合理的地址分配方式,目前IP地址已嚴重缺乏,IP地址短缺已成為目前Internet所面臨的最大問題之一。
為了節(jié)約IP地址資源,IETF拋棄了傳統(tǒng)的地址分類方式(把IP地址空間人為地劃分為A、B、C、D類地址的方式)。開始使用在RFC 1918中指定的CIDR(Classless Inter-Domain Routing)。同時為了解決IP地址耗損的問題,在RFC 1631中提出了使用NAT來解決共用IP地址訪問Internet的問題。
1 NAT 概況
NAT是把一個網(wǎng)絡(luò)中使用的IP地址翻譯成能被另一個網(wǎng)絡(luò)識別的IP地址。一個網(wǎng)絡(luò)被指定為內(nèi)部網(wǎng)絡(luò),另一個為外部網(wǎng)絡(luò)。通常,一個公司把自己的本地內(nèi)部網(wǎng)絡(luò)地址映射到一個或多個全局外部IP地址,并把收到的包中的全局IP地址解釋成本地IP地址。這也有助于安全,因為每個出去和進來的請求都必須經(jīng)過一個翻譯過程,這是一個認證請求或把它與以前請求匹配的過程。
NAT包含在路由器中,通常也是防火墻的一部分。網(wǎng)絡(luò)管理員創(chuàng)建一個NAT表,用它來實現(xiàn)全局到本地和本地到全局地址的映射。NAT也可以和策略利用路由一起使用。NAT可以靜態(tài)定義,也可以根據(jù)IP地址池動態(tài)進行。
NAT的描述詳見RFC 1631。它討論了NAT與CIDR的關(guān)系,這是一個解決IP地址耗盡的方法。NAT通過區(qū)別公共IP地址和私有IP地址而減少了對公共IP地址的需求。CIDR把公共IP地址聚集在一起,減少了IP地址的浪費。
2 NAT 原理
在傳統(tǒng)的標準的TCP/IP通信過程中,所有的路由器僅僅是充當一個中間人的角色,也就是通常所說的存儲轉(zhuǎn)發(fā),路由器并不會對轉(zhuǎn)發(fā)的數(shù)據(jù)包進行修改,比如對于以太網(wǎng)接口,路由器除了將源MAC 地址換成自己的MAC 地址以外,路由器不會對轉(zhuǎn)發(fā)的數(shù)據(jù)包做任何修改。NAT(Network Address Translate,網(wǎng)絡(luò)地址翻譯)恰恰是出于某種特殊需要而對數(shù)據(jù)包的源IP地址、目的IP地址、源端口、目的端口進行改寫的操作。
從原理的角度可以將NAT分成了兩種類型,即源NAT(SNAT)和目的NAT(DNAT),顧名思義,所謂SNAT就是改變轉(zhuǎn)發(fā)數(shù)據(jù)包的源地址,所謂DNAT就是改變轉(zhuǎn)發(fā)數(shù)據(jù)包的目的地址。
3 NAT 的VxWorks 實現(xiàn)
3.1 VxWorks的底層接口概況
3.1.1 VxWorks MUX 接口層
在VxWorks中,TCP/IP協(xié)議棧使用MUX接口去和數(shù)據(jù)鏈路層通信,MUX接口的目的是隔離數(shù)據(jù)鏈路層和網(wǎng)絡(luò)層。MUX接口之上是網(wǎng)絡(luò)協(xié)議層,比如TCP/IP、 MUX_PROTO_OUTPUT、 MUX_PROTO_SNARF等協(xié)議,在MUX之下為網(wǎng)絡(luò)硬件的驅(qū)動程序。MUX接口層提供一套接口去完成協(xié)議和驅(qū)動注冊,協(xié)議和驅(qū)動之間數(shù)據(jù)接收、發(fā)送,Multicast地址訪問,MUX ioctl等工作。整個層次結(jié)構(gòu)如圖1所示。
3.1.2 VxWorks 中對IP數(shù)據(jù)包的截獲
要在VxWorks中實現(xiàn)NAT,必須實現(xiàn)兩個基本操作:IP數(shù)據(jù)包的截獲與IP數(shù)據(jù)包的偽裝處理。
對于VxWorks協(xié)議棧來講,NAT的存在是透明的。所以,要實現(xiàn)NAT的功能,必須在VxWorks網(wǎng)絡(luò)協(xié)議棧處理數(shù)據(jù)包之前截獲數(shù)據(jù)。要實現(xiàn)這一點,VxWorks為我們提供了兩類鉤子函數(shù),截獲以太幀的EtherHook和截獲IP數(shù)據(jù)包的IpFilterHook。
其中EtherHook又包括EtherInputHook和EtherOutputHook,分別用來截獲接收和發(fā)送的以太幀。用戶可以通過EtherInputHookAdd和EtherOutputHookAdd來分別進行安裝。
而IpFilterHook提供對IP數(shù)據(jù)包的截獲,它只對應(yīng)一個鉤子函數(shù),用IpFilterHookAdd來進行安裝。當收到一個IP數(shù)據(jù)包的時候,IpFilterHook會被自動調(diào)用,從而達到對IP數(shù)據(jù)包截獲的目的。
對比兩種接口,EtherInputHookAdd將調(diào)用MuxBind去添加一個MUX_PROTO_SNARF協(xié)議,這樣可以得到進入MUX接口層的所有數(shù)據(jù)包。而由IpFilterHookAdd安裝的IpFilterHook,不屬于MUX接口層,僅僅用來截獲IP數(shù)據(jù)包,而不會接收到非IP數(shù)據(jù)包。
鑒于以上的區(qū)別,我們使用IpFilterHookAdd函數(shù)安裝的IpFilterHook來截獲IP數(shù)據(jù)包比較合適,參見圖2。
3.2 NAT偽裝策略
3.2.1 網(wǎng)絡(luò)接口
網(wǎng)絡(luò)接口是VxWorks的一個內(nèi)核對象,它是由網(wǎng)絡(luò)驅(qū)動程序注冊的。它在內(nèi)核中用于標識網(wǎng)絡(luò)設(shè)備的驅(qū)動程序,包含著該網(wǎng)絡(luò)設(shè)備特有的屬性、配置及操作接口等。而這個驅(qū)動程序可以驅(qū)動一個特定型號的網(wǎng)絡(luò)芯片,比如I82557,RTL 8139等,也可以驅(qū)動一些其他類型的設(shè)備,比如通過Serial Port、CompactPCI Bus、Loopback等。在VxWorks中,接收到的IP數(shù)據(jù)被保存在一個mBlk的結(jié)構(gòu)當中。該結(jié)構(gòu)除保存數(shù)據(jù)內(nèi)容外,還保存了管理數(shù)據(jù)內(nèi)容的信息結(jié)構(gòu)以及接口信息。
3.2.2 哪些IP數(shù)據(jù)包需要偽裝
在做NAT地址映射時,我們需要判斷對哪些IP包進行偽裝(NAT變換)。我們通過下面這個實例來進行講解(見圖3)。
在這個實例中,網(wǎng)關(guān)通過網(wǎng)絡(luò)接口If0連接到局域網(wǎng)中,并通過If1連接到Internet上,同時,網(wǎng)關(guān)啟用NAT功能。此時,位于局域網(wǎng)中的主機A如果想訪問Internet上10.2.4.0/24網(wǎng)段的主機B,最好的方法是通過網(wǎng)關(guān)上的NAT。
那么,具體哪些包需要進行NAT變換呢?我們先根據(jù)源地址和目的地址來劃分網(wǎng)關(guān)可能收到的包的類型。
?。?)接口If0收到的IP數(shù)據(jù)包,目的地址為網(wǎng)關(guān)If0接口的IP地址。
?。?)接口If0收到的IP數(shù)據(jù)包,目的地址為網(wǎng)關(guān)If1接口的IP地址。
?。?)接口If0收到的IP數(shù)據(jù)包,目的地址非網(wǎng)關(guān)任一接口的地址的私網(wǎng)IP地址。
?。?)接口If0收到的IP數(shù)據(jù)包,目的地址非網(wǎng)關(guān)任一接口的地址的公網(wǎng)IP地址。
?。?)接口If1收到的IP數(shù)據(jù)包,目的地址為If1接口的IP地址。
?。?)接口If1收到的IP數(shù)據(jù)包,目的地址非If1接口的IP地址。
對于前面3種情況,NAT不進行任何處理,直接交給VxWorks網(wǎng)絡(luò)協(xié)議棧,由協(xié)議棧來做進一步的處理。
對于第4種情況,符合NAT變換的需求,NAT將改變原IP包的源地址為網(wǎng)關(guān)的外出口地址,同時選擇網(wǎng)關(guān)該接口未分配的端口來修改原IP包中的源端口,并添加該記錄到NAT映射表內(nèi)。最后把IP包送到If1接口,然后發(fā)送到目的主機。
對于第5種情況,我們將收到的IP數(shù)據(jù)包送到NAT處理。通過查找NAT映射表,決定是否將其目標地址轉(zhuǎn)換為LAN中的某一個地址,還是不做任何處理,直接歸還給協(xié)議棧。對于第6種情況,我們這里也簡單地直接歸還給協(xié)議棧進行處理。
3.3 NAT 映射表及timer管理
3.3.1 NAT 映射表
對于每一個需要進行地址翻譯的IP數(shù)據(jù)包,內(nèi)核必須知道如何翻譯它。NAT 映射表就是用來解決這個問題的。NAT 映射表中記錄有足夠標識一個連接的所有信息:協(xié)議類型、源地址、源端口、目的地址、目的端口、NAT地址、NAT端口等。通過IP數(shù)據(jù)包中攜帶的信息可以在NAT表中找到最匹配的一項。在實現(xiàn)當中,我們采用表1的結(jié)構(gòu)來表示一個映射表項。
3.3.2 為什么NAT 映射表項需要設(shè)置timer
為了避免通過NAT進行通信的主機突然崩潰后,出現(xiàn)殘留的映射表項占據(jù)系統(tǒng)資源的情況。在每個NAT映射表項中,我們使用了一個軟件定時器來指示這個映射表項是否超時。如果在一段時間內(nèi)這個表項沒有被訪問過,從而導(dǎo)致定時器超時,NAT將清除這個表項,以減少系統(tǒng)資源消耗。在這個NAT的實現(xiàn)過程中,為了使TCP/IP協(xié)議棧能夠正常工作,針對不同的協(xié)議以及協(xié)議的不同階段,我們使用了不同的默認超時值。如表2所示。
3.4 NAT 映射表管理
3.4.1 NAT 映射表的創(chuàng)建、查找及刪除
在NAT的實現(xiàn)過程當中,如何快速地尋找一個IP包在NAT中是否有對應(yīng)的映射選項,需要一個高效的數(shù)據(jù)結(jié)構(gòu)和快速的查找算法。
在實現(xiàn)當中,我們選用采用索引查詢的散列表來作為存儲NAT映射表項的數(shù)據(jù)結(jié)構(gòu)。使用協(xié)議類型值、內(nèi)部網(wǎng)絡(luò)地址和端口來計算散列值,并結(jié)合映射表項的標志來確定需要做地址翻譯的IP數(shù)據(jù)包。
如果當前的IP數(shù)據(jù)包是外出的IP數(shù)據(jù)包,但是沒有匹配到一個合適的映射表項,那么NAT將建立一個新的映射表項,添加到散列表中。
如果當前的IP數(shù)據(jù)包是來自于外部網(wǎng)絡(luò)的,要么能夠匹配到一項合適的映射表項,要么目的端口已經(jīng)被配置為端口轉(zhuǎn)發(fā)(在這種情況下,NAT將依據(jù)端口轉(zhuǎn)發(fā)配置,在NAT映射表中靜態(tài)添加一個入口),否則,將不會改變這個IP數(shù)據(jù)包。
為了避免已經(jīng)出現(xiàn)異常的連接繼續(xù)占用系統(tǒng)資源,在每個映射表項的定時器超時后,其回掉函數(shù)將刪除存儲在散列表中的對應(yīng)的NAT映射表項。
3.4.2 如何互斥地訪問NAT映射表
在NAT映射表的處理和映射表項超時處理中,都需要對映射表進行查找、添加和刪除操作。為了安全地訪問映射表,我們必須同步對NAT映射表的訪問。在實現(xiàn)當中,我們使用了VxWorks提供的二進制信號量來保護對NAT映射表的操作。
3.5 TCP session state和TCP sequence number管理
3.5.1 TCP SYN/FIN/RST 狀態(tài)
對于一個TCP連接,如果NAT收到一個帶有RST標志的TCP數(shù)據(jù)包,我們將NAT映射表中對應(yīng)表項的定時器超時值置1,那么這個映射表很快將被刪除。如果收到一個FIN數(shù)據(jù)包,那么就重新設(shè)置對應(yīng)表項的定時器超時值為120s。否則,我們設(shè)置對應(yīng)映射表項的定時器超時值為5min。
3.5.2 TCP sequence number 調(diào)整
NAT的原理就是通過修改過往IP數(shù)據(jù)包的內(nèi)容,來達到偽裝IP數(shù)據(jù)包的目的。
在對部分基于TCP的應(yīng)用協(xié)議(如FTP)的數(shù)據(jù)包進行NAT變換時,如果由于應(yīng)用程序支持模塊改變了TCP數(shù)據(jù)包的內(nèi)容,導(dǎo)致數(shù)據(jù)包的長度發(fā)生變化,那么,為了使當前的TCP連接能夠繼續(xù)正常連接,就必須重新調(diào)整TCP的序列號(見圖4)。
TCP連接的序列號是在兩個方向上進行調(diào)整的。調(diào)整的原則如下:
如果外出的數(shù)據(jù)包長度減小,那么當前外出的TCP數(shù)據(jù)包的序列號將減小,反之則增加。
對于收到的來自于外部網(wǎng)絡(luò)的ACK 序列號,就要相應(yīng)地增加和減小了。
這里我們需要注意,由于VxWorks沒有使用Real Time來初始化TCP連接的初始序列號,而是使用一個固定的值來初始化它,導(dǎo)致每次重啟之后VxWorks的第一次TCP連接都會以相同的序列號開始遞增。由于VxWorks的TCP/IP協(xié)議棧的這種特征,我們在接收到TCP連接的第一個TCP數(shù)據(jù)包(帶有SYN標志,沒有ACK標志)時,要重新初始化已經(jīng)匹配的NAT映射表項,避免因為TCP連接序列號調(diào)整出錯。
3.6 端口轉(zhuǎn)發(fā)功能
3.6.1 為什么需要端口轉(zhuǎn)發(fā)功能
如果有某個處在Internet上的主機想訪問NAT服務(wù)器后的某個主機,這個連接必須已經(jīng)被記錄在NAT映射表中,但由于某些安全原因,NAT僅僅對由內(nèi)部網(wǎng)絡(luò)發(fā)起的網(wǎng)絡(luò)連接有效。當外部IP數(shù)據(jù)包進入允許NAT功能的接口時,如果NAT找不到合適的映射表項,IP數(shù)據(jù)包將交給VxWorks協(xié)議棧來處理。
為了使NAT能夠處理這種由外部網(wǎng)絡(luò)首先發(fā)起的網(wǎng)絡(luò)連接,NAT允許手工配置一些NAT的映射表項。這項功能就叫端口轉(zhuǎn)發(fā)。
3.6.2 端口轉(zhuǎn)發(fā)實現(xiàn)過程
由外到內(nèi)的IP包指的是從公網(wǎng)通過NAT發(fā)送到私有網(wǎng)絡(luò)的IP包。它的源IP是公共IP,目的IP是NAT的公共IP。當截獲到一個由外到內(nèi)的IP包時,NAT就以IP包的目的IP和目的Port加上包的協(xié)議類型作為NAT映射表項的匹配查詢條件進行搜索。如果找到一個對應(yīng)的表項,就用表項的Real Src IP和Real Src Port來替換IP包的目的IP和目的Port,而保持IP包的源IP和源Port不變。然后,重新計算TCP或UDP的校驗和,再計算IP頭的校驗和,最后把IP包重新歸還給VxWorks的網(wǎng)絡(luò)協(xié)議棧。如果在映射表中沒有搜索到對應(yīng)的表項,則對IP包不作任何處理,直接歸還給VxWorks網(wǎng)絡(luò)協(xié)議棧。
3.7 NAT配置接口
為了使NAT能夠適應(yīng)某些變化,我們在實現(xiàn)過程當中加入了對NAT的配置接口,主要對以下兩方面需要進行配置。
NAT接口配置:配置在那個允許NAT功能的網(wǎng)絡(luò)接口上。這個接口是和外部網(wǎng)絡(luò)相連的,有唯一的全局IP地址。
端口轉(zhuǎn)發(fā)映射表配置:配置NAT可以對那些由外部網(wǎng)絡(luò)發(fā)起的網(wǎng)絡(luò)連接進行地址轉(zhuǎn)換,以及如何進行地址轉(zhuǎn)換。
3.8 NAT如何處理IP分片
NAT本身還應(yīng)該考慮IP數(shù)據(jù)包的分片。但是在分片的IP數(shù)據(jù)包中,除了第一個IP數(shù)據(jù)包帶有源、目的端口信息以外,后續(xù)的IP分片都沒有端口信息。
這樣,IP數(shù)據(jù)包分片的這個特征給我們的NAT處理帶來了很多不便。因此,在這次的實現(xiàn)過程中,我們的NAT實現(xiàn)暫時不支持分片的IP數(shù)據(jù)包。
3.9 NAT的測試
如圖3所示,主機A通過NAT訪問主機B上的HTTP服務(wù)器,主機B通過手工配置在NAT上的映射表項訪問主機A上的TFTP服務(wù)器。
整個過程非常良好,TCP包和UDP包以及Port-Forward功能也成功得到了驗證。
4 NAT的未來
NAT這項技術(shù)主要是為了解決IP地址空間不足。在NAT功能的支持下,內(nèi)部網(wǎng)絡(luò)可以使用一個公共的IP地址訪問外部網(wǎng)絡(luò),因此,它很好地隱藏內(nèi)部網(wǎng)絡(luò)的網(wǎng)絡(luò)拓撲結(jié)構(gòu),也使網(wǎng)絡(luò)更安全。由于這些特點,NAT也常常是作為Firewall的重要部分一起提供的,但是它并不是Firewall。由于NAT可以帶來一定的安全性,相信即使在IPv6的時代,它還是能夠繼續(xù)應(yīng)用。
評論
查看更多