名字與號碼之間的鴻溝
走到這裡,你已經爬了很長一段路。你知道網際網路上每一個介面,都是靠一個像 192.168.1.10 的 IP 位址去聯絡的;知道封包會橫越世界、朝那個號碼路由而去;也知道一個應用程式是靠對某個位址與連接埠開啟通訊端來碰到網路。剩下的只有一個「人形」的問題,而你每天都會撞上它:沒有人想為了逛一個網站去打 142.250.72.14。人是用名字在思考的——jovana.education、my-bank.com、某個朋友的郵件主機——而網路是用號碼在思考的。總得有個東西在兩者之間翻譯。
那個翻譯者就是 網域名稱系統,幾乎總是被叫做 DNS,而它的日常比喻恰恰精準:DNS 是網際網路的電話簿。你知道一個人的名字;你去查它;你拿回你真正要撥的那個號碼。一個像 jovana.education 的 網域名稱,是人記得住的那個名字;它所對映到的 IP 位址,則是網路要撥的那個號碼。DNS 就是那個「給它前者、它把後者交給你」的服務。這聽起來簡單到幾乎不需要一整級——直到你問:這本電話簿是誰在保管的?而它又如何能為全球數十億個名字,持續維持正確?
如果機器只想要那個號碼,那何必還要有名字?因為名字給了我們號碼給不了的東西:一層由人類掌控的間接。名字好記又有意義,而位址只是一串任意的數字。名字是穩定的:一家公司可以把網站搬到一台全新、有著新 IP 位址的機器上,而只要那個名字持續指向新號碼,每一條連結、每一個書籤、每一張名片就都還能用。名字是你對人們許下的承諾;位址則是底下那個可以自由變動的實作細節。
為什麼不乾脆用一張巨大的清單就好?
最直覺的第一個點子,正是早期網際網路真的用過的那個:保留一份主檔,列出每一個名字與它的號碼,然後複製給每一台電腦。在 1970 年代,當網路只有幾百台機器時,這行得通——當年真的就只有一個檔案,叫做 HOSTS.TXT,由單一處所維護、由大家下載。但想像今天還這麼做。一張列出地球上每一個名字的清單會大得驚人,它在公布的那一瞬間就已過時,而全世界每一個新名字都得由一間中央辦公室來核准。每個人都去抓同一個檔案,也會無情地把那唯一的來源打到不堪負荷。
於是 DNS 做了三個設計選擇,這三者合起來,讓一本電話簿就能服務整個星球,而這一級接下來的內容,其實就是把這三者一一展開。第一,名稱空間是階層式的,像一棵樹,所以它能被切成許多片。第二,對那些片段的權責是被「授權下放」的,所以沒有任何單一辦公室必須知道或核准一切——每根分枝的擁有者,管理自己的那些名字。第三,答案會被快取在「最需要它的地方」附近,所以同一個問題很少需要兩次大老遠跑到來源。階層、授權、快取:把這三個詞放進口袋裡。
由右而左讀一個名字
仔細看一個網域名稱,你已經能看見藏在裡頭的那棵樹。一個像 mail.jovana.education 的名字,是由右而左讀的,從一般往具體走,就像一個從國家往下讀到街道的郵政地址一樣。最右邊的標籤 education,是一個頂級網域——靠近樹頂的那些大分枝之一,與你熟悉的 com、org、net,以及像 uk 或 tw 的國家代碼並列。在它左邊,jovana 指名了那根分枝裡一個特定的、已註冊的網域。再往左的 mail,則指名了一台特定主機,是 jovana.education 的擁有者選擇去定義的。每一個點,都是往樹下走的一步。
mail . jovana . education [ . ]
| | | |
a host a domain a TLD the root
(specific) (registered) (big branch) (the trunk)
read direction: <----------- general --------
more specific <----------------------------- more general甚至有一個標籤你幾乎從不打、卻始終存在:根,最後那個點之後的一個空標籤,是世上每一個名字都掛在上頭的主幹。所以 mail.jovana.education 完整來說是一條路徑:根,然後 education,然後 jovana,然後 mail。因為這個結構是一棵樹,「這個名字對應哪個號碼?」這份回答的工作,就能被乾淨地分割:擁有 education 分枝的人處理以 education 結尾的名字,經營 jovana.education 的人處理它裡頭的名字,而誰都不需要知道別人那根分枝的事。正是這種乾淨的分割,讓權責得以授權下放——我們三個詞裡的第二個。
究竟是誰替你問了這個問題
當你的瀏覽器需要某個名字背後的號碼時,它不會自己出征去質問全世界的伺服器。它把整件工作交給一個叫做 解析器的幫手(通常是你作業系統裡的「殘根解析器」,而它又倚賴一台由你的網路或 ISP 經營、就在附近的遞迴解析器)。你可以把解析器想成一位勤勉的研究助理。你說「替我找出 jovana.education 的位址」,它就跑出去,問它必須問的任何伺服器、跟著它拿到的任何指標走,然後帶著一個乾淨的單一答案回來——或一句客氣的「查無此名」。你的程式問了一個問題、拿到一個答案;所有的東奔西跑,都是它替你做的。
這裡先給你嚐一口解析器跑的那趟追逐,剛好夠看出它的形狀;下一篇會一台伺服器、一台伺服器地把它走完。注意它是如何沿著你剛學會讀的那棵樹一路往下走的。
- 你的程式問解析器:「jovana.education 的位址是什麼?」然後就只是等一個答案。
- 解析器去問一台根伺服器,它不知道那個位址,但知道誰負責 education,於是回答「去問 education 的伺服器」。
- 解析器去問一台 education 的伺服器,它也不知道那個位址,但知道誰經營 jovana.education,於是回答「去問 jovana.education 的伺服器」。
- 解析器去問 jovana.education 自己的伺服器——那台對這個名字握有真正權威的——而這一次,拿到了真正的 IP 位址。
- 解析器把那個位址交還給你的程式,它現在就能對它開啟一個通訊端了。整趟追逐只花了不到一秒的一小段。
關於這趟追逐,有兩個誠實的提醒。你剛看到的那段向下行走——解析器跑完所有腿力活、回傳一個最終答案——是解析器替你做遞迴工作;而它從每一台伺服器收集到的那些「去問他們」的逐步回覆,則是迭代式的風格。遞迴解析與迭代解析的差別,以及究竟哪一方扮演哪個角色,重要到足以在第三篇得到專門的處理。現在,只要握住這幅圖像:一位助理、沿著一棵樹往下幾跳、帶一個答案回來。
快取:為什麼這本電話簿這麼快
如果每一次名字查詢都真的從根開始跑完整趟追逐,根伺服器會被淹沒,網路會感覺遲鈍。第三個設計選擇拯救了這一點:快取。當你的解析器得知 jovana.education 在某個位址時,它會把這個答案記住一陣子。下一次只要你網路上有任何人問同一個名字——而熱門的名字會被不停地問——解析器就會立刻憑記憶回答,完全不去打擾樹上任何一台伺服器。這和「把朋友的號碼抄在自己手機裡,而不是每次要打就翻開電話簿」是同一種本能。
但一個記住的答案可能會過時——萬一擁有者把這個名字搬到一台新機器上呢?所以每一個 DNS 答案都蓋著一個 TTL(存活時間)的戳記:一個秒數,表示這個答案在必須重新查詢之前可以被信任多久。長的 TTL(比方說一天)意味著更少的查詢與更快的回應,但對變動的反應較慢。短的 TTL(比方說一分鐘)意味著變動傳播得快,代價是更多的查詢。那一個旋鈕——由擁有名字的人設定——就是那個在整個系統裡安靜地權衡「速度對上新鮮度」的開關,也正是它真正讓 DNS 得以擴展。快取與 TTL,在這一級稍後會有專屬於它們的一整篇。
一個名字實際上回傳了什麼,以及接下來是什麼
在這一級接下來把機制填滿之前,做最後一次重新框定。一個名字並不是只對映到一種東西。一個名字的電話簿條目,其實是一小組「有型別的」紀錄——每一筆都是一個 資源紀錄——而型別告訴你它在回答哪一個問題。問 IPv4 位址,你讀到的是一筆 A 紀錄;問 IPv6 位址,你讀到的是一筆 AAAA 紀錄;問這個網域的電子郵件該送到哪,你讀到的是一筆 MX 紀錄;NS 紀錄指名對一個區域握有權威的那些伺服器,CNAME 讓一個名字成為另一個名字的別名,而 TXT 紀錄則裝著常用於驗證的自由格式文字。同一個名字、不同的問題、不同的紀錄型別。
還有一個你必須從一開始就帶著往前走的誠實:預設情況下,DNS 既未經身分驗證、也未加密。當一個普通的 DNS 答案回來時,你的解析器通常無法證明它真的來自這個名字的合法擁有者、且沿途沒有被偽造或竄改,而任何在監看網路的人,都能看見你正在查哪些名字。DNS 是在一個更友善的年代為「正確性與規模」而設計的,不是為了安全。把這兩道缺口都補起來——用 DNSSEC 證明答案是真的、用 DNS over HTTPS 或 TLS 把問題藏起來——是真實而重要的工作,而那正是這一級的結尾所在。
所以這就是你剛踏進的這一級的地圖。你現在握有「為什麼」:人需要穩定、好記的名字,機器需要號碼,而 DNS 就是那本透過階層、授權與快取把兩者接起來的分散式電話簿。前方的篇章填上「如何」——名稱空間及其區域的結構、從根到權威伺服器的逐步解析、讓快取得以安全的紀錄型別與 TTL,最後是普通 DNS 所缺乏的安全與隱私。在你將會打進的每一個名字背後,都坐著這套安靜、橫跨星球的查詢。從這裡開始,你要學的,是它究竟如何運作。