原文:IOS支持IPv6 DNS64/NAT64網絡html
從2016年6月1日起,iOS應用必須支持IPv6,不然審覈將被拒。詳見Supporting IPv6 DNS64/NAT64 Networks。本文是翻譯稿。從本文中能夠學到有關IPv6過分時期的網絡架構和具體IOS應用如何兼容的知識。ios
隨着IPv4地址池即將耗盡,企業和移動通訊供應商在逐步部署IPv6 DNS64/NAT64
網絡。IPv6 DNS64/NAT64
是一個僅有IPv6的網絡,且能經過轉換繼續支持IPv4。根據你app的性質,這樣的轉化會有不一樣的影響:web
若是你是編寫客戶端應用,而且使用高層次的網絡API,如NSURLSession
和CFNetwork框架,使用域名鏈接。那麼你無需更改你的應用,便可工做在IPv6地址下。若是你不是採用域名鏈接,你可能須要看Avoid Resolving DNS Names Before Connecting to a Host。關於CFNetwork,參見CFNetwork Framework Reference
。編程
若是你是編寫服務器程序,或者是底層網絡應用,你須要確保你的socket代碼能同時在IPv4和IPv6地址下工做。參見[RFC4038: Application Aspects of IPv6 Transition.
](https://tools.ietf.org/html/rfc4038)。瀏覽器
主要的網絡供應商,包括美國的蜂窩移動網絡供應商,在積極地推動和部署IPv6。這是由多方面因素形成的。安全
World IPv6 Launch是個追蹤全球範圍內部署活動的組織。訪問World IPv6 Launch website能夠看到近期的進程。服務器
近幾年,衆所周知,IPv4地址最終將耗盡,無類域間路由(Classless Inter-Domain Routing)和網絡地址轉換(NAT)等技術延緩了這勢在必行的趨勢。然而,2011年1月31日,最上層的IPv4分配機構Internet Assigned Numbers Authority(IANA)宣佈地址用盡。American Registry for Internet Numbers (ARIN)預計在2015年夏季用完IPv4地址。從這裏查看倒計時。網絡
除了能解決IPv4耗盡的問題,IPv6比IPv4更加高效,好比:架構
無需網絡地址轉換(NAT)app
使用簡介的頭部信息能夠加快在網絡中的路由
避免網絡數據包碎片
相鄰地址解析時避免使用廣播 (Avoids broadcasting for neighbor address resolution)
第四代移動通訊技術(4G)僅基於包交換,因爲IPv4地址的限制,爲了保證4G開發的擴展性,須要IPv6的支持
IP Multimedia Core Network Subsystem (IMS) 容許一些服務經過IP傳輸,例如多媒體SMS消息和VoLTE。 有些服務提供商使用IMS時僅支持IPv6。
業界在向IPv6遷移的過程當中,須要繼續支持古老的IPv4網絡,這使運營商產生了額外的操做和維護成本。
爲了緩解IPv4地址的耗盡,許多IPv4網絡採用NAT技術。儘管這種方案臨時奏效,可是實踐證實耗資巨大而且不夠可靠。現在,隨着愈來愈多的設備使用IPv6,運營商必須同時支持IPv4和IPv6,這種努力倒是花費巨大的。
圖 10-1 蜂窩移動網絡分別提供IPv4和IPv6連接
理想狀況下,運營商但願丟掉對IPv4的支持。然而,這麼作會致使客戶端沒法訪問基於IPv4的服務器,而IPv4的服務器依然是網絡的重要組成部分。爲了解決這個問題,大多數的網絡供應商實現了一個叫DNS64/NAT64的轉換流程。這是個純IPv6網絡,並經過轉換也可繼續訪問IPv4的內容。
圖 10-2 蜂窩移動網絡用DNS64和NAT64來部署一個IPv6網絡
在這個流程中,若是客戶端向DNS64服務器發起一個DNS查詢,當DNS找到一個基於IPv6的地址後,馬上返回客戶端。若是沒法找到對應的IPv6地址,DNS64服務器將請求IPv4地址,而後DNS64服務器將IPv4做爲前綴合成一個IPv6地址,而且將其返回給客戶端。這樣,客戶端將老是得到一個IPv6目標地址,見圖10-3。
圖 10-3 DNS64 IPv4到IPv6轉換過程
當客戶端向服務端發送請求時,目標地址爲合成後的IPv6地址會自動由NAT64網關路由過去。對於請求,網關做的是IPv6到IPv4的轉換。一樣的,對於服務器響應,網關做的是IPv4到IPv6的轉換。見圖10-4
圖 10-4 DNS64/NAT64轉化方案的流程
對IPv6 DNS64/NAT64網絡的兼容性,將是App Store的提交時的必須條件,因此兼容對於app來講是至關重要的。好消息是,大多數app已是IPv6兼容的了。對於這些app,進行按期的迴歸測試依舊是必要的。對於那些IPv6不兼容的應用在面對DNS64/NAT64網路時可能遇到麻煩。幸運的是,解決問題一般很簡單,下面章節會討論這個問題。
有幾個致使應用沒法支持IPv6的場景。本節描述如何解決這些問題。
嵌入IP地址的協議。許多通訊協議,像SIP
, FTP
, WebSockets
, P2PP
,均可能在協議的報文中包含了IP地址。例如,FTP
參數命令DATA
, PORT
, PASSIVE
的交換信息中包含了IP地址。相似的,IP地址值可能出如今SIP
的頭部,像To
, FROM
, Contact
, Record-Route
以及Via
。參見Use High-Level Networking Frameworks和Don’t Use IP Address Literals
配置文件中使用IP地址。參見Don’t Use IP Address Literals
網絡狀態監測。許多app試圖主動的監測網絡鏈接和wifi鏈接,卻將IP地址做爲參數而調用網絡可達性相關的API。參見Connect Without Preflight
使用底層網絡接口。一些app直接使用socket
和其餘的低層次網絡API,好比gethostbyname
gethostbyname2
和inet_aton
。這些API很容易由於錯誤使用而僅支持IPv4。好比,域名解析時使用AF_INET
地址簇,而不是AF_UNSPEC
地址簇。參見Use High-Level Networking Frameworks
使用了小的地址簇存儲容器。一些app和網絡庫,使用了例如unit32
,in_addr
,sockaddr_in
這種32位或更小的容器來存儲地址。參見Use Appropriately Sized Storage Containers
附上下面的指導來確保IPv6 DNS64/NAT64的兼容性。
app請求網絡時,能夠構建在高層次的網絡框架上,也可使用底層的POSIX
兼容的socket
接口。在多數狀況下,相比底層接口,高層次的接口效率高一些,兼容性好,容易使用,不容易掉入一般的編程錯誤陷阱中。
圖 10-5 網絡框架和API層次
WebKit
。此框架提供一系列的類用來在窗口上顯示web內容,並且實現了瀏覽器特性,諸如:連接、前進後退管理、最近訪問歷史。WebKit將加載網頁的流程簡化了,包括異步地從HTTP服務器上請求網頁內容,這些服務器響應的數據包可能一點點送達,也可能以隨機的順序到達,甚至可能因爲網絡錯誤收不全。詳見WebKit Framework Reference
Cocoa URL loading system
。這個系統用於簡單地經過網絡發送和接收數據,卻不須要提供顯示的IP地址。數據的發送和接收使用這幾個類中的一個:NSURLSession
NSURLRequest
NSURLConnection
,這些類使用NSURL
對象。NSURL
對象容許你操做URL。建立一個NSURL
對象時使用initWithString:
方法,並傳入一個指定的URL。調用NSURL
類的checkResourceIsReachableAndReturnError:
方法檢測目標主機的可達性。詳見URL Session Programming Guide
CFNetwork
。這個核心服務框架提供了一個抽象網絡協議的庫。這個庫提供了大量易用的網絡操做,好比BSD socket,DNS解析,處理HTTP/HTTPS。調動CFHostCreateWithName
方法,避免顯示的使用IP地址來標識主機。調用CFStreamCreatePairWithSocketToCFHost
與主機創建TCP連接。詳見CFNetwork Programming Guide中的CFNetwork Concepts
若是你須要使用低層次的socket接口,參看以下指導:RFC4038: Application Aspects of IPv6 Transition
Getting Started with Networking, Internet, and Web 和 Networking Overview 提供詳細的網絡框架API的說明
在許多API中請確保再也不使用點分十進制表示的IPv4地址,例如getaddrinfo
或SCNetworkReachabilityCreateWithName
。取而代之,應該使用高層次網絡框架和地址無關的API,例如在使用getaddrinfo
和getnameinfo
時,傳入主機名或域名。詳見:getaddrinfo(3) Mac OS X Developer Tools Manual Page 和 getnameinfo(3) Mac OS X Developer Tools Manual Page。
從IOS9何OSX10.11開始,
NSURLSession
和CFNetwork
會在本地自動將IPv4的地址合成IPv6地址,便於與DNS64/NAT64通訊。不過,你依舊不應使用IP地址串。
檢測網絡可達性的API(參見SCNetworkReachability Reference)用來在遇到鏈接異常時進行診斷。許多app錯誤的使用了API,它們每每經過調用SCNetworkReachabilityCreateWithAddress方法,並將IPv4地址0.0.0.0
做爲參數傳入,來不斷檢查網絡鏈接,實際表示是否至少可達一個路由(which indicates that there is a router on the network)。然而,即便有這樣的路由也不保證互聯網的鏈接存在。總之,避免進行網絡可達性的檢測。只須要直接進行鏈接,而且優雅的處理失敗的狀況。若是你確實須要檢測網絡可用性,需避免使用SCNetworkReachabilityCreateWithAddress,而是調用SCNetworkReachabilityCreateWithName,並傳入主機名。
有些app還在調用SCNetworkReachabilityCreateWithAddress的時候傳入IPv4地址169.254.0.0
(一個自動分配的本地IP),試圖檢測Wi-Fi鏈接。若要檢測Wi-Fi或蜂窩移動網絡鏈接,參見網絡可達標識kSCNetworkReachabilityFlagsIsWWAN
。
使用Storage Container結構,如sockaddr_storage
,用以有足夠的空間存放IPv6地址。
查找並刪除IPv4相關的API,如:
inet_addr()
inet_aton()
inet_lnaof()
inet_makeaddr()
inet_netof()
inet_network()
inet_ntoa()
inet_ntoa_r()
bindresvport()
getipv4sourcefilter()
setipv4sourcefitler()
若是你處理的IPv4的類型,去報同時處理對應的IPv6類型
IPv4 | IPv6 |
---|---|
AF_INET | AF_INET6 |
PF_INET | PF_INET6 |
struct in_addr | struct in_addr6 |
struct sockaddr_in | struct sockaddr_in6 |
kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6 |
若是你的app須要鏈接到僅支持IPv4的服務器,且不使用DNS域名解析,請使用getaddrinfo
處理IPv4地址串(譯註:getaddrinfo可經過傳入一個IPv4或IPv6地址,獲得一個sockaddr結構鏈表)。若是當前的網絡接口不支持IPv4,僅支持IPv6,NAT64和DNS64,這樣作能夠獲得一個合成的IPv6地址。
代碼10-1展現瞭如何用getaddrinfo
處理IPv4地址串。假設你內存中有一個4個字節的IPv4地址串(如{192,0,2,1}),這個示例代碼將之轉化爲字符串("192.0.2.1"),使用getaddrinfo
合成一個IPv6地址結構(struct sockaddr_in6
包含IPv6地址串爲"64:ff9b::192.0.2.1"),而後嘗試鏈接到這個IPv6地址。
代碼 10-1 使用getaddrinfo
處理IPv4地址串
#include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <err.h> uint8_t ipv4[4] = {192, 0, 2, 1}; struct addrinfo hints, *res, *res0; int error, s; const char *cause = NULL; char ipv4_str_buf[INET_ADDRSTRLEN] = { 0 }; const char *ipv4_str = inet_ntop(AF_INET, &ipv4, ipv4_str_buf, sizeof(ipv4_str_buf)); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_DEFAULT; error = getaddrinfo(ipv4_str, "http", &hints, &res0); if (error) { errx(1, "%s", gai_strerror(error)); /*NOTREACHED*/ } s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } break; /* okay we got one */ } if (s < 0) { err(1, "%s", cause); /*NOTREACHED*/ } freeaddrinfo(res0);
從IOS9.2和OSX10.11.2開始合成IPv6地址的功能才被加入到
getaddrinfo
。不過,這麼用不會對舊的系統產生兼容性問題。參見getaddrinfo(3) Mac OS X Developer Tools Manual Page.
大多數蜂窩移動供應商已經開始部署IPv6 DNS64/NAT64網絡,測試這種網絡最簡單的的方法是用Mac創建一個本地的IPv6 DNS64/NAT64網絡。你能夠將其餘設備連接到這個網絡來測試。見圖10-6
提示:IPv6 DNS64/NAT64網絡僅在OSX 10.11及更高版本上能夠設置。除此以外,基於Mac來創建的IPv6 DNS64/NAT64網絡僅與支持RFC6106: IPv6 Router Advertisement Options for DNS Configuration的客戶端設備兼容。若是你的設備不是iOS或OSX設備,請確保它支持RFC。還需注意的是:不一樣於運營商提供的DNS64/NAT64網絡,基於Mac系統的IPv6 DNS64/NAT64老是返回合成後的IPv6地址。所以,它不能用於訪問你本地網絡之外的純IPv6網絡。
圖 10-6 本地的基於Mac的 IPv6 DNS64/NAT64 網絡
使用你的Mac創建本地的IPv6 Wi-Fi網絡
確保你的Mac鏈接到互聯網,但不是經過Wi-Fi
啓動System Preferences
按住Option
鍵(標準鍵盤是Alt鍵)點擊Sharing
,不要放開Option鍵。
圖 10-7 打開Sharing preferences
在共享列表中選擇Internet Sharing
圖 10-8 配置Internet Sharing
放開Option
鍵
勾選Create NAT64 Network
複選框
圖 10-9 啓用一個本地IPv6 NAT64網絡
選擇你用於互聯鏈接的網絡接口,例如藍牙局域網(譯者注:一般這裏mac用以太網鏈接互聯網,不多有用藍牙的)
圖 10-10 選擇共享的網絡接口
選擇Wi-Fi複選框
圖 10-11 經過Wi-Fi開啓共享
點擊Wi-Fi Options
,配置你網絡的網絡名和安全選項
圖 10-12 設置Wi-Fi網絡選項
勾選Internet Sharing
複選框啓動你的本地網絡
圖 10-14 啓動網絡共享
當彈出確認是否開啓共享時,點擊Start
圖 10-15 開啓網絡共享
一旦共享啓動後,你應該能夠看到一個綠色的狀態指示燈和一段話說明共享已開啓。在Wi-Fi菜單中,你一樣將看到一個小的向上的箭頭,表示網絡共享已經開啓。如今你擁有了一個IPv6 NAT64的網絡,其餘設備能夠鏈接這個網絡來測試app。
圖 10-16 網絡共享開啓圖標
提示:爲了確保測試時嚴格使用本地的IPv6網絡,請確認測試設備沒有其餘的網絡接口正在使用。例如,若是你在測試iOS設備,確保蜂窩移動網絡服務是禁用的,這樣才能確保經過Wi-Fi鏈接。