歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux平台VPN技術概論

Linux平台VPN技術概論

日期:2017/2/28 16:08:54   编辑:Linux教程

聲明:

1.對於IPSec,不談其Tunnel以及Transport模式
2.對於OpenVPN,不剖析代碼
3.不涉及Linux內核源碼剖析
4.不深入談PPTP以及L2TP
5.本文不是HOWTO也不是技術文檔
6.本文的性質是科普

第一部分.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模型也有賴於這個事實。

Copyright © Linux教程網 All Rights Reserved