歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> OpenVPN的按需連接實現

OpenVPN的按需連接實現

日期:2017/2/28 14:37:57   编辑:Linux教程

上帝按照自己的形象,造出了人,人按照自己的喜好,造出了計算機,計算機也都有心跳。操作系統靠時鐘中斷這種心跳來推進機器的時間,然而後來Linux實現了NOHZ,即沒有事情的時候,不再無謂地觸發時鐘中斷,而是徹底halt,有事請來的時候,其它的中斷會將機器喚醒,繼續心跳。這種nohz機制節省了資源,最小化了bug觸發率。

IPSec VPN完全是按需連接的,隧道模式下,如果數據包過來,匹配到了加密策略,那麼就看加密隧道有沒有建立,如果還沒有建立,則觸發IKE協商,如果已經建立了,則直接通過隧道傳輸數據,當然IPSec也可以使用萬惡的心跳...

心跳保持的VPN長連接有幾個問題,第一,如果收不到心跳,隧道就要被迫斷開一次,這種斷開事件會被審計為一次異常事件,因為按照正常看來,既然要保持長連接,那它就不應該斷開,現在斷開了,那是不應該的。第二,對於那種帶寬屬於稀缺資源的環境,心跳報文會占用可觀的資源,比如3G用戶,在沒有實際數據傳輸的情況下,發送的心跳報文將是完全的浪費。

VPN為何要保持長連接呢?難道隨用隨連不好嗎?隧道的長連接難道僅僅為了展示自己是一個基礎設施嗎?對於網到網拓撲來講,這可能是真實的,但是對於終端用戶而言,長連接基礎設施反而意味著壓力,因為終端用戶要為心跳報文買單。OpenVPN是一種高度靈活的VPN,它的靈活性以及好處在於你如何使它和外界關聯配合,而不在於它本身!記住這一點非常重要!

OpenVPN也可以實現按需連接,即沒有數據的時候隧道斷開,有數據來的時候創建隧道,並且在持續一段時間沒有數據的時候再次斷開隧道。這些事件中,除了”持續一段時間沒有數據的時候再次斷開隧道“這個功能(--inactive參數)是OpenVPN本身的功能外,其它的都需要外部的協助,首先我們要考慮的是,如何按需創建連接。

通過iptables識別什麼是”需要通過OpenVPN加密傳輸“的數據,識別到了以後,必須”堵住“該數據,直到隧道建立後再將它放行,堵在哪裡呢?當然是堵在隊列裡面,如果隧道建立的時間比較久,那隊列無疑會滿掉,此時丟棄新來者是迫不得已的行為。有了此大方向,接下來就是具體的方案。在Linux上,幾乎什麼東西都不需要自己重做,以上這個功能可以通過iptables的QUEUE來實現,該target將數據包queue,用戶態進程read這些排隊的數據包到用戶態,然後...

然後該進程可以直接將包重新注入回內核,也可以在注入之前先去建立OpenVPN隧道,隧道建立以後再注入數據包,既然此時隧道已經建立了,路由規則該添加的也添加了,那麼後續的數據包就不需要再QUEUE到用戶態了,這個又是怎麼實現的呢?還好,Netfilter有一個addons擴展,擴充了iptables的功能,我們需要的就是一個叫做condition的模塊,該模塊的使用使得多條iptables規則之間可以完成很多復雜的控制邏輯,如下一條:

iptables -t mangle -A PREROUTING -d 192.168.1.1/32 -m condition --condition "vpn" -j QUEUE

它的意思就是只有在vpn這個condition變量的值為1的時候,發往192.168.1.1的數據包才會去排隊,否則就直接匹配下一條規則,不會被排隊。到此為止,所有的准備工作基本就緒,剩余的工作即是如何把這一切拼接在一起形成方案。為了快速說明問題,我就不再使用OpenVPN舉例了,我用一種等價的方式說明問題:

只有當到達192.168.1.1的數據包來的時候才建立其明細路由,持續沒有到達192.168.1.1的流量5秒鐘後刪掉該明細路由。

這個足以說明問題了,它足夠簡單。雖然說即使它這麼簡單,最終還還是偷了懶,沒有實現完全。首先添加上面列舉的那條iptables規則,然後創建一個用戶態進程,代碼如下:

#include <linux/netfilter.h>
#include <string.h>
#include <stdlib.h>
#include <libipq.h>
#include <stdio.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <linux/ip.h>
#include <signal.h>

#define BUFSIZE 2048
static int condition = 0;

void condition_handler(int num)
{
if (condition == 1) {
condition = 0;
} else {
condition = 1;
}
}

int main(int argc, char **argv)
{
int status;
unsigned char buf[BUFSIZE];
struct ipq_handle *h;
signal (SIGUSR1, condition_handler);
h = ipq_create_handle(0, 2/*PROTO_IPV4*/);
status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
do{
status = ipq_read(h, buf, BUFSIZE, 0);
switch (ipq_message_type(buf)) {
case IPQM_PACKET: {
ipq_packet_msg_t *m = ipq_get_packet(buf);
size_t data_len = m->data_len;
//讀取到有數據包後,觸發執行啟動VPN腳本的命令
system("/home/zhaoya/start_vpn param1 param2 paramX");
//等待start_vpn命令執行完畢,它會建立VPN隧道,建立完成發送信號給該進程
while(!condition) {
pause();
}
//成功建立隧道以後,將數據包原封不動地重新注入回去
status = ipq_set_verdict(h, m->packet_id,
NF_ACCEPT, data_len+sizeof(struct iphdr), (char*)m->payload);
break;
}
default:
break;
}
} while (1);
ipq_destroy_handle(h);
return 0;
}

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2013-12/93745p2.htm

相關閱讀:

Ubuntu下OpenVPN客戶端配置教程 http://www.linuxidc.com/Linux/2013-06/86562.htm

Ubuntu 10.04搭建OpenVPN http://www.linuxidc.com/Linux/2012-11/74790.htm

Ubuntu 13.04 VPN (OpenVPN) 配置和連接不能同時訪問內外網的問題 http://www.linuxidc.com/Linux/2013-07/86899.htm

如何在Linux上用OpenVPN搭建安全的遠程網絡架構 http://www.linuxidc.com/Linux/2013-11/92646.htm

OpenVPN 的詳細介紹:請點這裡
OpenVPN 的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved