Linux中IP隧道的分析與建議
----隨著計算機網路的日益普及,網路的安全成為目前的熱門話題。本文以Linux 2.0.34(RedHat5.2採用)為基礎,對隧道技術進行分析,並側重安全領域對在Linux環境下利用隧道技術實現虛擬專網提出建議。
----為什麼需要IP隧道?沒有接觸過這個概念的人自然會提出這樣的疑問。實際上概念最初的提出很簡單,就是為了在TCP/IP網路中傳輸其他協議的資料包。設想一下IPX協議或X.25封裝的資料包如何通過Internet網進行傳輸,在已經使用多年的橋接技術中是通過在源協議資料包上再套上一個IP協議頭來實現的,形成的IP資料包通過Internet後卸去IP頭,還原成源協議資料包,再傳送給目的站點。對源協議資料來說,就如同被IP帶著過了一條隧道。這種技術在業餘無線網路(Amateur Packet Radio Network)中得到了廣泛的應用,目前的移動式IP(mobileIP)技術已經在此基礎上得到了很好的發展。
----利用IP隧道來傳送的協議包也包括IP資料包,本文主要分析的IPIP封包就是如此。所謂IPIP,就是把一個IP資料包又套在一個IP包裡。為什麼要這麼做呢?其實並非多此一舉。見過一些應用就會明白,移動IP(Mobile-IP)和IP多點廣播(IP-Multicast)是兩個典型的例子。目前,IP隧道技術在構築虛擬專網(VPN,Virtual Private Network)中也顯示了出極大的生命力。本文也將對利用IP隧道技術構築VPN做簡單設想。
IP隧道的多種理解和實現
----Internet的研究者多年前就感到需要在網路中建立隧道,最初的理解是在網路中建立一條固定的路徑,以繞過一些可能失效的閘道器。可以說,隧道就是一條特定的路徑。這樣的隧道是通過IP報頭中的源路由選項來實現的。在目前看來,這種方法的缺陷十分明顯。要設定源路由選項就必須知道資料包要經過的確切路徑,而目前多數路由實現中都不支援源路由。
----另一種實現隧道的機制是開發一種新的IP選項,用來表明源資料包的資訊,原IP頭可能成為此選項的一部分。這種隧道的意義與我們所說的隧道已十分接近。但它的不足在於要對目前IP選項的實現和處理做較大的修改,此外它還缺乏靈活性。
----最常用的一種實現方法是開發一種新的IP封包(encapsulation)協議,仍然套用當前的IP頭格式。通過IP封包,不須指明網路路徑,封包就能透明地到達目的地。也可以通過封包空間把未直接連線的機器綁在一起,從而建立虛擬網路。這種方法易行、可靠、可擴充套件性強。Linux採用了這一方法,這就是目前我們所理解的隧道思想。
封包協議結構
----封包協議的實現原理十分簡單,從圖一中可以看到通過隧道傳送的資料報在網路中是如何流動的。為了敘述簡便,下文中把在隧道中傳送的IP資料包稱為封包。
圖一封包協議實現模型
----圖一中的裝置#都處於隧道的兩端(中間的(#)裝置只做簡單的轉發),分別起打包(封裝)和解包(解封)的作用。在整個資料包的傳送路徑中,除了隧道兩端的#裝置,其他閘道器把資料包看成一個普通的IP包進行轉發。裝置#就是一個基於封包的兩個實現部件———封裝部件和解封部件。封裝和解封部件(裝置)都應當同時屬於兩個子網。封裝部件對接收到的資料報加上封包頭,然後以解封部件地址作為目的地址轉發出去;而解封部件則在收到封包後,還原為資料報,轉發到目的子網。
----隧道的源端(封裝部件)對進入隧道的資料包進行封裝,形成封包。圖二是一個完整的封包示意圖。
圖二封包結構
Linux封包實現
----在Linux中,隧道的實現主要涉及兩個檔案:new-tunnel.c和ipip.c。另外,Linux還定義了一種新的協議型別———IPIP(IPPROTO-IPIP),它類似於上面所說的封包型別。
----在Linux中IP Tunnel的實現也分為兩個部件:封裝部件和解封部件,分別司職傳送和接收。但這兩個部件是在不同的層次上以不同的方式實現的。
----封裝部件是在資料鏈路層以虛裝置的方式實現的,所有原始碼見:
/usr/src/linux/drivers/net/new-tunnel.c
----為實現封裝,Linux實現一個稱為tunl的網路裝置(類似於loopback裝置),它具有其他網路裝置共有的特徵。對於使用此裝置的上層應用來說,對這些網路裝置不加區分,呼叫及處理方法當然也完全一樣。
----new-tunnel.c中的兩個主要過程是tunnel-init()和tunnel-xmit(),其中tunnel-init()初始化與裝置tunl相關的device結構,而tunnel-xmit()在從tunl裝置傳送資料時被呼叫,tunl裝置作為實現IP隧道技術的封裝部分,在此過程中完成對相應的資料報進行封裝所需的全部操作,形成IPIP型別的IP包,並重新轉發此資料包(ip-forward())。
----解封部件在IP的上層實現,系統把它作為一個虛的傳輸層(實際上與傳輸層毫無關係),具體處理見檔案:
/usr/src/linux/net/ipv4/ipip.c。
----我們知道,每一個IP資料包均交給ip-rcv函式處理,在進行一些必要的判斷後,ip-rcv對於傳送給本機的資料包將交給上層處理程式。對於IPIP包來說,其處理函式是ipip-rcv(與TCP包的處理函式tcp-rcv一樣,IP層不加區分)。也就是說,當一個目的地址為本機的封包到達後,ip-rcv函式進行一些基本檢查併除去IP頭,然後交由ipip-rcv解封。
----ipip-rcv的作用就是去掉封包頭,還原資料包,然後把還原後的資料包放入相應的接收佇列(netif-rx())中。
----上述的IPTunnel實現思路十分清晰,但由於IP Tunnel的特殊性,其實現的層次並不單純。它的封裝和解封部件不能簡單地像上面所說的那樣分層。tunl裝置雖然應算進鏈路層,但其傳送程式還做了很多其他的工作,如製作IPIP頭及新的IP頭(這些一般認為是傳輸層或網路層的工作)。呼叫ip-forward轉發新包也不是一個網路裝置應當做的事。可以說,tunl借網路裝置之名,做的工作卻很多,因此相當“高效”。而解封部件巨集觀上看在網路層之上,解出IPIP頭,恢復原資料包是它分內的事,但在它解出資料包(即原完整的協議資料包)後,它把這個包放入相應的協議接收佇列。這項任務可不是一個上層協議乾的,這是網路裝置中斷接收程式的義務。在這點上,它好像又到了資料鏈路層。隧道機制就是這樣的。
為實現VPN的擴充套件
----實際上Linux只為實現隧道機制提供了一個框架,圖二中的封包協議頭在Linux中被忽略了,也就是說,封包頭只含封包IP頭,其後緊跟原IP資料包。這樣的結構用於傳輸公開資料沒有關係,但對於一個VPN來說,安全保密是不可缺少的重要功能。我們希望通過隧道的資料可靠且不可竊取或假冒,因此加密和認證就必不可少。為實現這一構想,可設計以下封包協議頭:
圖三IPIP頭設想圖
----其中type用於建立不同目的的隧道(可能處理上有差別),OldPacketLen是進入隧道的原資料包長度,DeviceID是對資料包進行封裝的裝置標識,EncapID是此封包的ID號,Flags是標誌位,初步定義如下:
0 保留
1 有否加密
2 有否做摘要
3 有否簽名
4 保留
5 是否傳送訊息金鑰
6 訊息金鑰是否加密
7 訊息金鑰是否需保留
8-15 保留
----IPIP Options用來傳送一些必要的資料,比如訊息金鑰、簽名等,其格式為,
類 型
長 度
數 據
----有了上述定義,就可以擴充套件Linux IP Tunnel為VPN服務了。首先,改寫new-tunnel.c和ipip.c兩個檔案,加入對IPIP頭的處理。然後,要實現一種金鑰的管理和傳送機制。當然,對稱金鑰是必需的,而對IP資料包加密要使用序列密碼。
----在一個VPN的隧道中,一個封包的格式應如圖四所示。
圖四VPN封包結構
----針對上述構想,通過對安全強度和通訊速度的權衡,可以採用從不加密但速度快到高度機密但速度慢等不同的策略。當然還可以就加密強度本身作出選擇,比如選擇128位還是512位、1024位的加密演算法。
----當然,該方案在錯誤檢測等方面還有需要完善的地方