一份完整的 IPv6 環(huán)境下 DNS 相關(guān)測(cè)試
董濤,網(wǎng)易游戲高級(jí)運(yùn)維工程師,主要工作方向?yàn)榫W(wǎng)易集團(tuán) DNS 的運(yùn)維與開(kāi)發(fā)。
張欣接,網(wǎng)易集團(tuán) DNS 團(tuán)隊(duì)負(fù)責(zé)人,負(fù)責(zé)網(wǎng)易域名系統(tǒng)的架構(gòu)設(shè)計(jì)及生態(tài)建設(shè)。
一、IPv6 支持度報(bào)告
IPv6 簡(jiǎn)介
IPv6(Internet Protocol version 6,互聯(lián)網(wǎng)通信協(xié)議第 6 版)是用于數(shù)據(jù)包交換互聯(lián)網(wǎng)絡(luò)的網(wǎng)絡(luò)層協(xié)議,是 IETF(互聯(lián)網(wǎng)工程任務(wù)小組 Internet Engineering Task Force,簡(jiǎn)稱 IETF)設(shè)計(jì)的用來(lái)替代 IPv4 協(xié)議的互聯(lián)網(wǎng)協(xié)議版本。
隨著電子技術(shù)及網(wǎng)絡(luò)技術(shù)的發(fā)展,計(jì)算機(jī)網(wǎng)絡(luò)已經(jīng)與人們的生活密切相關(guān),可能身邊的每一樣電子設(shè)備都需要連入網(wǎng)絡(luò),IPv4 的地址數(shù)量已經(jīng)無(wú)法滿足。IPv6 的應(yīng)用將徹底解決這些問(wèn)題。IPv6 由 128 比特位構(gòu)成,單從數(shù)量級(jí)上來(lái)說(shuō),IPv6 所擁有的地址容量是 IPv4 的約 8×10 28 倍,達(dá)到 2 128(約 3.4 × 10 38)個(gè)。這不但解決了網(wǎng)絡(luò)地址資源數(shù)量的問(wèn)題,同時(shí)也為物聯(lián)網(wǎng)的發(fā)展提供了基礎(chǔ)。
IPv6 地址的表達(dá)形式采用 32 個(gè)十六進(jìn)制數(shù),由兩個(gè)邏輯部分組成:一個(gè) 64 位的網(wǎng)絡(luò)前綴和一個(gè) 64 位的主機(jī)地址,主機(jī)地址通常根據(jù)物理地址自動(dòng)生成,叫做 EUI-64(或者 64- 位擴(kuò)展唯一標(biāo)識(shí))。例如 2001:0db8:85a3:08d3:1319:8a2e:0370:7344 是一個(gè)合法的 IPv6 地址。
IPv6 全球部署更新
-
2008 年,歐盟發(fā)布了“歐洲部署 IPv6 行動(dòng)計(jì)劃”
-
2009 年,日本發(fā)布《IPv6 行動(dòng)計(jì)劃》
-
2010 年,美國(guó)政府發(fā)布 IPv6 行動(dòng)計(jì)劃
-
2010 年,韓國(guó)發(fā)布“下一代互聯(lián)網(wǎng)協(xié)議(IPv6) 促進(jìn)計(jì)劃”
-
2012 年,加拿大政府發(fā)布了《加拿大政府 IPv6 戰(zhàn)略》
-
2017 年,國(guó)務(wù)院辦公廳印發(fā)《推進(jìn)互聯(lián)網(wǎng)協(xié)議第六版(IPv6)規(guī)模部署行動(dòng)計(jì)劃》
操作系統(tǒng) IPv6 支持度
應(yīng)用軟件 IPv6 支持度
客戶端軟件
1、瀏覽器
服務(wù)器軟件
1、程序開(kāi)發(fā)軟件
2、數(shù)據(jù)庫(kù)
總結(jié)
毋庸置疑,下一代互聯(lián)網(wǎng) IPv6 是萬(wàn)物互連,智能化時(shí)代基礎(chǔ)網(wǎng)絡(luò)的重要支撐協(xié)議,但是從一個(gè)只擁有 IPv4 協(xié)議的巨型網(wǎng)絡(luò)要全面、平穩(wěn)地過(guò)渡到一個(gè)純 IPv6 網(wǎng)絡(luò)需要一段極為漫長(zhǎng)的時(shí)間。從報(bào)告統(tǒng)計(jì)的數(shù)據(jù)來(lái)看,各種基礎(chǔ)軟件和應(yīng)用軟件都已基本支持 IPv6?,F(xiàn)在在國(guó)內(nèi)的環(huán)境下,IPv6 的基礎(chǔ)環(huán)境還需要完善,為此工信部也發(fā)布了
《推進(jìn)互聯(lián)網(wǎng)協(xié)議第六版(IPv6)規(guī)模部署行動(dòng)計(jì)劃》(http://www.miit.gov.cn/n1146290/n4388791/c6166476/content.html)
推動(dòng)各單位加快支持 IPv6。
IPv6 支持度報(bào)告的數(shù)據(jù)來(lái)源是:下一代國(guó)家互聯(lián)網(wǎng)中心在 2017 年 11 月發(fā)布的 IPv6 支持度報(bào)告
(https://www.ipv6ready.org.cn/public/download/ipv6.pdf), 感興趣的同學(xué)可以查看原文。
二、IPv6 環(huán)境下 DNS 相關(guān)測(cè)試
背景介紹
名詞簡(jiǎn)介
-
A 記錄
A 記錄是一個(gè)域名指向 IPv4 地址的解析結(jié)果,即最常見(jiàn)的記錄類型, 例如 ipv6test.ntes53.netease.com. 1800 IN A 123.58.166.70
-
AAAA 記錄
AAAA 是一個(gè)域名指向 IPv6 地址的解析結(jié)果。如果想要一個(gè)域名解析到 IPv6 地址,則需要設(shè)置此種類型的解析結(jié)果。同一個(gè)域名可以同時(shí)有 A 與 AAAA 兩種記錄類型, 例如 ipv6test.ntes53.netease.com. 1800 IN AAAA 2403:c80:100:3000::7b3a:a646
-
緩存 DNS 服務(wù)器
用戶直接使用的 DNS 服務(wù)器,各種平臺(tái)、操作系統(tǒng)上直接設(shè)置的 DNS 服務(wù)器,常見(jiàn)的有 8.8.8.8, 114.114.114.114
-
權(quán)威 DNS 服務(wù)器
用于域名的管理。權(quán)威 DNS 服務(wù)器只對(duì)自己所擁有的域名進(jìn)行域名解析,對(duì)于不是自己的域名則拒絕應(yīng)答。例如網(wǎng)易的權(quán)威 DNS 服務(wù)器只會(huì)響應(yīng)網(wǎng)易域名的請(qǐng)求,對(duì)于其他域名,則拒絕應(yīng)答。
-
雙棧網(wǎng)絡(luò)環(huán)境
雙棧網(wǎng)絡(luò)環(huán)境即客戶端或服務(wù)器同時(shí)擁有 IPv4、IPv6 兩種網(wǎng)絡(luò)環(huán)境,可以簡(jiǎn)單的理解為機(jī)器上既有 IPv4 地址又有 IPv6 地址
測(cè)試場(chǎng)景
下文中所有測(cè)試使用的程序均為測(cè)試方法中的程序
1.目前純 IPv4 環(huán)境下,僅新增 AAAA(IPv6) 記錄之后,對(duì)已有程序的影響
假定已經(jīng)存在了一個(gè)程序(C 程序、python 程序、瀏覽器等),通過(guò)域名訪問(wèn)某個(gè)服務(wù),現(xiàn)在在 IPv4 環(huán)境下一切工作正常。當(dāng)給這個(gè)域名增加了 AAAA 記錄之后,測(cè)試對(duì)目前的程序的影響。
域名解析
HTTP 請(qǐng)求
客戶端
結(jié)論
-
當(dāng)在某域名原有的 A 記錄類型的基礎(chǔ)上新增 AAAA 記錄后,原有的程序工作正常
2.客戶端 IPv6/v4 雙棧環(huán)境下,測(cè)試程序的行為
假定用戶的環(huán)境是雙棧環(huán)境,假定一個(gè)服務(wù)通過(guò)域名對(duì)外提供服務(wù),測(cè)試這種情況下程序的行為。
域名解析
HTTP 請(qǐng)求
客戶端
結(jié)論
-
當(dāng)域名同時(shí)存在 A 與 AAAA 記錄,并且網(wǎng)絡(luò)類型為雙棧網(wǎng)絡(luò)時(shí),絕大多數(shù)程序工作正常。僅有一種情況例外,即程序中使用了 gethostbyname 函數(shù),同時(shí) resolv.conf 中配置了 options inet6 時(shí),此時(shí)程序會(huì)返回錯(cuò)誤的解析結(jié)果
-
RFC 以及絕大多數(shù)實(shí)現(xiàn)方式,均回優(yōu)先使用 IPv6 地址建立連接
-
雙棧環(huán)境下,客戶端使用 IPv4 與 IPv6 緩存 DNS 服務(wù)器獲取的解析結(jié)果是一致的
3. 客戶端純 IPv6 環(huán)境下,測(cè)試能否正常工作
假定用戶只有 IPv6 地址,DNS 也是使用 IPv6 地址 (DNS 必須有雙棧環(huán)境,因?yàn)楝F(xiàn)在很多權(quán)威服務(wù)器沒(méi)有 IPv6 地址,純 IPv6 環(huán)境下無(wú)法正常工作),假定一個(gè)服務(wù)通過(guò)域名(同時(shí)擁有 A、AAAA 記錄)對(duì)外提供服務(wù),測(cè)試服務(wù)是否可以正常訪問(wèn)。
域名解析
HTTP 請(qǐng)求
客戶端
結(jié)論
當(dāng)某域名即存在 A 記錄 又存在 AAAA 記錄時(shí):
-
如果程序中使用了 gethostbyname 時(shí),程序可能會(huì)拿到錯(cuò)誤的解析結(jié)果,取決于 resolv.conf 的配置(當(dāng)配置了 option inet6 時(shí),會(huì)獲取到錯(cuò)誤的解析結(jié)果)
-
Windows 在這種情況下,部分應(yīng)用工作不正常。在指定使用 IPv6 socket 的情況下,程序工作正常。
-
根據(jù)安卓官方的描述,Android 6.0 之后的版本已經(jīng)支持 IPv6,但是根據(jù)對(duì)國(guó)內(nèi)大多數(shù)廠商的安卓手機(jī)的調(diào)研,目前國(guó)內(nèi)安卓手機(jī)很少可以原生支持 IPv6
4. DNS 解析測(cè)試
這里測(cè)試了緩存服務(wù)器和權(quán)威服務(wù)器在各種網(wǎng)絡(luò)環(huán)境下,優(yōu)先使用的解析鏈路。
結(jié)論
當(dāng)權(quán)威服務(wù)器和緩存服務(wù)器均支持 ipv6 時(shí),緩存服務(wù)器優(yōu)先使用 ipv6 鏈路進(jìn)行解析,其他情況均使用 ipv4 鏈路進(jìn)行解析。
結(jié)論
-
經(jīng)過(guò)測(cè)試與查證,
gethostbyname
不支持 IPv6,使用此函數(shù)可能會(huì)拿到錯(cuò)誤的結(jié)果或者程序拋出異常。建議使用getaddrinfo
函數(shù)取代此函數(shù) -
目前已經(jīng)存在 A 記錄的域名,添加 AAAA 記錄后,不管客戶端與服務(wù)端的網(wǎng)絡(luò)環(huán)境如何:
-
絕大多數(shù)情況下對(duì)客戶端與服務(wù)端工作正常
-
下面一種情況下會(huì)出現(xiàn)工作異常:
當(dāng)使用了 C 的 gethostbyname 并且在 resolv.conf 中配置了 options inet6時(shí),此函數(shù)返回錯(cuò)誤的結(jié)果
-
-
經(jīng)過(guò)測(cè)試,雙棧網(wǎng)絡(luò)下 IPv4 與 IPv6 的優(yōu)先級(jí):
-
優(yōu)先使用 IPv6 發(fā)起解析請(qǐng)求
-
優(yōu)先使用 IPv6 請(qǐng)求建立連接 (TCP, UDP)
-
優(yōu)先解析 A 地址記錄
-
參考資料
-
Windows 8 IPv4 與 IPv6 選擇的方法:Connecting with IPv6 in Windows8
(https://blogs.msdn.microsoft.com/b8/2012/06/05/connecting-with-ipv6-in-windows-8/) -
Windows 當(dāng) IPv6 不可用后的回退機(jī)制:Is there any setting for connection timeout when IPv6 fallback to IPv4?
(https://social.technet.microsoft.com/Forums/en-US/d09e938a-a594-4766-8898-3926a81fc5dc/is-there-any-setting-for-connection-timeout-when-ipv6-fallback-to-ipv4?forum=w7itpronetworking) -
目前廣泛使用的 IPv4 與 IPv6 優(yōu)先選擇算法為 Happy Eyeballs
(https://en.wikipedia.org/wiki/Happy_Eyeballs):-
目前使用此算法的項(xiàng)目有:Chrome, Opera 12.10, Firefox version 13, OS X, cURL
-
此算法會(huì)優(yōu)先選擇 IPv6 鏈路使用
-
此算法的原理可參考 RFC 6555(Happy Eyeballs: Success with Dual-Stack Hosts)
(https://tools.ietf.org/html/rfc6555) -
此算法的簡(jiǎn)略工作流程如下:
-
當(dāng)客戶端是雙棧環(huán)境時(shí),客戶端會(huì)向緩存 DNS 服務(wù)器發(fā)起域名 A 記錄與 AAAA 記錄的解析請(qǐng)求,并受到解析結(jié)果,對(duì)應(yīng)下圖中的 1-4
-
客戶端獲取到解析地址后,會(huì)同時(shí)使用 IPv4 與 IPv6 兩種鏈路嘗試建立連接,對(duì)應(yīng)下圖中的 6-7。當(dāng) IPv6 鏈路比 IPv4 鏈路先建立連接,或者 IPv4 已經(jīng)建立連接,但是在很短的時(shí)間間隔內(nèi),IPv6 也成功建立連接后,則這兩種情況下客戶端應(yīng)該使用 IPv6 鏈路完成后續(xù)的網(wǎng)絡(luò)請(qǐng)求,對(duì)應(yīng)圖中的 8-12
-
測(cè)試方法
解析域名
C/ C ++
-
gethostbyname
Linux
Windows
getaddrinfo
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <netdb.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- int lookup_host ()
- {
- struct addrinfo hints, *res;
- int errcode;
- char addrstr[100];
- void *ptr;
- memset (&hints, 0, sizeof (hints));
- hints.ai_family = AF_INET;
- errcode = getaddrinfo ("IPv6test.ntes53.netease.com", NULL, &hints, &res);
- if (errcode != 0)
- {
- perror ("getaddrinfo");
- return -1;
- }
- while (res)
- {
- inet_ntop (res->ai_family, res->ai_addr->sa_data, addrstr, 100);
- switch (res->ai_family)
- {
- case AF_INET:
- ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
- break;
- case AF_INET6:
- ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
- break;
- }
- inet_ntop (res->ai_family, ptr, addrstr, 100);
- printf ("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4,
- addrstr, res->ai_canonname);
- res = res->ai_next;
- }
- return 0;
- }
- int main (void)
- {
- lookup_host();
- }
windows
Python
-
socket.gethostbyname
- import socket
- result = socket.gethostbyname("IPv6test.ntes53.netease.com")
- print result
- getaddrinfo
- import socket
- result = socket.getaddrinfo("IPv6test.ntes53.netease.com", 0, socket.AF_INET6)
- print result
- result = socket.getaddrinfo("IPv6test.ntes53.netease.com", 0, socket.AF_INET)
- print result
- result = socket.getaddrinfo("IPv6test.ntes53.netease.com", 0, socket.AF_UNSPEC)
- print result
當(dāng)不指定 socktype 時(shí),此值默認(rèn)為 socket.AF_UNSPEC
。
HTTP 請(qǐng)求
Python
requests 包
C++
- #include <stdio.h>
- #include <curl/curl.h>
- int main(void)
- {
- CURL *curl;
- CURLcode res;
- curl = curl_easy_init();
- if(curl) {
- curl_easy_setopt(curl, CURLOPT_URL, "http://IPv6test.ntes53.netease.com:8000");
- /* example.com is redirected, so we tell libcurl to follow redirection */
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
- // curl_easy_setopt(curl, CURL_IPRESOLVE_V6, 1L); // 使用 IPv6 地址
- // curl_easy_setopt(curl, CURL_IPRESOLVE_V4, 1L); // 使用 IPv4 地址
- // curl_easy_setopt(curl, CURL_IPRESOLVE_WHATEVER, 1L); // 獲取系統(tǒng)允許的 IPv4 或者 IPv6 地址
- /* Perform the request, res will get the return code */
- res = curl_easy_perform(curl);
- /* Check for errors */
- if(res != CURLE_OK)
- fprintf(stderr, "curl_easy_perform() failed: %s\n",
- curl_easy_strerror(res));
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
- return 0;
- }