什么是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