1. 程式人生 > >BadVPN詳解之--組網原理剖析

BadVPN詳解之--組網原理剖析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                這可能是第一篇關於BadVPN原理的中文介紹,所以我恪守職責,希望能將BadVPN的原理闡述清楚,而不僅僅是為了欺世盜名取天下之先。

序:格爾上市

這一段插在這裡有點突兀,與BadVPN無關,只是我的一點實感,忽略即可。
       明天小小要去廈門演出,今天是什麼日子?是小小準備且出發的日子。但是同樣在今天,也就是2017年4月21日(寫完本文時估計已經到了22日...),上海格爾軟體股份有限公司成功上市了。也許你不知道這個公司,確實這公司的業務是很小眾,不像BAT佈局那般巨集大,但這並不意味著這家公司的平庸。於公於私我不得不多說幾句。

於公的宣傳

格爾軟體是專門搞PKI的一家公司,也許你不知道什麼是PKI,但沒關係,只要百度一下就好,概念很簡單,不需要Google。格爾是國內少數幾個搞PKI的公司之一,而且也算是龍頭之一吧。做個比喻,如果說騰訊依託其QQ,微信成為了社交APP的龍頭,那麼格爾就是國內PKI產業的龍頭(我有點帶有感情色彩,不管是對騰訊還是對格爾,我只是想說公司好),那麼PKI產業包括什麼?它包括身份認證,訪問控制等,而這些在網際網路時代是每個人的基本需求。
       在網際網路時代,資訊保安已經不僅僅是組織,機構,國家的事情,而是關係我們每一個人,這是一個非常有前途的產業,雖然僅憑資訊保安無法成就像Google,fb,騰訊,阿里那般的格局,但是這並不意味著那些諸如BAT之類的巨頭可以忽視資訊保安,相反,他們需要更加重視資訊保安,要麼自己做,要麼購買既有的解決方案或與其深度合作,讓專業的人做專業的事。誠然,格爾做不出像微信這樣的APP,也無法成就像支付寶那幫風風火火的網際網路支付的巨集大場面,但這些一開始就並不是格爾的目標,格爾的目標是為所有這些提供底層的安全保障。
       格爾公司成功的與包括華為,騰訊在內的第一梯隊巨頭企業達成了合作和交流,與其一起深度合作,為構建安全的基礎設施提供保障,解除安裝了這些巨頭企業的鉅額開銷,這些事情做的很棒!
       如今格爾成功上市,我心裡表示高興,於我個人而言,我供職過的公司成功上市,我當然覺得風光,畢竟,我也是為其奮鬥過的人,哪怕,只是為了自己,即使,現在在利益方面已然與我無關。

於私的感恩

在N多家公司為自己奮鬥,為了自己能在一個大城市買上房子,成家立業,這幾乎是每個IT人的夢想,當然,我也在此之列。雖然我早已離開了,但我感謝格爾公司,是它讓我在上海立足了根本,買了自己的第一套房子,在公司期間,我和老婆生育了可愛的小小並伴隨其快樂成長。
       也許,很多人會覺得我傻,不就是一家公司嗎?到哪不是工作,你工作,老闆給錢,天經地義。但是這對我不一樣!
       像很多華中科技大學(原諒我總拿這學校開涮,其實我是做過統計的)的畢業生,畢業就能到騰訊,到華為這種大廠,這當然是很好的事,我並不嫉妒,我的父親告訴我要為別人的幸運感到慶幸,因為幸運的人越多,自己的機會就越多,畢業進大廠這使得他們無需多個城市,多家公司折騰,可能一生就在三地生活過就夠了,自己的老家,武漢,以及深圳。對於這種高材生,我祝福他們,對於另一類高材生,那些畢業於北京,上海一等名校(我故意把北京上海的名校和武漢的這種技校相區別,請別介意,其實都一樣,together with哈工大,哈工程,北航,南航...)然後出國再回來的海歸,我更應該祝福他們,以上這兩類人才無論如何在任何時候都可以待價而沽。慢慢的,圈子就已經完全被他們所佔據,至少華為對學校是有要求的吧。這導致像我們這種不入流的兩年制大專生很難找到像樣的工作,那些名校的科班生,那些校招進大廠的他們根本無法體會我們這種辛苦找工作的求職者心裡的酸楚。他們跟我們完全處在兩個世界。
       對於那些勢利眼的面試官或者HR而言,他們一聽到我的資歷就會馬上在心裡做一個MARK標記,與LRU相反,是最近最常用的標記,如果要PASS掉某些人,他們會優選我這種。然而,世事總是有例外,就這樣在我2009年裸辭後三個月求職未果,不經意間老婆幫我投了個簡歷,在2010年3月29日去格爾面試的時候,一頭長髮的小雨跟我面談了不到半小時就讓HR給我打電話,我還沒到家就接到了入職邀請,小公司,沒有Offer,沒有什麼正式的檔案,只說能不能下週一上班(事實上,我是在3月24號週三才去上班,前兩天好好吃了幾頓,睡了幾覺,因為找到工作對我而言太重要,我必須把這件事當成一件喜事而慶祝。這是批量的名校科班畢業生所完全不能理解的)...
       於是我一干就是五年,其中第一年我恍恍惚惚,再往後就看我的部落格吧。我很感謝格爾能給我這個學習成長的機會,為我提供各種機會和資源,讓我精通了VPN,精通了網路,最終讓我徹底抹掉了學校和學歷的陰影,並且在將近10年以後成功入職了大廠,我覺得這是格爾帶給我的,作為回饋,我只能繼續努力,好好供職於我現在的公司,畢竟鵝廠也同樣沒有因為我的學校和學歷而計較,我突然感到我是幸運的人。
       來之不易才懂的珍惜,人要記著對自己好的人或者事,不僅僅是因為利益,總把任何東西看成利益,那太Low。總之,無條件謝謝我的父母,我的家人,格爾公司,鵝廠,...!
       感慨發完,可以步入正題了。

前言

我關注VPN已經多年了,有三類VPN讓我覺得驚歎幫我理解了網路協議的體系結構。首先IPSec,I2TP,PPTP這種傳統的VPN技術讓我知道原來協議棧還可以如此的相互Over,然後就接觸到了OpenVPN,如此一個簡單的玩意兒竟然擁有如此強大的組網能力,我喜歡這個OpenVPN,一去就是三五年,期間這個玩意兒也為我帶來很多現實的東西,比如獎金,比如加薪升職什麼的,打心眼裡,我覺得利用OpenVPN的理念,可以創造出世界第一等的VPN產品...直到我遇到了BadVPN!
       當然,最基本的VPN就是IPSec VPN,然而要想配置好一個多點的IPSec VPN網路及其複雜和費事,最終EzVPN彌補了這個不足,它通過一個所謂的中心節點簡化了配置。然而這一切都是“官方”的方案。落實到普通程式設計師可以就地使用的方案,沒幾個。OenVPN是一個,BadVPN也是一個。
       我承認,前幾年我被OpenVPN衝昏了頭腦,竟然忽略了世界上還有一個叫做BadVPN的東西。都到了2017年了,我才第一次注意到它,這多多少少有點讓自己覺得悲哀。

BadVPN是另一個VPN

為了能快速理解BadVPN的原理,我準備從OpenVPN開始,當你知道了OpenVPN有什麼問題的時候,就會更加容易理解BadVPN是如何解決這些問題的了,而這些正是理解BadVPN的關鍵。我先來展示一個OpenVPN的結構圖,假設使用TAP Bridge模式:




可以看出,OpenVPN有一個所謂的“中心節點”,其它所有的子節點都連線到這個中心節點。OpenVPN的這個中心節點身兼兩職:
1.提供總體的控制功能,負責與子節點金鑰協商,分配虛擬子網的IP地址給子節點,推送策略給子節點等。
2.同時作為一個對等的VPN節點存在,和各個子節點所攜帶的子網互聯互通。

上述兩點可以看出,第一點是控制平面的功能,第二點是資料平面的功能,二者完全在一個鏈路上傳輸,這意味著什麼?這意味著要精心設計OpenVPN的協議,以區分到來的資料包包含的是控制資訊還是資料。
       OpenVPN協議區分了資料是控制面的資料還是資料面的資料,然而這種區分是帶內實現的,也就是說通過協議頭的欄位來實現的,姑且不說封裝這個協議頭會帶來什麼開銷,僅僅在OpenVPN程序中去多路複用並行處理控制平面和資料平面就夠複雜的了。
       按照傳統的網路設計觀點,中心節點即服務端就是一個交換機,而各個VPN子節點客戶端就像是“該交換機埠的另一端”連線的各個主機或者級聯交換機,這是一個典型的星型拓撲。然而按照SDN控制平面的觀點來看的話,中心節點就是一個控制器,它控制了整個的VPN網路轉發邏輯,所有的子節點要傳送資料必須無條件轉發到中心節點,讓中心節點決定資料轉發到何方,這意味著哪怕是子節點客戶端之間互相通訊,也必須經由中心節點來轉發。
       不管站在什麼立場上來看,OpenVPN的中心節點都是一個單點,不管是從效率還是從可用性上來權衡,這都不是一個優雅的方式。說點題外話,幸虧我個人精通Linux網路,可以通過iptables,iproute2,多執行緒改造OpenVPN,bonding TAP網絡卡,Keepalived等措施來破除這種限制,消除種種效率和可用性上的威脅,我才得以駕馭OpenVPN,不然的話,用OpenVPN來組網還真的限制多多。即便我有能力Hold住存在單點問題的OpenVPN,最終我還是失敗了。我已經把OpenVPN堆積的不成樣子了,迫切需要一個新的思路。

       OpenVPN的中心節點扮演了過於重量級的角色,這導致了任意建立VPN通道的節點之間的關係不可能是對等的,OpenVPN必須以主從方式建立VPN通道。這就主從結構的限制使得OpenVPN在組網方面很難構建多點對多點的網狀拓撲。

    那麼BadVPN有何不同呢?為了與OpenVPN做對比,我還是先來展示一個BadVPN的總覽圖:




所有的節點綜合起來構成了一個巨大的交換機,大家一起完成交換機的功能,各個VPN子節點(為了對比,我依然沿用OpenVPN中心節點,子節點的術語)就是交換機埠本身,而不再是“埠對端”連線的裝置。其中,中心節點不再負責實際的資料轉發,而僅僅作為一個“維護這個交換機組成部分”的控制器存在,中心節點負責以下的事宜:
1.記錄該VPN網路中擁有多少節點主機,即“該大交換機中有多少埠”以及“埠的新增,刪除以及通告”。
2.構建子節點與中心節點之間,子節點與子節點之間的TLS控制通道,協商子節點之間的通訊金鑰。

這意味著各個子節點之間的VPN互通不再需要經過中心節點,實際上也根本就沒有什麼可以進行資料通訊的VPN中心節點。VPN通訊節點之間變成了真正的點對點通訊,除非你配置中繼(BadVPN的一種特殊執行方式,在許可權受制的場景下使用,本文不討論,詳情參見BadVPN的Document),任何VPN之間的通訊都是直接通訊,不需要經過第三方。
       這意味著什麼?
       這意味著:
1.BadVPN的協議會非常簡單。
2.BadVPN的處理過程會非常簡單。

BadVPN將控制平面和資料平面做了帶外的分離,不再僅僅是帶內分離而依靠協議來區分。關於這一點,後面會詳述,下面的小節我們在感官上認識一下BadVPN的原理。

BadVPN的執行原理圖解

長篇大論終究會因為文筆不好而適得其反,所以還是通過畫圖具體來點情景分析為好。我分兩種場景來描述BadVPN的行為,即非打洞場景和打洞場景,先看非打洞場景。

1.普通情形的情景原理分析

控制面的生成

第一個節點連線中心節點時




第二個節點連線中心節點時




第三個節點連線中心節點時





三個節點都連線上了中心節點,本文中描述的“BadVPN構成的巨大交換機”就已經生成了,我們可以看到,是中心節點維護了這個巨大的交換機。
       這個時候,這個交換機是空的,就像剛上好架,插好網線,加電完畢後的狀態一樣。我們知道,乙太網交換機是自學習的,本文中敘述的“BadVPN交換機”自然也不例外。那麼下面我們就看一下在有實際資料傳輸的時候,這個交換機到底是怎麼運作的吧。


資料面的運作

子節點A或其攜帶子網需要ping子節點B的TAP地址,傳送ARP




子節點A收到子節點B的TAP回覆的ARP Reply




子節點A封裝ICMP Ping在加密通道上發給子節點B




附:我的改進

其實我不很贊同BadVPN裡面的Peer-Macs表的設計,我覺得應該是三元組設計,即Peer-Vips-Macs表,詳見我下一篇文章,講述我自研的一個VPN,可能介於OpenVPN和BadVPN之間,也可能是BadVPN介於OpenVPN和我的VPN之間...誰知道呢?總之,皮鞋爆炸。

2.NAT後需要打洞的情景原理分析

我不會在這個小節裡重複上面常規場景裡的圖解,我覺得我只描述UDP打洞場景就好了(我直到現在依然記得江琦博士TCP打洞全世界第一,希望長春Leadwell做SIP的同事見文與我聯絡,想念你們...)。
       打洞原理非常簡單,我假設中心節點是X,而子節點A和子節點C均在NAT之後,那麼打洞過程如下圖所示,分兩步:
第一步:讓中心節點X分別記錄下A和C的外網地址和埠:




第二步:彼此嘗試並最終成功連線




這樣,即便子節點處在NAT之後,依然可以建立正常的點對點互聯,並且如果二者在同一個NAT後面,還可以建立直連互聯,這真是強大!事實上,這種模式早就被我們使用了好多年,偉大的騰訊公司早就使用這種方式運作QQ了。難道QQ不是一種特殊的VPN嗎?QQ是什麼:
1.QQ對等客戶端雙方加密通訊;
2.QQ自帶打洞功能,處在不同NAT後面的客戶端依然可以直接建立連線(若真不行,經由伺服器中轉是補償方案);
3.QQ自帶打洞功能,處在同一NAT後面的客戶端可以不經NAT而直連。


3.對協議設計的影響

BadVPN無需在協議中區分控制資訊和資料,BadVPN是完全的帶外控制,而不像OpenVPN那般的帶內控制。
       我們看看BadVPN的資料通道協議,即子節點之間互發資料的協議,非常簡單。它經由下圖所述的封裝即可傳輸:




因為資料發給誰是“交換機查表”的結果,不會錯的,所以無需在接收端進一步判斷。接收端收到之後,可以信任一定是發給自己的(當然為了安全起見,還是要判斷一下的,但這不是根本)。
       這有點類似於全雙工交換式乙太網的運作方式,一條網線連線且僅僅連著兩臺裝置,如果這條網線上有流量,那一定是這兩臺裝置之間的流量,如果其中一臺裝置發出資料,那麼接收端一定是網線另一端的裝置,這就是點對點全雙工通訊。
       除了資料通道不再需要中心節點中轉,對於控制通道協議而言,我們依然可以看到這裡解除控制和資料的耦合後的好處。僅舉一例,即子節點之間的金鑰協商過程。假設子節點A和B同時連線於中心節點X,當B節點接入後,B要和A之間建立SSL通道,這個SSL通道是SSL中的SSL,分為A到X以及X到B兩段,如下圖所示:




然後A和B之間的對稱金鑰就是在這兩段的SSL通道中協商出來的。協商方式非常多,可以讓A或者B隨意一方生成一個金鑰,經由A-X-B或者B-X-A的SSL通道傳輸給B或者A,也可以使用簡單的DH演算法來直接交換生成金鑰,總之,就跟IPSec的IKE兩階段協商一個道理,第一節點通道要為第二階段提供保護。
       這種事情在OpenVPN就會非常複雜,因為在資料通道層面上,必須將整個控制通道分為不同資料通道的不同控制通道,而不是一個統一的控制通道,因此,對於OpenVPN而言,只能將兩種通道徹底分開,然後依靠“類似深度包解析”的方式來判斷哪個資料屬於哪個通道的控制面還是資料面,從而導致了大量的冗餘。這有點類似於資料庫表的設計,要通過鍵溝通的方式來建立關聯,而不是把所有資料都塞入一張複雜的大表中:




附:命令列引數解析

我說過,BadVPN是靠點對點的方式完成VPN通訊的,那麼完成這種通訊的基礎就是底層的TCP/IP網路,顯然需要對五元組。和OpenVPN的理由一樣,BadVPN建議使用UDP來作為傳輸協議以防重傳疊加。但是即便是UDP,也要確定哪個4元組不是嗎?是的。
       對於在文章《 BadVPN詳解之--編譯與執行》中的“執行”一節,命令列中的ext-addr引數所指定的IP地址和埠就是VPN資料通訊的IP地址和埠,也是上面圖示中中心節點向新接入的子節點通告的既已經接入的子節點的IP地址和埠,這個元組是控制通道的元組。
       與ext-addr引數不同的是,中心節點的listen-addr引數以及子節點中的server-addr引數均指代控制通道的資料通訊元組。

4.對組網拓撲的影響

BadVPN一開始就是點對點的對等拓撲,中心節點不負責任何資料傳輸和轉發任務,正如其例項文件所述:
NOTE: badvpn-server does not actually participate in the virtual network. If you want the server machine to be part of the network, run a local badvpn-client, like on other peers.
再次看一眼“BadVPN是另一個VPN”小節中的BadVPN總覽圖,會發現,子節點之間誰也不比誰更重要,大家完全是對等的。所以對於BadVPN而言,拓展整個虛擬子網變得超級容易,就像在一臺乙太網交換機的一個埠上連線一臺主機一樣。
       BadVPN在配置中去除了TAP和TUN之間的區分,也不再BadVPN內部配置虛擬網絡卡的IP地址等。BadVPN直接幫你構建了一個數據通道,該資料通道由一個既已存在的控制通道所控制。所有的子節點均在一個虛擬出來的乙太網中,所有人都知道什麼是乙太網,那就是隻要把網線插入交換機,配上IP地址就可以互聯互通的網路,BadVPN正是幫你構建了這麼一個網路,非常簡單!


我的遺憾(純情感迸發,純技術者請繞道)

我遺憾自己沒有在2015年9月前看到這個BadVPN專案。如果在此之前得知這個專案的話,我可能就不會迷茫,我會繼續鑽研技術細節而不是什麼產品的市場場景,我可能會重構BadVPN而不是不可救藥的OpenVPN。
       但是一切都太晚了。我於2015年9月份放棄了自己的OpenVPN專案,背井離鄉來到了一個對自己而言非常陌生的地方深圳,這裡擁有來自全國各地(兩湖兩廣居多)懷著激情和夢想的年輕人(以在大城市買房置業為目標),卻連一條像樣的快速路都沒有(不拿堵車說事,深圳的快速路高架橋完全不敵廣州,上海,毫無規劃,基本也就是見招拆招),產業更是出其不意的單調,但這裡的人卻無比喜歡自己生活的城市,也是是他們大多數從自己的家鄉到武漢等地上大學然後就到了深圳沒在別的地方生活過的緣故吧,說實話,像我這種以文化享受為己任的多元化人,並不喜歡深圳這座城市。但是就因為我沒有在正確的時間接觸到BadVPN,導致了我無力進一步深挖VPN的架構,具有諷刺意味的是,我現在也成了深圳人,也開始喜歡上了這個地方,和我的性格比較類似,如果我不喜歡深圳的道路,那麼我來自己建設它,所以如果我不幹IT了,我希望能成為深圳的城市規劃者,當然,這是後話。
       小小長大了,要在深圳上小學了,我很欣慰諸多喜歡我的讀者也在關注著小小一天天地長大,曾經有人告訴我他看過我寫的一篇關於VPN的文章,那時我記錄了小小的出生,那是2011年6月28日小小出生的第二天,我寫那篇文章的時候,我正休著陪產假,換班時在家裡寫了那篇文章,這篇文章是《 Linux的Netfilter框架深度思考-對比Cisco的ACL-》。
       後來為了小小在上海買了房子,在我的第一座一線城市的房子裡,想了太多的關於OpenVPN的點滴,也分享了很多,我很懷念我家的榻榻米,同時必須要感謝關注我的每一個人。現如今,深夜裡我坐在深圳的窗下,正在下雨,非常爽,但是我很遺憾,我沒有及時意識到BadVPN的存在,我甚至無法把OpenVPN發揚光大,在無所事事的時候誤入了歧途。但我相信,總有一天我會回去做我喜歡的東西的,雖然我為了把房子租出去而丟棄了榻榻米換成了床,如果我回去,我還是會換回去的,哪怕只是為了情懷!記得那個時候,小小蹣跚學步,呀呀學語...我深深的知道,如果有一天我回到了上海的家,再次遇到了我的好鄰居,我的好朋友,也許我可以再次和他們一起喝酒吹牛,但再也沒有小小小時候伴隨的的快樂了。
......

我曾經的c2c組網方案

OpenVPN的主從模式限制了OpenVPN的組網靈活性。有一個實際的需求是建立N個VPN節點間的對等通訊,這在BadVPN看來就是一個原始的配置,N個子節點同時連線中心節點即可,這樣它們就自然而然建立了對等的P2P拓撲,然而如果使用OpenVPN,便不然。OpenVPN的方案需要太多額外的支援,比如要用Bonding,Bridge,iproute2,Policy routing,iptables,ebtables等工具助力完成配置,過程及其複雜。
       這裡只設一個題目,如下A,B,C三個節點需要建立對等的點對點連線,該如何?由於OpenVPN必須採用主從模式,那麼A,B,C三點必須採用咬尾巴蛇的策略來建立互通,如下圖所示:




顯然很合理。那麼如果是四個節點,五個節點,甚至更多的節點呢?顯然環形的咬尾巴蛇策略就不可行了,那麼要實現兩兩互通那該怎麼辦?典型且直接的方案就是每一個VPN節點均執行一箇中心節點模式VPN,再執行N-1個子節點模式VPN,這樣便可以彼此互通:




拓撲是搞定了,還挺和諧對稱(PS:這是一個真實的案例拓撲,目前依然在一個規模想當的都會網路上執行著)。然而你考慮以下的問題了嗎:
1.一個VPN節點上要建立多少tap虛擬網絡卡?
2.如何實現多個節點間流量的隔離?
3.由於每個節點均執行一箇中心節點模式的VPN,那麼策略怎麼推送?
4.要配置多少Policy routing路由,用以支援不同的子網之間的互通和隔離?
5.要想完成上述第4點,需要配置多少iptables規則?
...

我相信,上面的清單要是列出來,很少有人可以瞬間理清頭緒的。我記得當時我在做這個產品的時候,曾經無數次的跟同事闡述以上這些原理,最終都是無果而終,最終的最終,我自己都已然忘卻,在我從OpenVPN相關的專案組離開後直到現在,有很多人問起過我關於OpenVPN的問題,恕不能答,因為我自己也理不清了...我每次都要看我之前寫的那些部落格或者筆記才能明白到底是怎麼一回事,唉。總之,罪魁禍首就是OpenVPN的主從模式導致組網太複雜了。
       如果使用BadVPN,則基本沒有這麼一回事了。BadVPN在搭建好之後,就是點對點的,無須設定任何規則即可所有節點互聯互通:




-----------------------------------------------
好了,以上就是BadVPN的大部分原理知識了。如果你還是不理解,請繼續聽我下回分解,在下文中,我將講述一個我自研的一個設計。該設計可能比較垃圾,也可能比較比較爆款,但不管怎樣是我的真情實感,在我遇上BadVPN之前就思考了一段時間,最終看到Badvpn之後,發現確實如此的相類似。
       不是英雄所見略同,而是正確的道路往往只有很少的幾條。且聽下回分解!

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述