點贊關注,不再迷路,你的支持對我意義重大!
?? Hi,我是丑丑。本文「計算機網(wǎng)絡」| 導讀 —— 跬步千里,始于足下 已收錄,這里有 Android 進階成長路線筆記 & 博客,歡迎跟著彭丑丑一起成長。(聯(lián)系方式在 GitHub)
前言
- DNS 往往是網(wǎng)絡請求的第一步,在計算機網(wǎng)絡面試中,DNS 也是除 HTTP、TCP 之外較重點考察的知識,其重要性可想而知。
- 在這篇文章里,我將梳理圖解 DNS & HTTPDNS 的原理知識。如果能幫上忙,請務必點贊加關注,這真的對我非常重要。
目錄
1. DNS 原理
1.1 DNS 簡介
域名(Domain Name,Domain) 是一個在互聯(lián)網(wǎng)上標識主機或主機組的名稱,相當于 IP 地址的別名,相對于晦澀難記的 IP 地址,域名更顯得易于記憶。
域名系統(tǒng)(Domain Name System,DNS) 則是將域名解析 IP 地址的一項互聯(lián)網(wǎng)基礎服務,提供該服務的服務器稱為 域名服務器(Domain Name Server)。
1.2 DNS 解析過程
互聯(lián)網(wǎng)上的域名系統(tǒng)是一個分布式的系統(tǒng),結(jié)構上是一個四層的樹狀層次結(jié)構,如下圖所示:
本地域名服務器(Local Name Server,local DNS):如果通過 DHCP 配置,local DNS 由互聯(lián)網(wǎng)服務提供商(ISP,如聯(lián)通、電信)提供;
根域名服務器(Root Name Server):當 local DNS 查詢不到解析結(jié)果時,第一步會向它進行查詢,并獲取頂級域名服務器的IP地址。全球一共有 13 個根域名服務器(除了它們的鏡像),它們并不直接用于域名解析,僅用于指出可查詢的頂級域名服務器。這個網(wǎng)站記錄了現(xiàn)有的 13 個根域名服務器:https://www.internic.net/domain/named.root;
頂級域名服務器(Top-level Name Server):負責管理在該頂級域名服務器下注冊的二級域名,例如.com 頂級域名服務器,而 baidu.com 權威服務器是注冊在 .com 的權威域名服務器;
權威域名服務器(Authoritative Name Server):在特定區(qū)域內(nèi)具有唯一性,負責維護該區(qū)域內(nèi)的域名與 IP 地址的映射關系。在 DNS 應答報文中,標志位 AA 標識本次 DNS 記錄是否來自權威域名服務器,否則可能來自緩存。
DNS 解析分為 遞歸查詢 和 迭代查詢 兩種方式。其中,客戶端與 Local DNS 之間一般采用遞歸查詢,而 DNS 服務器之間一般采用迭代查詢。
提示:如果 DNS 服務器之間使用遞歸查詢,對根域名服務器的負擔就太重了,而如果客戶端與本地域名服務器之間使用迭代查詢,DNS 服務對于客戶端就顯得不透明了。
- 遞歸查詢:
所謂遞歸查詢,與我們經(jīng)常提及的遞歸函數(shù)的思想是一致的,即:如果 DNS 服務器查不到該域名,那么它將重新以客戶端的身份向其他 DNS 服務器發(fā)送查詢請求報文,客戶端只要等待最終結(jié)果即可。用偽代碼呈現(xiàn)可能比較好理解,類似這樣:
fun dns(client: String, server: String, domain: String): String {
if (server 查詢 domain 成功) {
return "ip"
}
// server 以客戶端身份遞歸查詢
return dns(server, "其他 DNS 服務器", domain)
}
- 迭代查詢:
所謂迭代查詢,即:如果 DNS 服務器查不到該域名,它不會替客戶端完成后續(xù)的查詢工作,而是回復下一步應當向哪一個域名服務器進行查詢,隨后客戶端重新向這個新的 DNS 服務器發(fā)送查詢請求。用偽代碼呈現(xiàn)可能比較好理解,類似這樣:
fun dns(client: String, server: String, domain: String): String {
while (true) {
if (server 查詢 domain 成功) {
return "ip"
} else {
// client 繼續(xù)以客戶端身份迭代查詢
server = "其他 DNS 服務器"
}
}
}
下面以查詢www.baidu.com
為例,闡述一次 DNS 解析過程:
0、首先檢查 DNS 緩存,下一節(jié)我們會講,如果緩存老化或未命中,客戶端需要向 local DNS 發(fā)送查詢請求報文
1、客戶端向 local DNS 發(fā)送查詢報文
query www.baidu.com
,local DNS 首先檢查自身緩存,如果存在記錄則直接返回結(jié)果,查詢結(jié)束;如果緩存老化或未命中,則:2、local DNS 向根域名服務器發(fā)送查詢報文
query www.baidu.com
,返回 .com 頂級域名服務器的地址(如果查無記錄)3、local DNS 向 .com 頂級域名服務器發(fā)送查詢報文
query www.baidu.com
,返回baidu.com
所在的權威域名服務器的地址(如果查無記錄)4、local DNS 向 baidu.com 權威域名服務器發(fā)送查詢報文
query www.baidu.com
,得到 ip 地址,存入自身緩存并返回給客戶端
1.3 DNS 報文
由于下一節(jié)我們將實戰(zhàn)抓取 DNS 包,所以這一節(jié)我們先介紹 DNS 報文格式。DNS 協(xié)議定義了三種報文,查詢報文 & 應答報文 & 更新報文,它們的總體上結(jié)構是一致的。
-
報文首部(Header)
- 1、事務 ID(Transaction ID):用來關聯(lián) DNS 查詢與應答,DNS客戶端每次發(fā)送查詢請求都會使用不同的 ID,而服務器在響應中重復這個 ID
- 2、標志(Flags):報文的標志字段,詳見下圖
- 3、問題數(shù)(Question Count):指定問題部分條目數(shù)
- 4、回答資源記錄數(shù)(Answer Resource Record count):指定應答部分中回答資源條目數(shù)
- 5、權威資源記錄數(shù)(Authority Resource Record count):指定權威資源記錄數(shù)
- 6、附加資源記錄數(shù)(Additional Resource Record count):指定附加資源記錄數(shù)
- 問題(Question)
問題用于表達具體查詢的問題,問題個數(shù)與報文首部中的 問題數(shù)(Question Count)字段一致。需要注意的是,按照 DNS 查詢的目的,DNS 解析可以分為 正向解析 和 反向解析 兩種,正向解析將域名解析為 IP 地址,而反向解析則恰恰相反,用于將 IP 地址解析域名。問題條目中 查詢類型 是比較重要的字段,這里僅列出 5 個比較常用的類型:
QTYPE | 描述 |
---|---|
A(1) | 將域名解析為 IPv4 地址 |
NS(2) | 查詢域名服務 |
CNAME(5) | 規(guī)范名稱 |
PTR(12) | IP 地址解析為域名 |
AAAA(28) | 將域名解析為 IPv6 地址 |
NS 和 CNAME 不好理解,這里解釋下:
CNAME(Canonical NAME) 是規(guī)范名稱或別名,用于將一個域名指向另一個域名。具體方法是:將一個域名作為 A 記錄 指向 IP 地址,而其他域名作為別名指向 A 記錄的域名,此時如果需要更改 IP 地址,就不需要更改每個域名的映射了,只需要修改 A 記錄 ,而 CNAME 記錄將自動指向新的 IP 地址。在 第 1.4 節(jié) DNS 解析實戰(zhàn) 中你將直接看到 CNAME 的應用。
NS(Name Server) :域名服務器記錄,用來指定該域名由哪個 DNS 服務器來進行解析
- 資源記錄(Resource Record)
回答資源記錄、權威資源記錄和附加資源記錄的格式相同,其中 TTL(Time to Live,單位秒) 表示資源記錄的生存時間,也就是允許緩存的時間。0 表示該記錄只能用于當前響應,不允許被緩存。
1.4 DNS 報文的傳輸協(xié)議
DNS 協(xié)議在傳輸層同時使用 TCP 和 UDP 協(xié)議,占用的是 53 端口,那么在什么情況下使用這兩種協(xié)議?
- 在區(qū)域傳輸時使用 TCP 協(xié)議
主輔域名服務器在進行區(qū)域傳送時(主輔域名服務器用于平衡負載),需要傳送的數(shù)據(jù)比簡單的查詢 & 應答報文的數(shù)據(jù)量要大得多了。使用 UDP 傳輸不可靠,所以采用應用于傳輸大量數(shù)據(jù),可靠性更高的 TCP 協(xié)議。
- 在域名解析時使用 UDP 協(xié)議
為了得到一個域名的 IP 地址,往往會向多個域名服務器查詢,如果使用 TCP 協(xié)議,那么每次請求都會存在三次握手連接時延,這樣使 DNS 服務變得很慢。
需要注意的是,DNS 協(xié)議規(guī)定 UDP 報文段的最大長度為 512 字節(jié),如果 DNS 報文段過長時會被截斷(此時 DNS 報文頭中標志位 TC(Truncation)置為 1),多余的數(shù)據(jù)會直接丟棄。這是因為 UDP 是無連接的,無法確定哪幾個 UDP 包是屬于同一個 DNS 報文段的。
1.5 DNS 解析實戰(zhàn)
計算機網(wǎng)絡是在實踐中發(fā)展起來的學科,僅停留在學習理論知識的層面是不夠的,下面我們將在實踐中學習 DNS 解析。在這里,我們是用 WireShark 抓取查詢www.baidu.com
的 DNS 請求,具體步驟如下:
- 步驟一:設置 WireShark 過濾條件
在過濾條件欄輸入條件:icmp || dns
,如下圖:
- 步驟二:終端 ping www.baidu.com
在終端輸入ping www.baidu.com
,如下圖:
- 步驟三:查看 DNS 查詢 & 應答報文
返回 WireShark,查看抓取的消息,可以看到兩條 DNS 報文消息,一條為查詢報文,另一條為應答報文,如下圖:
現(xiàn)在我們具體查看這兩條 DNS 報文消息,有了上一節(jié)的鋪墊,相信閱讀這兩段報文已經(jīng)很簡單了。先看 DNS 協(xié)議的報文段部分,下層協(xié)議的報文段后面講:
- 查詢報文:
在這個報文里提出了一個問題,即:查詢 www.baidu.com 的 IPv4 地址(A 記錄),標記位指出以下信息:這是一個查詢報文;這是一次正向解析;報文未截斷;要求服務器執(zhí)行遞歸查詢;
- 應答報文:
- 傳輸層 & 網(wǎng)絡層:
從圖中還驗證了 DNS 在進行域名解析時使用 UDP 協(xié)議,端口號為 53,與上一小節(jié)的分析一致。另外,還可以看出 IP 包的第一跳是發(fā)送給局域網(wǎng)路由器,而不是直接發(fā)送給 local DNS 服務器,這也合理。
1.6 DNS 緩存
一次完整的 DNS 查詢過程需要訪問多臺 DNS 服務器才能得到最終的結(jié)果,這肯定會帶來一定的時延。為了改善時延,DNS 服務并不是每次請求都要去訪問 DNS 服務器,而是訪問過一次后將 DNS 記錄緩存在本地。具體來說,DNS 服務是一個多級的緩存:
瀏覽器緩存 -> 操作系統(tǒng)緩存 -> 路由器緩存 -> local DNS 緩存 -> DNS 查詢
緩存并不是永久有效的,前面提到過 DNS 應答報文中的 TTL(Time to Live)值,它決定了 DNS 記錄在緩存中的有效時間。需要注意的是,TTL 只是一個參考值,實際使用的緩存有效時間不一定等于該值,甚至是固定值。這也引發(fā) DNS 緩存也存在一些“副作用”,我后文再說。
2. DNS 存在的問題
經(jīng)過上一節(jié)的 DNS 理論知識學習和實踐探索,相信大家對 DNS 已經(jīng)建立起了一定的認識。那么,DNS 是一個完備的服務嗎,在實踐中它有存在什么問題呢?這一節(jié)我們來討論這個問題。
2.1 DNS 查詢時延
從第一節(jié)的分析可以看出,一次完整的 DNS 查詢過程需要訪問多臺 DNS 服務器才能得到最終的結(jié)果,這肯定會帶來一定的時延。從實踐來看,這個時間還不容小覷。
提示: 有贊技術團隊指出,DNS 解析時延的波動較大,好的情況幾毫秒、十幾毫秒就完成了,差的時候,可能需要花很多時間:《有贊webview加速平臺探索與建設》 —— 有贊移動組
2.2 緩存一致性
DNS 緩存的存在雖然減少了時延,卻是以犧牲一致性(consistency)為代價的。具體來說:Local DNS 是分地區(qū)、分運營商的,在域名解析緩存的處理上,實現(xiàn)策略就不統(tǒng)一了。有時候 Local DNS 的解析結(jié)果 可能不是最近、最優(yōu)的節(jié)點,有的時候并不會遵從 TTL 的限制,而是設置一個固定時間。這就會導致域名指向新的 IP 地址后,一些客戶端依然訪問了緩存中 舊的 IP 地址。
除了運營商的緩存策略外,緩存投毒也是降低 DNS 可用性的原因。攻擊者可以通過 DNS 劫持,利用 DNS 的緩存機制不對應答數(shù)據(jù)做檢查的漏洞,誘騙 DNS 服務器緩存較大 TTL 的虛假 DNS 記錄,從而長期欺騙客戶端。
2.3 DNS 劫持(中間人攻擊)
由于 DNS 缺乏 加密、認證、完整性保護的安全機制,容易引發(fā)網(wǎng)絡完全問題。最常見的域名劫持攻擊是針對 DNS 報文首部的 事務 ID 進行欺騙,由于事務 ID 在查詢報文和應答報文中是匹配的,因此偽裝 DNS 服務器可以提前將事務 ID 相同的偽造報文發(fā)送到客戶端,以實現(xiàn)域名劫持(前提是合法的報文還未到達),把目標網(wǎng)站域名解析到錯誤的 IP 地址。
提示: 獲取事務 ID 的方法主要采用 網(wǎng)絡監(jiān)聽與序列號猜測,具體可翻閱《計算機網(wǎng)路安全原理》 (第 8 章)—— 吳禮發(fā) 著
2.4 調(diào)度不精準問題
由于存在緩存、轉(zhuǎn)發(fā)、NAT 等問題,權威的 DNS 服務器可能會誤判客戶端所在的位置和運營商,從而導致解析出跨運營商訪問的 IP 地址,用戶的訪問速度降低。
3. HTTPDNS 原理
雖然 DNS 存在不少問題,但也不能因噎廢食放棄整套域名系統(tǒng),解決方案無非是不走尋常路,換一種方式獲取 IP 地址 —— HTTPDNS。
3.1 HTTPDNS 簡介
與傳統(tǒng)的 DNS 解析不同,HTTPDNS 是自己搭建基于 HTTP 協(xié)議的服務器,當客戶端需要 DNS 解析的時候,不再向 local 發(fā)送 DNS 查詢報文,而是直接通過請求直接訪問 HTTPDNS 接口。而服務端則根據(jù)客戶端的位置和所屬運營商,返回就近的 IP 地址。
當然了,基于容災考慮,當出現(xiàn) HTTPDNS 不可用時會觸發(fā)降級策略,使用運營商 LocalDNS 進行域名解析。
3.2 HTTPDNS 優(yōu)勢
相對與 DNS,HTTPDNS 的主要優(yōu)點如下:
降低時延
縮短了查詢鏈路,不像 DNS 查詢那樣需要訪問多臺 DNS 服務器才能得到最終的結(jié)果;域名防劫持
域名解析請求直接發(fā)送至HTTPDNS服務器,繞過運營商 Local DNS,避免域名劫持問題;調(diào)度精準
由于 DNS 服務器端獲取的是真實客戶端 IP 而非 Local DNS 的 IP,能夠精確基于客戶端位置、運營商信息,獲得最精準的解析結(jié)果,讓客戶端就近接入業(yè)務節(jié)點快速生效
域名解析結(jié)果變更時,HTTPDNS 服務沒有傳統(tǒng)DNS 服務多級緩存的影響,域名更新能夠更快地覆蓋到全量客戶端。
3.3 HTTPDNS 正向效益
目前,騰訊、阿里和百度都有自己的 HTTPDNS 解決方案,筆者收集了他們公示的使用效益,具體如下:
-
騰訊
-
百度
- 官方博客:iOS劫持率由0.12%降低到0.0002%,Android劫持率由0.25%降低到0.05%,第二點的收益不明顯,原因在于Feed業(yè)務主要目標群體在國內(nèi),百度在國內(nèi)節(jié)點布局相對豐富,服務整體質(zhì)量也較高;
阿里
未查及...
4. 總結(jié)
應試方面,建議重點掌握四層 DNS 解析過程 & HTTPDNS 原理、理解知曉 DNS 存在的問題、DNS 報文格式重點理解 TTL、幾種查詢類型。
參考資料
- 《域名系統(tǒng)》 —— 維基百科
- 《How DNS Works》 —— Microsoft 文檔
- 《計算機網(wǎng)路安全原理》 (第 8 章)—— 吳禮發(fā) 著
- 《TCP-IP 協(xié)議及其應用》 (第 8 章)—— 林成浴 著
- 《全局精確流量調(diào)度新思路 - HttpDNS 服務詳解》 —— 廖偉健 著
- 《百度 App 網(wǎng)絡深度優(yōu)化系列《一》DNS優(yōu)化》 —— 蔡銳 著
- 《趣談網(wǎng)絡協(xié)議》 (第 18、19 講)—— 劉超 講,極客時間 出品
- 《萬字長文!搞定逃不脫的 DNS 面試題》 (第 2 節(jié)) —— 我是程序員小賤 著
- 《為什么 DNS 使用 UDP 而不是 TCP?》 (車小胖的回答)—— 知乎問答
- [《TCP/IP詳解·卷1 —— 協(xié)議》] —— [美]Kevin R.Fall、W.Richard Stevens 著
- 《What really happens when you navigate to a URL》 (第 2 節(jié)) —— Igor Ostrovsky 著
實用資源
創(chuàng)作不易,你的「三連」是丑丑最大的動力,我們下次見!