Linux平臺VPN技術概論

龍蝦天天發表於2017-05-08

第一部分.VPN要解決的問題以及方案

一.問題及方案

基於主機的第三層vpn的要旨就是“透明/安全的接入”,其中透明的含義就是配置要簡單,儘量讓使用者感覺不到vpn的存在,因此這種vpn的實現其實只要解決兩個問題即可:
1.如何拿到第N層資料,然後放回第M層;
2.加密/解密第三層ip資料包;

針對第一個問題,實際上我們依賴的是這樣一個事實,即OSI的分層網路模型,這樣才可以使第M層將第N層的PDU當成有效載荷,解析時只需要根據下層的協議號就可以定位上一層的協議型別。以封裝第三層資料的VPN為例,上述第一個問題在linux上有三種方案:

1.使用netfilter

使用netfilter無疑是最直接的方式,對於接收的包,需要在prerouting上掛載一個鉤子,對於本地發出的包,則需要在output上掛載一個鉤子,這樣就可以在鉤子函式中進行加密/解密處理了,處理完畢之後再根據策略封裝成一個新的ip資料包,重新路由並且傳送出去或者接收。


2.使用虛擬網路卡

這是一種不直接但是很自然的方式,因為,我們知道從網路卡出來的包一個包含一個IP資料包(暫不考慮其它三層協議,比如ipx)。實現一個虛擬網路卡,在其xmit傳送函式中處理加密,然後重新封裝,重新路由。這裡暫時先不考慮在哪裡解密,因為網路卡傳送和接收的邏輯是不一樣的,我們可以實現一個虛擬網路卡,然而卻不能修改ip協議棧,除非使用netfilter。


3.將IP資料包匯出到使用者態,比如使用packet套結字以及替換send/recv

這是最靈活的方案,然而如果使用packet的話卻不行。因為packet無法截獲資料包。因此需要在socket層次替換send/recv函式,實現加密/封裝以及解密/解封裝。這裡暫時不考慮send處理,因為對於一般的應用資料,是很難替換send的(Linux沒有windows的LSP機制),這種方式,控制接收較方便,而控制傳送則很難,和使用虛擬網路卡的情形正好相反。


我們發現,2和3是互補的,虛擬網路卡很容易拿到發出的未封裝的原始IP資料包-通過路由即可,但是拿不到接收的封裝過的IP資料包,而替換socket的send/recv則很容易拿到接收的封裝過的IP資料包但是拿不到傳送的未封裝的IP資料包。因此將2和3結合一下,就出現了第四種方式。接下來我們來討論vpn整體的設計。在架設vpn的時候,首先要明白三件事:
1.確定不安全通路的兩個端點。我們就在這兩個端點之間建立vpn通路;
2.要考慮到對forward資料包的支援,否則就沒有必要使用三層vpn了,使用應用層vpn即可。
3.隧道的概念。隧道其實就是vpn鏈路兩個端點之間的加密通路,其中封裝著加密後的原始IP資料包。

確定了vpn鏈路的端點以後,就可以根據上述的3種方式進行加密/封裝,解密/解封裝的操作了,也就是說,修建一條隧道。具體的方案如下:

方案1:採用netfilter的方式

這種方案部署起來比較簡單,因為端點的兩臺裝置是對稱的,netfilter鉤子會處理IPSec協議邏輯。成型的專案有Freeswan等,具體細節參見《FreeSWAN 結構框架》。

方案2:虛擬網路卡+udp

這種方案在端點兩端的加密/封裝,解密/解封裝是不對稱的,其中加密/封裝這步操作在虛擬網路卡完成,解密在recv邏輯中完成,解封裝在send邏輯中完成。成型的專案如cipe等。資料通路實際上就是虛擬網路卡的方式和匯出到使用者態方式的結合。


設計要點:
1.VPN隧道終點使用UDP埠區分了不同的IP安全通道,而不需要採用IPSec的方式;
2.為何不用TCP呢?因為會引起重傳疊加導致網路不可用,詳見CIPE的作者所做:《Why TCP Over TCP Is A Bad Idea》。同樣的規則在後續的OpenVPN中依然如此,詳見OpenVPN的man手冊中的--proto選項。
3.加密在核心態,解密在使用者態-使用UDP,之所以這樣的不對稱法是因為UDP埠是可以從客戶端“連線(訪問的含義)”的,不同的UDP埠就可以區分出來自不同地點的IP安全通道。這種方案依賴於,安全隧道總是由外部(位置不確定的網際網路的任意一處)先發起建立請求。後面的OpenVPN的C/S模型也有賴於這個事實。

二.VPN型別

vpn按照網路通路區分劃分為:

1.傳輸模式VPN

傳輸模式的VPN只加密資料,不構建隧道,也就是隻實現資料安全。如下圖所示,圖片來自cisco:

2.隧道模式VPN

隧道模式的VPN不但加密資料,但是構建隧道,也就是說實現網路層次PDU的封裝。如下圖所示,圖片來自cisco:

vpn按照認證方式區分可以使用不同的協議承載方式

1.PPPoE

嚴格來講,這不是一種VPN,而只是一種接入方式,它只是實現了在乙太網上承載ppp包。雖然它不屬於vpn的範疇,然而卻能表現隧道的思想,所謂隧道無非就是第m層的pdu用一種特定的隧道協議承載第n層的pdu,思想如下圖:


2.L2TP

L2TP是一個協議,使用這種協議的vpn用撥號來進行認證。如下圖所示,圖片來自華為:


3.SSL VPN

這種vpn使用證書,密碼等SSL認可的可配置的方式進行認證。它不一定是第四層vpn,也不一定是第七層vpn,而只是強調它使用SSL協議實現認證以及金鑰協商等安全策略。本文推崇的vpn也就是使用虛擬網路卡實現的ssl vpn。

第二部分.進一步的討論

一.問題

到此為止,vpn的兩個首要工作都得到了解決,使用虛擬網路卡,recv,或者netfilter抓住IP資料包,然後直接加密,也就是加密/封裝和解封裝/解密。但是加密的標準以及加密方式我們還沒有涉及,理論上,任何加密演算法都是可以對IP資料包進行加密的。
     實現VPN有多種方式,標準的方式是使用IPSec協議(ESP,AH等)來實現的,IPSec是一個封裝第三層資料包的協議集,也可以理解成一個第四層協議集,和tcp/udp等是完全並列的,tcp,udp的協議號分別為6和17,而esp,ah的協議號分別為50和51。總之IPSec協議集旨在第三層將資料直接進行加密/解密,要支援IPSec無疑需要對協議棧進行修改,在Linux,netfilter可以完成此任務,Freeswan正是這樣實現的IPSec。
     然而在核心態通過修改協議棧的實現方式很不靈活,配置起來也是比較複雜,如果能在使用者態實現資料包的加密/解密就比較好,這是完全可行的,因為IPSec協議集和TCP/UDP一樣也是第四層協議,完全可以用tcp或者udp來承載加密後的資料。既然使用虛擬網路卡可以方便的拿到IP資料包,那麼就可以想辦法匯出到使用者態,然後加密/解密後再發出去。

二.tap虛擬網路卡

     到此,我們明白IPSec只是加密/解密的支撐協議,和加密/解密沒有關係,並且這種方式對於配置和實現來講都不是很靈活,當然,這裡先不考慮效能因素。既然IPSec只是支撐協議,那也就是說只要能實現加密/解密,並且能實現將封裝後的資料包傳輸到vpn鏈路的對端就可以了。可是,又如何將虛擬網路卡抓取的ip資料包匯出到使用者態呢?
     前面提到,使用虛擬網路卡抓取IP資料包和使用替換socket的send/recv函式抓取資料包是矛盾且互補的,因此它們的結合對於封裝和解封裝的實現是不對稱的。
     tap網路卡的出現帶來了福音。tap網路卡在實現一個虛擬網路卡的同時也實現了一個字元裝置,在虛擬網路卡的xmit函式中直接將未加密未封裝的原始IP資料包放到字元裝置的輸入緩衝區,然後使用者態程式就可以從該字元裝置讀取到ip資料包,使用者態程式只需要將之加密,然後通過sock

et發出即可,藉助協議棧完成原始ip資料包的封裝。資料到了對端,使用者態程式從socket讀取到的就是加過密的原始ip資料包,因為協議棧已經自動解封裝了,然後將之解密後寫入虛擬網路卡字元裝置即可,此時,虛擬網路卡字元裝置模擬中斷cpu,從而虛擬網路卡呼叫接收函式。因此,最終我們有了方案3:


採用這個模型的開源專案有很多,它們都基於一個很簡單的demo程式:simpletun(http://backreference.org/wp-content/uploads/2010/03/simpletun.tar.bz2)
在simpletun的基礎上,衍生了VTun,OpenVPN,Openssh's VPN等專案。

三.安全策略擴充

到此為止,vpn的通路問題解決了,其中最漂亮的方案就是使用tap網路卡。可是加密/解密演算法,認證演算法等還沒有涉及。和解決通路問題一樣,處理安全策略也有很多的方案:

方案1:使用IPSec協議集以及IKE機制。

這個方案其實就是IPSec的方案,無疑,這種方案對使用tap網路卡是有限制的,因此很多情況下都是直接在核心實現。詳情參見相關標準。

方案2:編寫使用者態程式,實現可配置的安全策略

這個方案比較籠統,但是它卻是最靈活的。最簡單的方式,實現一個通過引數配置加密演算法的程式,比如VTun所作的那樣,然而VTun對於身份認證和演算法及金鑰支援比較弱。最終人們想到了SSL協議。
     SSL協議可以保證通訊的保密性和可靠性,它使用公鑰技術,支援安全且靈活的認證機制,常見的有使用X509證書的認證。SSL協議本身就包含金鑰協商,因此相比IPSec的IKE要簡單的多。正是tap虛擬網路卡和SSL的結合,才帶來了vpn技術的革命!tap網路卡和SSL是缺一不可的,雖然VTun使用了tap網路卡,然而它沒有使用SSL協議,這就直接阻礙了它的進一步擴充,而cipe則更是一箇中間過程,它的安全運算全部在核心態完成,根本無法使用SSL協議。OpenVPN是這個革命的一個產兒。
     OpenVPN的基本要素有以下幾點:
1.可配置的認證方式
2.可配置的加密演算法,金鑰協商
3.可插拔的外掛機制
4.自動的策略推送機制-包括客戶端的虛擬網路卡的ip地址
5.集中的管理功能
6.靈活的外接程式
7.強大的日誌輸出功能


四.方案對比

1.對比IPsec和虛擬網路卡-通路方案選擇

1).IPSec的通路方案是在網路層直接修改IP資料包實現封裝,然後直接交由路由模組重新路由。IPSec對原始IP資料包的封裝是直接在網路層完成的(雖然邏輯上IPSec屬於第四層)。
2).虛擬網路卡方案利用了這樣的一個事實,即可以通過路由的方式將IP資料包匯入虛擬網路卡,另外從虛擬網路卡接收的IP資料包也可以通過路由的方式匯出到本機或者其它物理網路卡。虛擬網路卡對原始IP資料包的封裝是利用標準的TCP/IP協議棧完成的(想使用標準協議棧封裝資料包,則必須將原始IP資料包放回到協議棧的頂端,即socket層,然後隨著資料在協議棧中往下流動,封裝過程自然完成)。
2.1).虛擬網路卡的副作用:由於虛擬網路卡也是一個起始於鏈路層的網路卡,因此可以為之配置網路層地址,即IP地址,出入虛擬網路卡的資料和出入物理網路卡的資料一樣受到所有TCP/IP協議棧語義的約束,因此也就可以通過虛擬網路卡很簡單地實現一個虛擬的區域網,雖然在物理上虛擬區域網內的裝置可能相隔千里。正是這一點使後來的OpenVPN可以很簡單的實現client2client。
3).總結:無疑,虛擬網路卡的方案沒有IPSec的方案更直接,因此效率上也會大打折扣,在這一點上考慮,IPSec的方案要勝出。

2.對比IPSec和SSL-安全策略方案選擇

1).IPSec定義了一整套內建的以及可外掛的安全策略協議,包括ESP,AH,IKE等,這些協議的操作全部在網路層完成。
2).SSL是一個安全套結字協議框架,通過Cipher Suit可以靈活配置認證以及加密,摘要演算法,這些操作全部在表示層和會話層完成。
3).總結:雖然IPSec是一種自然而然的方式,然而可供選擇演算法非常有限,並且配置很不靈活,因此SSL相比IPSec的安全協議集無疑會勝出。

3.綜合對比-IPSec方案VS虛擬網路卡+SSL

在資料通路和安全策略上,VPN更加關注的是安全策略,資料通路對於VPN來講是完全透明的,而安全策略則需要是高度可定製的,除非在效率要求很高的需求下,虛擬網路卡+SSL的方案要略勝一籌。以下只給出IPSec和虛擬網路卡+SSL的資料封裝框圖:
IPSec的方式:


虛擬網路卡+SSL的方式:


五.使用netfilter的引申

netfilter是一個很優秀的框架,它設計的5個HOOK點真的是恰到好處,因此我們可以圍繞它做出幾乎所有和協議棧相關的東西。包括虛擬網路卡的功能也是可以通過netfilter完成的。也就是說,不再需要虛擬網路卡了,這樣既實現了使用者態的安全策略,又不需要虛擬網路卡,也就是下面這張圖所顯示的,僅以forward出口包為例:


作為對比,列出虛擬網路卡的方式:


六.Linux的其它可選方案-GRE+ESP/AH

將這節內容放到最後有點過分了,因為這節的內容對於linux上實現VPN而言實在太重要了。
有很多成熟的方案可以實現vpn,特別是建立vpn隧道,其中最方便的vpn通路建立方式當屬GRE隧道了,並且GRE也是一個相當成熟的隧道協議。因此使用GRE隧道技術可以方便的鋪設隧道。其次,在Linux的2.6核心中,出現了一個新的框架,這就是xfrm-xfrm is an IP framework, which can transform format of the datagrams,i.e.  encrypt  the  packets  with  some algorithm. xfrm policy and xfrm state are associated through templates TMPL_LIST.This framework is used as a part of IPsec protocol.使用xfrm來實現IPSec要比使用netfilter來得更直接,因為xfrm是內嵌在協議棧內部的,而不是像netfilter一樣外掛在外部的。
     xfrm通過註冊一個struct net_protocol使得ESP,AH在第四層協議中有了名分,畢竟struct net_protocol就是一個協議棧第四層的操作例程集合,正如tcp和udp擁有tcp_protocol以及udp_protocol一樣,esp和ah也有esp4_protocol和ah4_protocol(暫不考慮IPv6)。如此xfrm以一種直接的方式在標準的協議棧中處理IPSec資料包,正如下圖所示:


可見Linux使用xfrm框架(其中為esp/ah等實現了兩個傳輸層的封裝機制,且可以外掛其它機制,比如基於5元素的策略查詢等)實現了邏輯上的IPSec安全策略,該框架包含兩大部分:

1.將IPSec安全協議集註冊在傳輸層;

2.修改路由模組,加入策略檢查邏輯,實現出口資料包的基於策略的捕獲,然後將其匯入傳輸層實現安全協議封裝。

然而VPN的另一大特性,也就是隧道的實現卻另有其人,那就是GRE模組(體現為ip_gre)。本質上,GRE網路卡和虛擬網路卡的思想是一樣的,只不過其使用一個標準協議,即GRE來封裝網路層資料包。GRE的關鍵在於網路的互通,比如它能將ipx封裝在IP中,從而實現跨協議通訊。

第三部分.網路層VPN技術發展階段

一.完全核心態的IPSec實現階段

這是官方的VPN建議,其背後有著強大的協會和組織以及商業機構。代表作有cisco,3com等廠商的核心安全裝置,以及開源屆的freeswan。Linux2.6核心中內嵌了xfrm框架,該框架以一種直接的方式而不是netfilter這種間接過濾的方式可以方便的實現IPSec。然而使用者卻沒有因為這種實現的方便性而增多,關鍵還是在於其配置的不靈活以及協議的封閉。

二.半虛擬網路卡階段

只實現了傳送例程而沒有實現接收例程的虛擬網路卡,導致沒有實現接收例程的原因是這個時候還沒有虛擬網路卡的字元裝置,無從接收資料。cipe是這個階段的代表作。在cipe的實現中,替換socket的send/recv例程並不是必要的,因為原始的協議棧對待從上到下的資料只是封裝,對待自下而上的資料是解封裝,如果不替換send/recv例程的話,資料到達使用者態再發出去時就被封裝成了本地出發的資料包了,而我們需要的是隻解除隧道封裝,而不再封裝本地的資訊,實際上,對recv的替換倒不是必須的,因為在recv中只處理了解密操作,而在使用者態也可以做,不過既然加密是在核心做的,解密也在核心做比較好,其中效率是一大原因。之所以如此複雜,是因為這只是半虛擬網路卡。

三.全虛擬網路卡階段

虛擬網路卡實現了一個字元裝置,完全對稱的實現了全虛擬網路卡,不但具有傳送例程,還有接收例程,這樣就可以完美的在兩臺主機的兩個虛擬網路卡字元裝置之間架設一條“虛擬物理線路”,分別處在兩個主機上的兩個程式中的一個只需要處理虛擬網路卡字元裝置和本地socket之間IO資料的處理/轉發即可。這種方式將安全策略完全解放到了使用者態,為OpenVPN的革命性進展開闢了道路。值得注意的是,此階段的vpn還是將注意力集中在網路通路上,畢竟安全策略剛剛從核心解放出來。代表作品有VTun。

四.SSL+全虛擬網路卡階段

虛擬網路卡加上SSL協議給軟體VPN帶來了一場革命,不僅僅是這種結合方式,而是這種結合方式之外的擴充套件功能才是亮點之所在。畢竟VTun也使用了虛擬網路卡,其模式和OpenVPN並沒有什麼太大的不同,然而正是SSL協議給這種結合方式帶來了新的活力,就像一劑猛藥瞬間啟用了最具擴充套件性的OpenVPN。細解OpenVPN,發現它是如此的簡單,實際上它在簡單的背後對映了不簡單的道理。如果我們細解牛頓三定律,也會發現它不過是伽利略理論的總結,正如OpenVPN不過是VTun加上一些標準化的安全擴充是一樣的道理。實際上,所謂的革命本是不存在的,人們普遍將量變引起質變的點當成是革命,而事實上,只要有一個矮人站到巨人的肩上,那他也會比巨人更高大!

五.最終權衡

由於半虛擬網路卡只是到達全虛擬網路卡的過渡,因此這裡不考慮半虛擬網路卡,另外全虛擬網路卡方案中的VTun也只是到OpenVPN的過渡。而基於IPSec的VPN受到各方面的限制也不予考慮,再者,VPDN的應用場合也有限制,也不予考慮。最終我們只剩下了基於虛擬網路卡的SSL VPN,當然正如OpenVPN官方網站所說,OpenVPN相比IPSec所欠缺的就是各個作業系統的原生支援,雖然OpenVPN的設計非常優秀,但是在標準化方面還是比不過IPSec,IPSec的成功,和諸如Cisco等公司的推波助瀾是分不開的,我們知道,第一流的公司做標準,第二流的公司做品牌,第三流的公司做產品,因此標準化是很重要的。在Windows上,如想用VPDN,基本直接就能支援,然而想使用OpenVPN,則必須安裝客戶端。另外效率問題也是OPenVPN的劣勢,然而這不是根本的劣勢,技術上的問題終究是可以得到解決的,我本人就曾經修改了tun驅動程式,使其吞吐量大幅提高...

第四部分.Linux VPN軟體選型

1.IPSec的實現:freeswan

雖然IPSec的側重點在效能和安全性,然而事實上在Linux中,Freeswan的效率並沒有想象的那麼高,因為它是netfilter實現的,而netfilter將會過往的每一個資料包進行判定,這會嚴重影響效率。Freeswan的優點在於其實現的標準性。
Freeswan在2.6之前的Linux核心中使用的更加廣泛一些,因為2.6核心有了更好的IPSec方案-Xfrm。另外,由於政治原因,Freeswan的推廣受到了很大的限制。

2.cipe

效率很高,然而配置不靈活,且只支援單通道。

3.vtun

效率很高,支援多客戶端,每個客戶端一個程式處理。配置也很豐富,然而缺乏更高階的安全策略的支援,正如其文件中所說的那樣。

4.openvpn

具有革命性的vpn實現,支援多客戶端,支援client2client。然而其效率卻不是很高。OpenVPN的靈活性及安全性蘊藏著巨大的收益,並且其實現的對稱性和簡單性吸引了大量的開發者,最終開發出了各個平臺的版本,這正體現了OpenVPN的強大。反觀VTun,直到現在,它也不支援Windows版本,並且2007年就停止了開發...

5.應用層ssl vpn

這是應用級別的VPN,諸如代理軟體,翻牆軟體都屬於這種範疇,它保護特定的主機,特定的應用,因此對於個人接入擁有很大的優勢,它可以得到更多的應用層的使用者資訊,這是網路層的vpn所無能無力的。然而如果你希望使一個網路安全的接入另一個網路,那隻能選擇1到4的方案了。


相關文章