IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)
來自專欄即時通訊技術分享
本文來自微信技術架構部的原創技術分享。
1、前言
在上篇《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》,我們講解了IPV6的基本概念。
本篇將繼續從以下方面展開對IPV6的講解:
- IPv6在Linux操作系統下的實現;
- IPv6的實驗;
- IPv6的過渡技術介紹;
- IPv6在Linux平台下socket編程應該注意的問題。
如您對IPV6的基本概念尚未了解,請先閱讀本文的上篇。
學習交流:
- 即時通訊開發交流3群:185926912[推薦]
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
(本文同步發佈於:http://www.52im.net/thread-1607-1-1.html)
2、系列文章
文章太長,分為兩篇來講,本文是2篇文章中的第2篇:
- 《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》
- 《IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)》(本文)
本文是系列文章中的下篇,主要講解IPV6的應用現狀和技術實踐等。
3、Linux內核IPv6架構簡析
本文後面主要的分析都是基於Linux,會有涉及關於Linux內核對IPv6的實現。主要是因為,現在IPv6的參考資料不多,除了與IPv6相關的RFC之外,還有少數可以參閱的IPv6國外文獻,而Linux內核一直都與跟隨著IPv6的協議更新和變化,Linux內核IPv6的實現是十分重要的參考材料之一。而且從事後台開發工作主要也是在Linux平台下,熟悉Linux下IPv6的實現也是為以後的工作做知識儲備。
PS:客戶端開發的同學可以參考各自平台的文檔......
Linux在很早之前就已經開始支持IPv6,目前我們接觸最多的Linux內核版本都很好地支持IPv6,同時也是支持IPv4/IPv6雙棧體系。在Linux操作系統中,IPv4是默認必須開啟,IPv6是可選編譯和配置開啟。
例如在編譯內核的時候,需要選擇IPv6編譯選項才支持IPv6:
當開啟支持IPv6的Linux的內核網路雙棧的結構,如下圖:
▲ 圖11:Linux內核雙棧架構Linux內核中,IPv6協議棧與IPv4協議棧並行關係,IPv6和IPv4完全是兩套不一樣的代碼實現。
IPv6完整的協議棧邏輯模塊包括:
- 1)網路層IPv6,核心邏輯:IPv6路由子系統;
- 2)傳輸層TCP/UDP實現:TCPv6、UDPv6;
- 3)控制報文協議ICMPv6,這裡值得一提的是ICMPv6在IPv6協議中的地位十分重要:ICMPv6不僅提供了與ICMPv4相同的服務診斷功能,例如報告數據包的錯誤和提供簡單的echo服務,ICMPv6是IPv6中鄰居發現協議的重要組成部分,用於管理鏈路上的點到點的通信;
- 4)鄰居子系統的實現:鄰居發現協議NDP(對應於IPv4裡面的ARP協議);
- 5)其他高級實現(IPv6 NAT、IPv6隧道、iPv6 IPSec等)。
由於我們平時的開發工作在應用層,以上1-4是將會接觸得最多。
4、IPv6實驗
本章我們通過實驗,加深對IPv6的認識。這裡的實驗沒有使用真實現網的IPv6接入點(目前國內絕大部分接入點都是教育網),而實驗的目的主要是觀察IPv6的數據包結構、IPv6的路由配置等,所以決定自己通過搭建中間路由器、應用伺服器的方式做實驗,便於抓包和代碼分析。
客戶端:windows 7
路由器:中間路由器使用自己編譯和搭建的Linux系統(內核2.6.32.27)應用伺服器:Ubuntu16.04LTS版本。為什麼要使用自己編譯的Linux作為路由器?因為IPv6的實踐類能參考的文獻比較少,而Linux內核的IPv6模塊是最重要的參考資源之一,在實踐中遇到問題可以使用打LOG和分析代碼的方法解決。
4.1無狀態自動配置地址實驗
IPv6地址的獲取是最重要的環節之一。本實驗使用開源的無狀態自動配置服務radvd進行實驗。
▲ 圖12:IPv6無狀態自動配置 ▲ 圖13:IPv6無狀態自動配置報文分析
無狀態自動配置過程:
- 1)由鏈路上的主機向鏈路發起「路由請求」報文,這個報文是以組播協議發送,尋找鏈路上最合適的路由器;
- 2)路由器收到請求會返回「路由通告」報文,報文裡面帶著本鏈路的地址前綴信息主機將接收到的前綴和自身的介面ID,組成完整的新地址;
- 3)主機嘗試使用新地址發起地址重複檢測,檢測鏈路上是否有其他主機也是這個地址,如果有,就停止使用該地址;如果沒有,就啟用這個新地址。
可以看到無狀態自動配置過程十分簡易(對比DHCPv4和DHCPv6來說),實際上,無狀態自動配置可以單獨組網使用,也可以配合有狀態自動配置一般會配合使用,加強網路節點管理。涉及自動配置和地址檢測等更多細節,可以查閱RFC1971、RFC4861。
4.2IPv6靜態路由配置實驗
本次實驗主要是了解windows和linux的靜態路由配置。
▲ 圖14:IPv6典型的網路拓撲由於各自的網路前綴(網段)不一致,在不使用默認路由的情況下,我們嘗試配置路由讓客戶端可以訪問到伺服器。
第一步:Windows 7配置靜態路由
去往伺服器的2001:db8:5::/64網段的路由 ▲ 圖15:Windows配置IPv6路由第二步:路由器1配置
▲ 圖16:Linux下配置IPv6路由第三步:路由器2配置
▲ 圖17:Linux下配置IPv6路由
第四步:伺服器靜態路由配置
▲ 圖18:伺服器配置IPv6路由第五步:結果
▲ 圖19:客戶端訪問伺服器客戶端可以順利ping通伺服器。可以看到,IPv6下的路由配置,無論是windows還是linux,與IPv4的配置差別不大,熟悉IPv4各個平台路由配置的同學可以很快上手IPv6的路由配置。
4.3IPv6的web服務
復用2的架構,在伺服器端部署一個web服務,在客戶端訪問該web服務。web服務沒有選擇像apache或者nginx這樣的龐然大物,而選擇了很輕量的boa。原因是boa雖然原始支持IPv6,但是我想粗暴的把所有IPv4的socket套接字都替換成IPv6版本,嘗試做一個自定義的升級。結果需要改動的代碼非常少,不超過20行,boa就能完全支持IPv6。
配合實驗,寫了一個簡單的CGI,只是在版面echo字元串。如下圖:
▲ 圖20:瀏覽器使用IPv6地址訪問網路資源
這裡值得注意的是,在瀏覽器中使用IPv6的地址訪問web資源,IPv6的地址必須要使用中括弧「[]」包起來。
▲ 圖21:IPv6下的http報文從Server端抓包看,IPv6下的Web服務http報文,除了網路層L3的報文頭部不一樣之外,其餘的都和IPv4版本的沒有太大差別差別。
4.4IPv6的過渡技術實驗
這部分將在過渡技術介紹中一起實驗。
5、IPv6的過渡技術
IPv6的提出,最重要的目的就是解決公網IPv4耗盡的問題,而且IPv6協議的設計就考慮到了更加好的效率、安全、擴展等方面,可以那麼說,IPv6是未來網路發展的大趨勢。
但為什麼IPv6已經發展了十幾年了,目前在我們的工作和生活中還是比較少接觸和使用。
這裡的原因是非常的複雜,有技術上障礙,因為IPv6和IPv4是兩個完全不兼容的協議(在極少數的特定場景可以實現兼容),如果要從支持IPv4升級到IPv6,無論是應用程序用客戶端、伺服器程序端、路由器等等,都要同時支持IPv6才能解決問題,這個的升級改造需要花費的成本是巨大的。
而且,正是由於技術上的升級花費大量的人力物力,無論是運營商還是互聯網服務商,一方面要重視用戶的體驗問題,這個肯定不能強制客戶更新換代硬體設備和軟體,另一方面也要維護自身的投資和利益,更願意去選擇利用現有技術降低IPv4地址耗盡帶來的壓力,例如NAT的廣泛應用,就是IPv6推廣使用的一個重要的「障礙」。
由上所述,IPv4升級到IPv6肯定不會是一蹴而就的,是需要經歷一個十分漫長的過渡階段(用我廠通用的術語說,就是IPv4升級IPv6這個灰度的時間非常長),要數十年的時間都不為過。現階段,就出現了IPv4慢慢過渡到IPv6的技術(或者叫過渡時期的技術)。過渡技術要解決最重要的問題就是,如何利用現在大規模的IPv4網路進行IPv6的通信。
要解決上面的問題,這裡主要介紹3種過渡技術:
- 1)雙棧技術;
- 2)隧道技術;
- 3)轉換技術(有一些文獻叫做翻譯技術)。
本章節會對以上的過渡技術,選取幾個典型的、我們未來最有機會接觸到的具體的過渡技術結合實驗觀察過渡技術的具體實現和數據包的表現形式。
5.1什麼是雙棧技術?
這種技術其實很好理解,就是通信節點同時支持IPv4和IPv6雙棧。例如在同一個交換機下面有2個Linux的節點,2個節點都是IPv4/IPv6雙棧,節點間原來使用IPv4上的UDP協議通信傳輸,現在需要升級為IPv6上的UDP傳輸。由於2個節點都支持IPv6,那隻要修改應用程序為IPv6的socket通信基本達到目的了。
上面的例子在區域網通信的改造是很容易的。但是在廣域網,問題就變得十分複雜了。因為主要問題是在廣域網上的2個節點間往往經過多個路由器,按照雙棧技術的部署要求,之間的所有節點都要支持IPv4/IPv6雙棧,並且都要配置了IPv4的公網IP才能正常工作,這裡就無法解決IPv4公網地址匱乏的問題。因此,雙棧技術一般不會直接部署到網路中,而是配合其他過渡技術一起使用,例如在隧道技術中,在隧道的邊界路由器就是雙棧的,其他參與通信的節點不要求是雙棧的。
5.2什麼是隧道技術?
當前的網路是以IPv4為主,因此儘可能地充分利用IPv4網路進行IPv6通信是十分好的手段之一。隧道技術就是這樣子的一種過渡技術。
隧道將IPv6的數據報文封裝在IPv4的報文頭部後面(IPv6的數據報文是IPv4的載荷部分),IPv6通信節點之間傳輸的IPv6數據包就可以穿越IPv4網路進行傳輸。隧道技術的一個很重要的優點是透明性,通過隧道進行通信的兩個IPv6節點(或者節點上的應用程序)幾乎感覺不到隧道的存在。
▲ 圖22:IPv6典型的隧道
上圖是一種典型的隧道技術:路由器-路由器隧道,兩個IPv6網路中的主機通過隧道方式穿越了IPv4進行通信。其中C節點和D節點被稱為邊界路由器,邊界路由器必須要支持IPv4-IPv6雙棧。當IPv6網路1的主機A將IPv6數據包發給邊界路由器C,C對IPv6數據包進行IPv4封裝,然後在IPv4網路上進行傳輸,發送到邊界路由器D,D收到IPv4的數據包後剝掉IPv4的包頭,還原IPv6的數據包,發送到IPv6網路2的主機B。
根據隧道的出口入口的構成,隧道可以分為路由器-路由器,主機-路由器隧道、路由器-主機、主機-主機隧道等類型。
隧道的類型也分為手動配置類型和自動配置類型兩種,手動配置是指點對點的隧道是手動加以配置,例如手動配置點對點隧道外層的IPv4地址才能建立起隧道;自動配置是指隧道的建立和卸載是動態的,一般會把隧道外層的IPv4地址內嵌到數據包的目的IPv6地址裡面,在隧道路由器獲取該IPv6地址時候取出內嵌IPv4地址從而使用該IPv4地址作為隧道的對端來建立隧道。
下面就介紹幾種我們很可能會接觸到的具體的隧道技術。
在介紹具體的隧道技術前,特別要說明一下,Linux內核原生支持一種叫做sit(Simple Internet Transition)隧道。這個隧道專門用於IPv6-in-IPv4的數據封裝解封和傳輸,應用十分之廣泛,現在很多主流的IPv6隧道技術都能基於sit隧道實現。關於sit隧道的技術實現,可以查閱Linux內核源碼 net/ipv6/sit.c 。
5.3隧道技術之6to4隧道
6to4是當前使用得比較廣泛的一種自動配置隧道技術,這種技術採用特殊的IPv6地址,稱為6to4地址,這種地址是以2002開頭,接著後面的32位就是內嵌的隧道對端的IPv4地址。當邊界路由器收到這類目的地址,取出IPv4地址建立隧道。
6to4隧道一般用在路由器-路由器、主機-路由器、路由器-主機場景,典型的應用場景是兩個IPv6的站點內主機通過6to4隧道進行相互訪問。
6to4隧道的一個限制是內嵌的IPv4地址必須是公網地址。
6to4隧道實驗過程如下。
如下圖,就是本次6to4實驗中使用的隧道架構,該架構是典型的路由器-路由器隧道,隧道兩側的IPv6網路對隧道的存在無感知。
▲ 圖23:6to4路由器-路由器隧道在Linux下的sit隧道可以自適應為6to4隧道。 ▲ 圖24:Linux下配置sit隧道(6to4)上圖就是在路由器上配置sit隧道的命令,因為是使用6to4隧道,隧道的目的端點地址是從目的地址中獲取,因此只需要配置本地端點即可。 ▲ 圖25:瀏覽器通過隧道訪問web服務配置完隧道後,使用客戶端訪問web服務,可以正常訪問。 ▲ 圖26:web伺服器端抓取http報文在web服務端抓取http報文,可以看到,web服務獲取到就是一個普通的http請問報文。 ▲ 圖27:隧道內抓取http報文在隧道內抓取http報文,可以看到裡面的乾坤。這個不是一般的http報文,它比服務端抓取到的多了一層IPv4報文頭部,是隧道的外出通信協議,隧道內層IPv6才是真正的數據。IPv4報文頭部中的協議欄位,不是我們熟悉的TCP(6)/UDP(17)協議,而是IPv6-in-IPv4專屬的隧道協議類型。可以看到,經過隧道的數據報文,在隧道兩端的邊界路由器分別完成了隧道協議的封包和解包,在真正獲取到數據的節點看來,幾乎不感知隧道的存在。
5.4隧道技術之ISATAP隧道
ISATAP全稱是站點內自動隧道定址協議(Intra-Site Automatic Tunnel Addressing Protocol),用來為IPv4網路中的IPv6雙棧節點可以跨越IPv4網路訪問外部的IPv6節點。
ISATAP隧道一般用於主機-主機、主機-路由器的場景。
ISATAP隧道實驗過程如下所示。
如下圖就是本次實驗使用的架構,是一種典型的主機-路由器場景。實驗中需要在路由器2上部署radvd服務,用於客戶端進行無狀態自動配置地址。Linux下的ISATAP隧道也是可以使用sit隧道實現。
▲ 圖28:ISATAP主機-路由器隧道 ▲ 圖29:Windows下配置ISATAP隧道實驗用的客戶端使用windows 7,原生支持ISATAP隧道,如上圖,需要進入netsh開啟並且設置ISATAP的路由器地址(支持域名)。 ▲ 圖30:ISATAP隧道中的無狀態自動配置當客戶端設置完router後,隧道已經建立,客戶端便發起了無狀態自動配置流程,可以看到上面的截圖路由器通過隧道將前綴信息下發給客戶端,客戶端完成無狀態自動配置,獲取到公網IP地址。 ▲ 圖31:ISATAP隧道介面地址在windows 7上查看ISATAP介面,獲取到公網地址。這個地址類型是ISATAP專用的地址結構,由64位全球單播路由前綴:200(0):5e5f:w.x.y.z組成(w.x.y.z是客戶端的IPv4地址)。 ▲ 圖32:使用ISATAP隧道訪問web服務如上圖,使用ISATAP隧道訪問web服務,在隧道內的數據抓包,可以看到和6to4的類似,這裡就不再深入闡述。5.5隧道技術之Teredo隧道
前面的隧道技術,主要是在IPv4的數據報文承載著IPv6的數據報文,這是一種特殊的數據包格式(IPV6-in-IPv4),不同於我們熟悉的TCP、UDP等傳輸層協議。而我們平常接觸到的網路都存在於NAT架構中(例如我們的辦公網路和家庭網路),在這種網路架構中,路由器僅對於TCP、UDP等傳輸層協議做NAT處理,而無法正確處理IPv6-in-IPv4這種報文,例如使用ISATAP隧道,IPv6雙棧節點與ISATAP路由器之前如果存在NAT,ISATAP建立隧道失敗;6to4隧道也會遇到同樣的問題。
Teredo隧道是有微軟公司主導的一項隧道技術,主要用於在NAT網路架構下建立穿越NAT的隧道。
Teredo隧道的核心思路,是將IPv6的數據封裝成IPv4的UDP數據包,利用NAT對IPv4的UDP支持進行穿越NAT的傳輸,當UDP包到達隧道的另外一端後,再把IPv4的包頭、UDP包頭剝離,還原IPv6的數據包,再進行下一步的IPv6數據通信轉發。Teredo節點會分配一個以2001::/32的前綴,而且地址中還包含Teredo的伺服器、標誌位和客戶端外部映射模糊地址和埠號等信息。
Teredo的實現還會遇到NAT的類型不同而被限制的問題。NAT的類型有錐形NAT、受限制的NAT、對稱NAT幾種,Teredo只能在錐形NAT和受限制的NAT的環境下正常工作,而且在這兩種NAT需要處理的邏輯又是不一樣的。因此Teredo整體的實現會比較複雜。
實驗環境搭建:
在Linux平台下有開源的Teredo實現版本:miredo。由於時間和文章篇幅的原因,而且部署miredo比較複雜,因此這裡的實驗等以後有機會再補充。5.6什麼是轉換技術?(有一些文獻叫做:翻譯技術)
隧道技術是比較好地解決了在很長期一段時間內還是IPv4網路是主流的情況下IPv6節點(或者雙棧節點)間的通信問題。但是由於IPv4到IPv6的過渡是十分漫長的,因此也需要解決IPv6節點與IPv4節點通信的問題。協議轉換技術可以用來解決這個問題。
協議轉換技術根據協議在網路中位置的不同,分為網路層協議轉換、傳輸層協議轉換和應用層協議轉換等。協議轉換技術的核心思路就是在IPv4和IPv6通信節點之間部署中間層,將IPv4和IPv6相互映射轉換。
我們非常熟悉的NAT也是一種典型的協議轉換技術,是將私網IPv4地址映射轉換為公網IPv4地址,這種轉換技術又稱為NAT44。而我們接著要重點介紹的名為NAT64/DNS64的協議轉換技術。
5.7轉換技術之NAT64/DNS64
提到NAT64/DNS64,相信做iOS客戶端開發的同學一定非常熟悉。在2016年中開始,蘋果要求app必須支持IPv6網路。而蘋果官方提供的過渡解決方案正是NAT64/DNS64。
以下是蘋果提供的技術圖:
▲ 圖33:蘋果提供的過渡技術解決方案NAT64/DNS64分為NAT64、DNS64兩大方面,兩者需要結合使用。
DNS64在RFC6147中明確定義,將IPv6的地址記錄AAAA DNS查詢消息轉換為IPv4的地址記錄查詢。當IPv6節點發起DNS請求,NAT64/DNS64中間層同時發起A域名查詢和AAAA域名查詢。如果僅有A域名查詢的IPv4地址響應,表明IPv6節點需要訪問一個IPv4的節點,NAT64/DNS64中間層將回應的IPv4地址轉換為IPv6地址,返回給IPv6節點。
IPv6節點使用獲取到的IPv6服務端地址進行訪問,數據包會經過NAT64/DNS64中間層,中間層將IPv6地址映射轉換為IPv4的地址進行訪問。
實驗環境搭建過程如下。
Linux平台下有多個NAT64的開源軟體,實現方式各有不同,有純內核態實現的ecdysis,也有用戶態實現的tayga。
DNS64的實現可以使用著名的開源DNS服務BIND就可以很好地支持,詳細可以查看上面2個開源軟體的搭建說明。
時間的原因,還沒有把NAT64/DNS64的開源軟體研究透徹,因此這裡的實踐等以後有機會再補上。
PS:在研究tayga和miredo源碼的時候,發現了在Linux平台上面有一些有趣的東西,如下圖,是tayga的軟體實現框架。
▲ 圖34:Linux下的一個有趣的虛擬設備Linux內核自帶了一個軟體虛擬設備,也是一種隧道的實現(/dev/net/tun),該設備可以實現將內核態的網路數據發送到用戶態,用戶態修改後再返回給內核態,用戶態的進程負責完成NAT64這一次「偷龍轉鳳」操作。
關於/dev/net/tun設備的實現,可以查閱Linux內核源碼drivers/net/tun.c,一些著名的VPN軟體例如openvpn等,都是以它作為實現基礎。
本章只介紹了一些典型的過渡技術,其實過渡技術種類還有很多,有一些在實驗室階段,有一些已經商用,有一些已經被廢棄,但是總的來說,每一種過渡技術都是在解決特定時期特定場景下的過渡問題。
6、IPv6 Socket編程應該注意的問題
在《IPv6 Socket編程》一文中,ray已經很詳細介紹了IPv6下的socket編程細節和應該注意的問題。本章作為一個補充,介紹一下IPv6 socket編程可能還會遇到的問題。
6.1IPv6地址編碼
IPv4地址本質是一個32位整數,因此一般無論是存儲層還是邏輯層,都經常將點分制的IPv4字元串地址轉為32位整數使用。而在IPv6,情況就複雜多了(可能也有同學就想到,光是原子性就很難保證了)。
舉一個典型的例子,現在有個需求,分別統計每個IP的訪問頻次。
在IPv4的情況下,最簡單就是STL用std::map搞定(單線程),土豪一點的可以開個16G的數組用空間換時間。
但是在IPv6的場景下,那就尷尬了,IPv6可是個128位整數,可以用map嗎?可能會有人直接將原始的字元串類型的IPv6地址作為key來累計。一旦那麼用,就要十分注意了。由於IPv6是支持前導0和連續0的壓縮表示方式,而且支持英文字母大小寫,例如:
2001:db8:4::41
2001:db8:4:0:0:0:0:0:412001:0db8:4::412001B8:4::41
這4個都是合法的IPv6地址,如果將輸入毫無修改地作為key來累計,那必須會將累計邏輯分散了,最終得不到正確的頻率結果。類似的問題也在MAC地址(BSSID)上面,由於MAC地址分號間的數字前導0可以省略,並且也是支持大小寫英文字母,所以也是會同樣的問題。在微信安全中心,MAC地址的邏輯統一轉為64位整數處理,情況相對還好。
但是到了IPv6有木有更好的解決辦法呢?答案是肯定的,但是需要具體問題具體分析。
在上面的頻率例子比較優雅的做法,依然用map的話,可以利用自定義key類型解決,這個方法需要重載自定義類型的比較符號』<』,如下圖所示:
▲ 圖35:自定義IPv6地址結構其中struct in6_addr就是一個128位的IPv6地址結構體。 ▲ 圖36:使用std::map實現IPv6頻率其實還有更優雅的方式,直接將IPv6的地址強制轉為2個64位整數來比較,if else會寫得更少一些,效率更高一些。
上面說到2個64位整數,微信安全中心有一些靜態的key-value數據查詢(批量寫,多次讀),其中key是MD5,我們將MD5也是作為2個64位整數來對待,將2個64位整數聯合排序,寫入內存,然後使用兩次二分查找的方式搜索,效率非常高。在這種場景下面,IPv6也是可以用類似的方法處理。
IPv6地址結構,以後很可能會給我們的編程或多或少帶來一些「未知」的坑-_-||。
6.2IPv6 socket「兼容」IPv4的情況
在IPv4和IPv6共存的一個很長的時間裡,在socket編程上不得不面對的就是IPv6和IPv4一定程度的「兼容問題」。而在文章前面有提到,IPv6和IPv4和完全不兼容的兩種協議,但是IPv6協議的地址空間更大,是可以使用IPv6的地址表示IPv4地址,例如IPv4映射地址,因此,在很特殊的情況下,IPv4和IPv6可以實現「兼容」,但是這種兼容是很有限的。在Linux平台下,這種「兼容性」是如何表現的,我們這裡來分析一下。
在Linux下面,以IPv6下的UDP Socket舉例,詳細如下。
有個UDP協議的Server改造IPv6,該Server機器上有一個網卡並且同時配置IPv6和IPv4地址,支持雙棧。Server進程創建IPv6 UDP socket套接字,綁定Server本地任意地址(IPv4和IPv6都是以全0地址為綁定任意地址)。客戶端是IPv4,向這個Server發送UDP請求數據包。
▲ 圖37:IPv6服務收到IPv4報文可以看到的是,IPv6的socket會正常收到客戶端的數據報文,並且會將IPv4地址轉化為映射地址,為了明確這個邏輯,我們分析Linux內核的實現。
▲ 圖38:IPv6下UDP socket收到IPv4數據包內核實現IPv6的socket收到數據包,如果是IPv4協議,則將來源IPv4的IP地址轉為IPv6的IPv4映射地址。與實驗的結果很一致。
如果Server的IPv6 socket按照這個來源地址返回數據包,那麼內核又是如何處理的呢?
▲ 圖39:IPv6下UDP socket發送IPv4數據包內核實現首先內核會判斷目的地址是否為IPv6的IPv4映射地址,如果是映射地址,那麼要發送的數據是IPv4數據,直接以IPv4協議棧的形式發送該數據(udp_sendmsg是IPv4 udp發送介面)。
可以看到,Linux內核本身對這類雙棧上的改造做了一定的適配,我們可以根據內核的這種特性去進行改造工作。
6.3使用鏈路本地地址
從前面的章節可以知道,IPv6具有自動配置地址的能力。鏈路本地地址是IPv6要求在每個介面默認自動配置生成的地址,用於鏈路上的通信,路由器不能轉發鏈路本地地址。除了以上提到的特徵外,鏈路本地地址就是一個普通的IPv6地址,我們可以使用這類地址做socket編程通信。
但是我們在IPv6 Socket編程的時候使用鏈路本地地址,有一個細節需要注意。
▲ 圖40:IPv6地址結構在IPv6地址結構中(對應於IPv4的struct sockaddr_in),有一個我們非常陌生的欄位scope_id,這個欄位在我們使用鏈路本地地址來編程的時候是必須要使用的,這個欄位表示我們需要選擇介面ID。為什麼需要需要有這麼一個欄位,那是因為鏈路本地地址的特殊性,一個網路節點可以有多個網路介面,多個網路介面可以有相同的鏈路本地地址,例如我們需要bind一個本地鏈路地址,這個時候就會有衝突,操作系統無法決策需要綁定的是哪個介面的本地鏈路地址。
又例如,如果我們在直連的2個主機之間直接用鏈路本地地址ping的話,會ping失敗。
因此IPv6引入了scope_id來解決這個問題,scope_id指定了使用哪個網路介面。
如何查看這個網路介面(網卡)的scope_id是多少?
在Linux下查看網路介面的scope_id:
▲ 圖41:Linux下查看網路介面scope id使用ip addr命令可以查看每個介面的scope_id,如圖第一列的數字就是scope_id。
在windows下查看scope_id:
▲ 圖42:Windows下查看網路介面scope id最後的百分號%後面的數字就是該網路介面的scope_id。
Windows下也可以使用route print -6查看介面列表,列表第一列數字就是scope_id。
因此,在使用鏈路本地地址編程的時候,需要把這個scope_id賦值到sin6_scope_id欄位。
而在使用ping命令的時候,需要在地址後面加上%和scope_id才能ping成功,如圖:
▲ 圖43:使用鏈路本地地址ping關於這個scope id,詳細可以查看RFC2553。
7、全文總結
本文主要科普介紹了IPv6的基本內容,配合各種實驗分析比較清晰認識了IPv6的各種基本概念;也介紹一些「超綱」的內容(我們的工作中很可能不會接觸到),但是我覺得這類內容在技術實現上十分有趣,可以在一些技術的方法和思路上面可能會給我們一些通用的啟示,例如NAT64/DNS64就是使用中間層來處理IPv4和IPv6互通的問題,我們的工作中也確實經常遇到類似的技術問題。
IPv6本身是一個很龐大的體系,還有很多高級內容沒有介紹(IPv6-IPSec、移動IPv6等等)。而且查看和IPv6相關的RFC,不斷在做修正,Linux內核的IPv6模塊代碼也不斷有配合新的RFC修改來做調整,引入新的邏輯,以適應各種場景的實際需求。有興趣的同學可以一直留意RFC的變化和緊跟Linux內核的版本發布。
本文是我在結合各種文獻和實驗對IPv6理解的一個總結歸納,難免會有理解偏差和手抖的地方,希望各位同學熟悉的話能幫忙指出其中的錯誤,並且提供修改建議和意見,謝謝:)。
(——接上篇《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》,全文完——)
8、參考文獻
1、《深入解析IPv6(第3版)》
2、《TCP/IP詳解-卷1協議》
3、《TCP/IP協議原理與應用(第4版)》
4、《精通Linux內核網路》
5、RFC4380 「Teredo: Tunneling IPv6 over UDP through Network Address Translations」
6、RFC3596 「DNS Extensions to support IP version 6」
7、RFC4193 「Unique Local IPv6 Unicast Address」
8、RFC3879 「Deprecating Site Local Address」
9、RFC2553 「Basic Socket Interface Extensions for IPv6」
10、RFC4214 「Intra-Site Automatic Tunnel Address Protocol(ISATAP)」
11、RFC6147 「DNS Extensions for Network Address Translation from IPv6 Clients to IPv4 Servers」
12、RFC6052 「IPv6 Addressing of IPv4/IPv6 Translators」
13、RFC6146 「Stateful NAT64: Network Address and Protocol Translation from IPv6 Clients to IPv4 Servers」
14、RFC3068 「An Anycast Prefix for 6to4 Deployment」
15、RFC2460 「Internet Protocol, Version 6 Specification」
16、RFC4291 「IP Version 6 Addressing Architecture」
17、RFC1971 「IPv6 Stateless Address Autoconfiguration」
18、RFC4861 「Neighbor Discovery for IP version6」
19、https://developer.apple.com/libr ... P40010220-CH213-SW1
9、文中使用到的開源軟體列表
1、Linux-2.6.32.27源碼 (www.kernel.org)
2、Linux-3.10.108源碼 (www.kernel.org)
3、Linux-4.9.75源碼 (www.kernel.org)
4、無狀態自動配置服務radvd (http://www.litech.org/radvd/)
5、NAT64服務tayga(http://www.litech.org/tayga/)
6、NAT64/DNS64服務ecdysis (http://ecdysis.viagenie.ca/)
7、teredo服務mirodo(https://www.remlab.net/miredo/)
8、輕量級web伺服器boa (http://www.boa.org/)
附錄:更多相關文章
[1] 更多網路編程基礎資料:
《TCP/IP詳解 - 第11章·UDP:用戶數據報協議》《TCP/IP詳解 - 第17章·TCP:傳輸控制協議》《TCP/IP詳解 - 第18章·TCP連接的建立與終止》《TCP/IP詳解 - 第21章·TCP的超時與重傳》《技術往事:改變世界的TCP/IP協議(珍貴多圖、手機慎點)》《通俗易懂-深入理解TCP協議(上):理論基礎》《通俗易懂-深入理解TCP協議(下):RTT、滑動窗口、擁塞處理》《理論經典:TCP協議的3次握手與4次揮手過程詳解》《理論聯繫實際:Wireshark抓包分析TCP 3次握手、4次揮手過程》《計算機網路通訊協議關係圖(中文珍藏版)》《UDP中一個包的大小最大能多大?》《P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介》《P2P技術詳解(二):P2P中的NAT穿越(打洞)方案詳解》《P2P技術詳解(三):P2P技術之STUN、TURN、ICE詳解》《通俗易懂:快速理解P2P技術中的NAT穿透原理》《高性能網路編程(一):單台伺服器並發TCP連接數到底可以有多少》《高性能網路編程(二):上一個10年,著名的C10K並發連接問題》《高性能網路編程(三):下一個10年,是時候考慮C10M並發問題了》《高性能網路編程(四):從C10K到C10M高性能網路應用的理論探索》《不為人知的網路編程(一):淺析TCP協議中的疑難雜症(上篇)》《不為人知的網路編程(二):淺析TCP協議中的疑難雜症(下篇)》《不為人知的網路編程(三):關閉TCP連接時為什麼會TIME_WAIT、CLOSE_WAIT》《不為人知的網路編程(四):深入研究分析TCP的異常關閉》《不為人知的網路編程(五):UDP的連接性和負載均衡》《不為人知的網路編程(六):深入地理解UDP協議並用好它》《不為人知的網路編程(七):如何讓不可靠的UDP變的可靠?》《網路編程懶人入門(一):快速理解網路通信協議(上篇)》《網路編程懶人入門(二):快速理解網路通信協議(下篇)》《網路編程懶人入門(三):快速理解TCP協議一篇就夠》《網路編程懶人入門(四):快速理解TCP和UDP的差異》《網路編程懶人入門(五):快速理解為什麼說UDP有時比TCP更有優勢》《技術掃盲:新一代基於UDP的低延時網路傳輸層協議——QUIC詳解》《讓互聯網更快:新一代QUIC協議在騰訊的技術實踐分享》《現代移動端網路短連接的優化手段總結:請求速度、弱網適應、安全保障》《聊聊iOS中網路編程長連接的那些事》《移動端IM開發者必讀(一):通俗易懂,理解移動網路的「弱」和「慢」》《移動端IM開發者必讀(二):史上最全移動弱網路優化方法總結》《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》《IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)》>> 更多同類文章 ……[2] QQ、微信團隊分享的其它技術文章:
《微信朋友圈千億訪問量背後的技術挑戰和實踐總結》
《騰訊技術分享:騰訊是如何大幅降低帶寬和網路流量的(圖片壓縮篇)》
《騰訊技術分享:騰訊是如何大幅降低帶寬和網路流量的(音視頻技術篇)》
《微信團隊分享:微信移動端的全文檢索多音字問題解決方案》
《騰訊技術分享:Android版手機QQ的緩存監控與優化實踐》
《微信團隊分享:iOS版微信的高性能通用key-value組件技術實踐》
《微信團隊分享:iOS版微信是如何防止特殊字元導致的炸群、APP崩潰的?》
《騰訊技術分享:Android手Q的線程死鎖監控系統技術實踐》
《微信團隊原創分享:iOS版微信的內存監控系統技術實踐》
《讓互聯網更快:新一代QUIC協議在騰訊的技術實踐分享》
《iOS後台喚醒實戰:微信收款到賬語音提醒技術總結》
《騰訊技術分享:社交網路圖片的帶寬壓縮技術演進之路》
《微信團隊分享:視頻圖像的超解析度技術原理和應用場景》
《微信團隊分享:微信每日億次實時音視頻聊天背後的技術解密》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(上篇)》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(下篇)》
《騰訊團隊分享:手機QQ中的人臉識別酷炫動畫效果實現詳解》
《騰訊團隊分享 :一次手Q聊天界面中圖片顯示bug的追蹤過程分享》
《微信團隊分享:微信Android版小視頻編碼填過的那些坑》
《微信手機端的本地數據全文檢索優化之路》
《企業微信客戶端中組織架構數據的同步更新方案優化實戰》
《微信團隊披露:微信界面卡死超級bug「15。。。。」的來龍去脈》
《QQ 18年:解密8億月活的QQ後台服務介面隔離技術》
《月活8.89億的超級IM微信是如何進行Android端兼容測試的》
《以手機QQ為例探討移動端IM中的「輕應用」》
《一篇文章get微信開源移動端資料庫組件WCDB的一切!》
《微信客戶端團隊負責人技術訪談:如何著手客戶端性能監控和優化》
《微信後台基於時間序的海量數據冷熱分級架構設計實踐》
《微信團隊原創分享:Android版微信的臃腫之困與模塊化實踐之路》
《微信後台團隊:微信後台非同步消息隊列的優化升級實踐分享》
《微信團隊原創分享:微信客戶端SQLite資料庫損壞修復實踐》
《騰訊原創分享(一):如何大幅提升移動網路下手機QQ的圖片傳輸速度和成功率》
《騰訊原創分享(二):如何大幅壓縮移動網路下APP的流量消耗(下篇)》
《騰訊原創分享(三):如何大幅壓縮移動網路下APP的流量消耗(上篇)》
《微信Mars:微信內部正在使用的網路層封裝庫,即將開源》
《如約而至:微信自用的移動端IM網路層跨平台組件庫Mars已正式開源》
《開源libco庫:單機千萬連接、支撐微信8億用戶的後台框架基石 [源碼下載]》
《微信新一代通信安全解決方案:基於TLS1.3的MMTLS詳解》
《微信團隊原創分享:Android版微信後台保活實戰分享(進程保活篇)》
《微信團隊原創分享:Android版微信後台保活實戰分享(網路保活篇)》
《Android版微信從300KB到30MB的技術演進(PPT講稿) [附件下載]》
《微信團隊原創分享:Android版微信從300KB到30MB的技術演進》
《微信技術總監談架構:微信之道——大道至簡(演講全文)》
《微信技術總監談架構:微信之道——大道至簡(PPT講稿) [附件下載]》
《如何解讀《微信技術總監談架構:微信之道——大道至簡》》
《微信海量用戶背後的後台系統存儲架構(視頻+PPT) [附件下載]》
《微信非同步化改造實踐:8億月活、單機千萬連接背後的後台解決方案》
《微信朋友圈海量技術之道PPT [附件下載]》
《微信對網路影響的技術試驗及分析(論文全文)》
《一份微信後台技術架構的總結性筆記》
《架構之道:3個程序員成就微信朋友圈日均10億發布量[有視頻]》
《快速裂變:見證微信強大後台架構從0到1的演進歷程(一)》
《快速裂變:見證微信強大後台架構從0到1的演進歷程(二)》
《微信團隊原創分享:Android內存泄漏監控和優化技巧總結》
《全面總結iOS版微信升級iOS9遇到的各種「坑」》
《微信團隊原創資源混淆工具:讓你的APK立減1M》
《微信團隊原創Android資源混淆工具:AndResGuard [有源碼]》
《Android版微信安裝包「減肥」實戰記錄》
《iOS版微信安裝包「減肥」實戰記錄》
《移動端IM實踐:iOS版微信界面卡頓監測方案》
《微信「紅包照片」背後的技術難題》
《移動端IM實踐:iOS版微信小視頻功能技術方案實錄》
《移動端IM實踐:Android版微信如何大幅提升交互性能(一)》
《移動端IM實踐:Android版微信如何大幅提升交互性能(二)》
《移動端IM實踐:實現Android版微信的智能心跳機制》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》
《移動端IM實踐:谷歌消息推送服務(GCM)研究(來自微信)》
《移動端IM實踐:iOS版微信的多設備字體適配方案探討》
《信鴿團隊原創:一起走過 iOS10 上消息推送(APNS)的坑》
《騰訊信鴿技術分享:百億級實時消息推送的實戰經驗》
《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》
《IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)》
>>更多同類文章 ……
(本文同步發佈於:http://www.52im.net/thread-1607-1-1.html)
推薦閱讀:
※在VS2015中用Halcon13 Variables Inpect插件
※如何看待馮大輝推出的readhub?
※人腦開發100%會發生啥事?
※丟失的iphone都去哪了!
※如何評價2018.05.17發布的一加6手機?