目錄
1、Dns
2、HttpDns
1、Dns

終端向LocalDNS發(fā)起遞歸查詢。
LocalDNS(未開啟轉(zhuǎn)發(fā)模式),則向根DNS服務(wù)器發(fā)起迭代查詢請(qǐng)求。(如開啟轉(zhuǎn)發(fā)模式,則轉(zhuǎn)發(fā)至上級(jí)localDns)
(任何LocalDNS都需知道根DNS服務(wù)器的IP地址(全球共13臺(tái))。)
- 根DNS服務(wù)器返回一級(jí)域名服務(wù)器IP地址,(com DNS服務(wù)器的IP地址)。
(LocalDNS將com DNS服務(wù)器及其IP地址加入到緩存,下次DNS請(qǐng)求,在緩存未過(guò)期的情況下,授權(quán)給com 區(qū)的域名需向com DNS服務(wù)器請(qǐng)求查詢時(shí),直接往com DNS服務(wù)器發(fā)查詢請(qǐng)求,不再向根DNS服務(wù)器請(qǐng)求。)
LocalDNS服務(wù)器向一級(jí)域名服務(wù)器(com DNS服務(wù)器)發(fā)起迭代查詢請(qǐng)求。
com DNS服務(wù)器返回二級(jí)域名服務(wù)器IP地址(wangsu.com DNS服務(wù)器的IP地址)。
(LocalDNS將wangsu.comDNS服務(wù)器及其IP地址加入到緩存,下次DNS請(qǐng)求,在緩存未過(guò)期的情況下,授權(quán)給wangsu.com區(qū)的域名需向wangsu.com DNS服務(wù)器請(qǐng)求查詢時(shí),直接往對(duì)應(yīng) DNS服務(wù)器發(fā)查詢請(qǐng)求,不再向根DNS服務(wù)器及com DNS服務(wù)器請(qǐng)求。)
- LocalDNS服務(wù)器向wangsu.com DNS服務(wù)器發(fā)起迭代查詢請(qǐng)求。
7.wangsu.com DNS服務(wù)器給出域名的IP地址。
(LocalDNS將www.wangsu.com
IP地址加入到緩存,下次相同的DNS請(qǐng)求,在緩存未過(guò)期的情況下,LocalDNS直接給出該域名的IP地址,不再向權(quán)威DNS服務(wù)器查詢。)
- LocalDNS服務(wù)器將該域名對(duì)應(yīng)的IP地址返回給終端用戶,
(DNS客戶端將域名對(duì)應(yīng)的IP地址接入緩存。下次請(qǐng)求該域名時(shí),若緩存未過(guò)期,DNS客戶端直接從緩存取出IP,不再向LocalDNS發(fā)起迭代查詢。)
遞歸查詢指如果終端用戶所請(qǐng)求的LocalDNS服務(wù)器不知道被查詢的域名的IP地址,則以DNS客戶端的身份,向其它域名服務(wù)器繼續(xù)發(fā)出查詢請(qǐng)求報(bào)文(即替主機(jī)繼續(xù)查詢),而不是讓主機(jī)自己進(jìn)行下一步查詢。因此,遞歸查詢返回的查詢結(jié)果或者是所要查詢的IP地址,或者是報(bào)錯(cuò),表示無(wú)法查詢到所需的IP地址。
迭代查詢指域名服務(wù)器或者給出最終結(jié)果,或者告訴DNS客戶(此處指LocalDNS)應(yīng)去哪些DNS服務(wù)器查詢。
遞歸查詢LocalDNS如果沒有記錄客戶端發(fā)過(guò)來(lái)的域名對(duì)應(yīng)的ip地址,則以客戶端的身份,根域名服務(wù)器發(fā)起迭代查詢,迭代查詢是值,根域名服務(wù)器不直接告訴LocalDNS結(jié)果,而是告訴LocalDNS去哪里查詢,然后LocalDNS一級(jí)一級(jí)的查詢,直至最終得到結(jié)果。
2、httpdns
2.1、httpdns解決的問題
2.1.1、域名劫持
1、黑客侵入了寬帶路由器并對(duì)Local DNS進(jìn)行篡改;
2、攻擊者還可以監(jiān)聽終端用戶的域名解析請(qǐng)求,并在Local DNS返回正確結(jié)果之前將偽造的DNS解析響應(yīng)傳遞給終端用戶
3、Local DNS針對(duì)部分域名的緩存進(jìn)行更改
2.1.2、調(diào)度不精準(zhǔn)
由于運(yùn)營(yíng)商策略的多樣性,其 Local DNS 的解析結(jié)果可能不是最近、最優(yōu)的節(jié)點(diǎn)。
部分Local DNS A供應(yīng)商為了降低運(yùn)營(yíng)成本,會(huì)將請(qǐng)求到自己節(jié)點(diǎn)的域名解析請(qǐng)求轉(zhuǎn)發(fā)給其他供應(yīng)商的Local DNS B節(jié)點(diǎn),Local DNS B請(qǐng)求權(quán)威dns解析時(shí),權(quán)威dns會(huì)根據(jù)Local DNS B的ip,分配離Local DNS B地理位置最近的ip地址。
Local DNS的布點(diǎn)受成本因素制約分布并不均勻也會(huì)導(dǎo)致上述調(diào)度不準(zhǔn)的問題。
2.2、HTTPDNS
1、使用HTTP協(xié)議進(jìn)行域名解析,將域名解析請(qǐng)求直接發(fā)送到HTTPDNS服務(wù)端,繞過(guò)運(yùn)營(yíng)商 Local DNS ,避免域名劫持。
2、HTTPDNS服務(wù)端會(huì)將終端用戶的IP信息直接交付給權(quán)威DNS,從而解決調(diào)度不精準(zhǔn)的問題。
3、另外通過(guò)域名預(yù)解析、緩存(DNS解析結(jié)果)、(解析結(jié)果)懶更新策略等方式實(shí)現(xiàn)無(wú)延遲解析。
2.2.1、預(yù)加載
app啟動(dòng)時(shí),可以對(duì)我們后續(xù)需要用到的域名,調(diào)用HTTPDNS SDK中的預(yù)解析方法發(fā)起異步的預(yù)解析請(qǐng)求。

2.2.2、懶更新
所謂懶加載策略,核心的實(shí)現(xiàn)思路如下:
1、如果緩存中沒有記錄,那么異步網(wǎng)絡(luò)請(qǐng)求HTTPDNS解析,獲取解析結(jié)果。
(網(wǎng)絡(luò)請(qǐng)求需要異步,同步調(diào)用需要直接拿到結(jié)果,可采取線程池+Future的策略)
2、如果緩存中存在記錄,不論過(guò)期與否,直接返回業(yè)務(wù)層緩存中的記錄;
3、如果緩存中的記錄已過(guò)期,后臺(tái)發(fā)起異步網(wǎng)絡(luò)請(qǐng)求進(jìn)行HTTPDNS解析;
絕大多數(shù)場(chǎng)景下域名對(duì)應(yīng)IP變更并不頻繁,特別是在單次APP的使用周期內(nèi),域名解析出的IP往往是相同的。
另一方面,即使域名對(duì)應(yīng)的IP發(fā)生改變,后臺(tái)會(huì)異步發(fā)起的異步HTTPDNS解析解析會(huì)很快獲取最新解析結(jié)果 ,結(jié)合我們的網(wǎng)絡(luò)重試策略,保證了下一次網(wǎng)絡(luò)請(qǐng)求的正確性。

2.2.3、OKhttp+HttpDns
public class OkHttpDns implements Dns {
private static final Dns SYSTEM = Dns.SYSTEM;
HttpDnsService httpdns;//httpdns 解析服務(wù)
private static OkHttpDns instance = null;
private OkHttpDns(Context context) {
this.httpdns = HttpDns.getService(context, "account id");
}
public static OkHttpDns getInstance(Context context) {
if(instance == null) {
instance = new OkHttpDns(context);
}
return instance;
}
@Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
//通過(guò)異步解析接口獲取ip
String ip = httpdnsManager.getIpByHost(hostname);
if(ip != null) {
//如果ip不為null,直接使用該ip進(jìn)行網(wǎng)絡(luò)請(qǐng)求
List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ip));
Log.e("OkHttpDns", "inetAddresses:" + inetAddresses);
return inetAddresses;
}
//如果返回null,走系統(tǒng)DNS服務(wù)解析域名
return Dns.SYSTEM.lookup(hostname);
}
}
//給okhttpclient設(shè)置自定義的dns
private void okhttpDnsRequest() {
OkHttpClient client = new OkHttpClient.Builder()
.dns(OkHttpDns.getInstance(getApplicationContext()))
.build();
自定義一個(gè)類實(shí)現(xiàn)Dns,并重寫Dns的lookup方法,
在這個(gè)方法中結(jié)合懶更新策略獲取域名對(duì)應(yīng)的ip,包裝成InetAddress list進(jìn)行返回。