什么是DNS
DNS是域名系統(DomainNameSystem)的縮寫,該系統用于命名組織到域層次結構中的計算機和網絡服務。域名是由圓點分開一串單詞或縮寫組成的,每一個域名都對應一個惟一的IP地址,在Internet上域名與IP地址之間是一一對應的,DNS就是進行域名解析的服務器。DNS命名用于Internet等TCP/IP網絡中,通過用戶友好的名稱查找計算機和服務。DNS是因特網的一項核心服務,它作為可以將域名和IP地址相互映射的一個分布式數據庫。
當我們發起一個網絡請求,首先要經過DNS服務,將域名轉化為IP地址,然后通過IP地址建立連接。DNS的工作流程如下圖所示。
Local DNS有什么缺陷
那么,傳統的Local DNS有什么缺陷呢。就目前端上而言,主要有幾個問題:
•Local DNS劫持
域名劫持是互聯網攻擊的一種方式,通過攻擊域名解析服務器(DNS),或偽造域名解析服務器(DNS)的方法,把目標網站域名解析到錯誤的地址從而實現用戶無法訪問目標網站的目的。
DNS劫持示例圖如下:
DNS劫持會導致端上網絡連接失敗或者DNS解析失敗,嚴重影響用戶使用,在之前,端上采用備用域名的機制去解決這個問題,但是效果并不是很好。
•DNS解析過慢
DNS解析分為遞歸查詢和迭代查詢兩種。
遞歸查詢:如果主機所詢問的本地域名服務器不知道被查詢域名的 IP 地址,那么本地域名服務器就以 DNS 客戶的身份,向其他根域名服務器繼續發出查詢請求報文,而不是讓該主機自己進行下一步的查詢。
迭代查詢:當根域名服務器收到本地域名服務器發出的迭代查詢請求報文時,要么給出所要查詢的 IP 地址,要么告訴本地域名服務器:你下一步應當向哪一個域名服務器進行查詢。然后讓本地域名服務器進行后續的查詢,而不是替本地域名服務器進行后續的查詢。
由于遞歸模式會導致DNS服務器流量很大,所以現在大多數采用迭代模式。
由于端上網絡環境的復雜性已經DNS解析的流程也較為復雜,有些場景下DNS解析時間高達幾百毫秒,對于一次網絡請求來說,是相當緩慢的。
什么是HttpDns
HTTPDNS 是面向移動開發者推出的一款域名解析產品,具有域名防劫持、精準調度等特性。
目前來說,騰訊和阿里都有自己的HTTPDNS解決方案。HTTPDNS有以下特性:
1.安全,由于httpdns使用http或者https協議通過ip直連的方式進行解析,繞過了運營商的Local DNS,避免了域名劫持
2.快速,通過預解析機制,將熱點域名提前解析,網絡連接時直接緩存獲取
Android端HttpDns接入指南
在阿里云HTTPDNS文檔中,有所謂的“最佳方案”,包含SNI場景、OkHttp場景等等,但是,這對于我們來說,接入量還是偏大,且覆蓋的場景依然有限。如果我們想很簡單的接入,且覆蓋全量JAVA場景,如何做呢。首先,我們看一下Android側DNS解析的調用流程,以API 28為例。
InetAddress#getAllByName() ->Inet6AddressImpl#lookupHostByName() ->Libcore.os.android_getaddrinfo()
而Libcore代碼如下Libcore源碼[1]:
public final class Libcore { private Libcore() { } /** * Direct access to syscalls. Code should strongly prefer using {@link #os} * unless it has a strong reason to bypass the helpful checks/guards that it * provides. */ public static Os rawOs = new linux(); /** * Access to syscalls with helpful checks/guards. */ public static Os os = new BlockGuardOs(rawOs); }
通過簡單的代碼跟蹤可以發現,他們實現Os這個接口[2] ,接口?對哦,動態代理。是的,我們可以通過動態代理的方式,去hook掉Java層發起的DNS解析請求。
上面的代碼,已經開源在KIDDNS-Android[3]
下期預告
Android P hide API的問題相信困擾了不少同學,那么下期,咱們一起了解下如何在Android P上使用hide API!
References
[1] Libcore源碼: https://android.googlesource.com/platform/libcore/+/refs/tags/android-9.0.0_r35/luni/src/main/java/libcore/io/Libcore.java
[2] Os這個接口: https://android.googlesource.com/platform/libcore/+/refs/tags/android-9.0.0_r35/luni/src/main/java/libcore/io/Os.java
[3] KIDDNS-Android: https://github.com/VIPKID-OpenSource/KIDDNS-Android