從一個網路到網路的網路
到目前為止,繞送感覺像是一個單一、整齊的問題。在前一個階段,你看著像 OSPF 與 RIP 這類協定,在一張網路圖上算出最小成本路徑——每台路由器都合作、誠實地分享自己的視野,並且對一個目標有共識:用最省的方式把每個封包送到目的地。這在單一組織內部運作得很漂亮,因為一個組織擁有每一台路由器,能命令它們乖乖配合。但網際網路斷然不是單一個組織。它是由數萬個各自獨立經營的網路鬆散結成的聯邦,這些網路分屬公司、大學、政府與內容供應商,他們彼此並不信任,也不共享單一個目標。
所以網際網路有兩層繞送,不是一層。在每個組織自家的網路內部,先前那個合作式、最小成本的故事仍然成立:那是域內繞送(intra-domain routing),屬於內部閘道協定的地盤。但封包一旦需要從一個組織跨入另一個組織,一個截然不同的遊戲就開始了。牽涉到的這些網路由不同的當事人經營、各有各的利益,沒有人會把自己內部的地圖誠實地公布給競爭對手。這第二層——在獨立網路之間繞送——叫做域間繞送(inter-domain routing),而要理解它,得先從替這些塊本身命名開始。
自治系統:一塊、一個擁有者、一套政策
那些各自獨立經營的塊,每一個都叫做自治系統(AS)。一個自治系統是一群在單一管理控制之下的網路與路由器,對網際網路的其餘部分呈現出一套一致的繞送政策。你家的網路供應商是一個 AS。一所大型大學是一個 AS。Google、Cloudflare、Netflix 各自經營一個或多個。它的定義就藏在名字裡:這個系統是自治的,意思是它自己決定內部繞送怎麼運作,而且關鍵在於——它自己決定要、與不要替誰載運流量。把每個 AS 想成一個主權國家,有自己的內部道路網,也有自己的邊境政策,規定要讓哪些鄰國的卡車過境。
因為網際網路需要明確無歧義地指稱每一個 AS,所以每一個都拿到一個全球唯一的號碼,也就是它的自治系統號碼(ASN)。這些號碼由配發 IP 位址區塊的同一批區域註冊機構發出。最初 ASN 是一個 16 位元的號碼,把全世界封頂在 65,536 個,但就像位址一樣這證明太少了,於是格式被加寬到 32 位元,挪出了數十億的空間。ASN 之於一個網路,就像區碼之於一個地區:一個簡短、官方的標籤,讓其他所有人都能毫無歧義地談論「AS15169」(那一個是 Google 的)。當我們畫出網際網路的結構時,那些點是以 ASN 標示的 AS,而它們之間的線,是商業關係。
為什麼這一層講的是金錢,不是距離
這裡是整個階段裡最大的一個心態轉變。在一個 AS 內部,繞送在最佳化一個數字:挑出總成本最小的那條路徑。在 AS 與 AS 之間,沒有一個共享的成本可以最小化,因為每個 AS 都是一門獨立的生意,而替別人載運流量是要花真金白銀的。所以域間繞送在最佳化的,是完全不同的東西:政策與經濟。一個 AS 問的不是「到這個目的地的最短路徑是哪條?」它問的是「我願意把這段流量透過我哪一個鄰居送出去,而哪條路徑替我賺最多或省最多錢?」最短的那條路徑,常常不是被選中的那條。
那些金錢關係有幾種標準款式。最重要的是供應商—客戶關係:一個較小的 AS 付錢給一個較大的,讓後者替它把流量載往、載回網際網路的其餘部分,這叫做購買中轉(transit)。在一段供應商—客戶關係裡,客戶付錢,而作為回報,供應商承諾代它抵達各處。另一種常見款式是對等互連(peering):兩個規模大致相當的 AS 同意直接交換彼此客戶之間的流量,通常是免費的,因為這替雙方都省下了為那段流量付錢給供應商。網際網路的整個形狀都從這兩種關係裡掉出來,而下一篇會把那個形狀畫得更細。
BGP:把自治系統黏合起來
如果每個 AS 都把自己的內部地圖保密、只想遵循自己的政策,那它們在邊界上用什麼語言交談?答案是邊界閘道協定(BGP),這個單一的協定撐住了整個網際網路。BGP 是一個 AS 告訴鄰居「這些前綴我到得了,而且這裡是封包要抵達那裡會經過的 AS 序列」的方式。鄰居收下這份資訊,套用自己的政策來決定喜不喜歡它,如果喜歡,就把一個更新過的版本傳給自己的鄰居。讓這套機制在各處運轉,於是一個前綴接一個前綴地,每個 AS 都學會了如何抵達其他每一個。
BGP 是一種路徑向量(path-vector)協定,這個詞值得拆開來看。前一個階段的距離向量協定,宣告的是一個目的地加上一段距離(「X 我到得了,成本 4」)。BGP 改成宣告一個目的地加上沿途整串 AS 的清單(「前綴 X 我經由路徑 AS65010、AS65020、AS65030 到得了」)。那串明列出來的清單——也就是 AS 路徑——一次做了兩件事。它讓一個 AS 能夠藉由檢視一條路線究竟跨越了誰的網路來套用政策;它也立刻防止了迴圈:如果一個 AS 看到自己的 ASN 已經在路徑裡,它就知道接受這條路線會繞成一個圈,於是把它丟掉。不必數到無窮大,不必猜測距離,就只是一份可讀的清單,列出鏈條裡有誰。
A BGP route advertisement, in plain words: Prefix: 203.0.113.0/24 (a block of addresses) AS-PATH: 65030 65020 65010 (read right-to-left: who to traverse) Reading it: "To reach 203.0.113.0/24, send the packet toward me, and it will pass through AS65020, then AS65010, which owns the block." If AS65030 ever sees 65030 already in an AS-PATH it receives, it drops that route -- the path would loop back through itself.
一身兩用的 BGP:邊界之內與跨越邊界
BGP 其實戴著兩頂帽子。當一個 AS 裡的路由器對另一個 AS 裡的路由器講 BGP,那是外部 BGP(eBGP),也就是真正的跨邊界對話,政策與經濟在此施行。但有一個更微妙的問題:一旦一個 AS 從外面學到一條路線,這個 AS 內部的每一台路由器也都需要知道它,否則封包可能抵達一台不知道下一步要往哪送的邊界路由器。所以同一個協定被用第二種方式來跑——內部 BGP(iBGP)——用來在單一 AS 內部的路由器之間搬運那些從外部學來的路線。BGP 標準用一個名字稱呼這兩種款式,但它們之間的政策規則差異很大。
這個區分很重要,因為 iBGP 跟先前那個內部協定做的是不同的工作,而且共存。內部閘道協定(像 OSPF)算出如何讓封包跨越內部道路網、從 AS 的一邊走到另一邊。疊在它上面的 iBGP,散布的是「有哪些外部目的地存在、該從哪個邊界出去」這項知識。所以封包在一個 AS 內部的旅程是:iBGP 告訴入口路由器「這個前綴的出口是邊界路由器 B」,而內部協定算出抵達邊界路由器 B 真正逐跳的路徑。兩個協定,兩個問題:iBGP 回答「我該從哪扇門離開?」內部協定回答「我怎麼走到那扇門?」
一條路線如何被選中,以及 BGP 為何脆弱
一個 AS 常常會聽到好幾條通往同一個前綴的不同 BGP 路線,每個鄰居一條,而它必須挑一條。它把這些路線跑過一份固定的屬性排序,而這個順序揭露了優先次序。第一個、也最有力的是本地偏好(local preference):一個 AS 純粹基於自己的政策理由設定的數字,通常用來偏好較便宜的出口(讓流量先走免費的對等互連連結,再走付費的供應商連結)。只有當本地偏好打平時,才退回去比較最短的 AS 路徑長度——這是 BGP 最接近在乎距離的時候,而它數的是 AS 跳數,不是英里或毫秒。在清單裡更低的位置,坐著 MED(多出口判別值),那是一個鄰居可以送來的提示,用來把你推向它某一個入口點而非另一個。
現在把整幅畫面拼起來。那些跑完整 BGP、對網際網路上每一個目的地都備有一條路線、完全不持有任何預設路由的路由器,住在所謂的無預設區(default-free zone)裡。一台位於無預設區的路由器不能聳聳肩說「我不知道,往上游送」;它必須真的知道一條通往現存每一個前綴的路徑。今天那大約是一百萬個前綴,一張逐年成長的表,而要讓它在全球各地保持一致,是一場在彼此不信任的當事人之間持續進行、極其微妙的協商。
那場協商正是 BGP 之所以以脆弱著稱的原因,本階段最後一篇會把這個主題完整探討。有三種失敗形狀反覆出現。一條不穩定的連結可能造成路由抖動(route flapping),一個前綴被宣告、被撤回,一再反覆,而每一次變動都向外擴散,逼得全球的路由器重新計算。一個設定錯誤或一個攻擊者可能造成劫持(hijack),一個 AS 宣告一個根本不屬於它宣告的前綴,把全世界的流量拉向自己。而當一個 AS 不小心把它本來只該自己用的路線重新宣告出去、接下了一段它從未答應提供的中轉時,就發生了洩漏(leak)。統合起來的教訓令人清醒:傳統的 BGP 大致上信任鄰居告訴它的話,所以單一一則壞掉的宣告,就能擾亂遠方的流量。把網際網路黏合在一起的那層膠水,反過來說,大部分是靠善意撐著的。