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