弈心:從事計算機網絡工作十年(新加坡7年,沙特3年),2013年考取CCIE,在新加坡先後任職于AT&T,新加坡交通部,蘋果,Equinix,蘇格蘭皇家銀行等大型企業、銀行和政府部門。 目前供職于“世界第一土豪大學“沙特阿蔔杜拉國王科技大學(KAUST),擔任Senior Network Engineer,為KAUST校史上第一位也是唯一一位華人IT部門高級職員。2019年6月在知乎發布了華語圈第一本專門為編程零基礎的網絡工程師量身打造的Python教程《網絡工程師的Python之路》。
國外流傳的一道CCIE挑戰題,這道題難度不低,出題的人是一位羅馬尼亞裔的美籍CCIE。為了防止作弊,所有參與者的回答都被出題人屏蔽,自己和出題者交流了一會,在得到所有自己所需要的信息後,花了幾天的時間做模拟實驗,找相關資料研究,最終給出了正确的答案。出題者肯定了我的解法,但是提醒我解法不止一種,并向我解釋了其他的解法,自己受益頗多,對ACL和Fragmentation(數據包分片)也有了更深層的理解。
先來看看這道題的拓撲,背景信息以及問題。
圖1
圖2
背景信息:
1. 某公司有三個site,分别為R1,R2,R3。
2. R3和R2之間跑GRE隧道,R2和R3的interface tunnel的MTU被人為的從1476改為1440.
3. R2和R1之間有兩條connection,一條是它們兩個互相直連的Backdoor(192.168.12.0/24),另外一條是通過ISP走Internet,R2-ISP-R1,走Internet的流量做了NAT(嚴格來說是PAT),走Backdoor的流量沒有NAT。
4. 用戶(172.16.1.10)直連R3,服務器(1.1.1.10)直連R1,服務器上運行的程序需要用到TCP port 1001和1002.
5. 需求: 如圖2所示,在R2上用PBR分流,實現TCP 1001的流量走R3-R2-R1, TCP 1002的流量走R3-R2-ISP-R1。
問題:
圖1給出了R2的配置,測試結果是走R3-R2-R1這條route的TCP1001的流量正常(圖3),走R3-R2-ISP-R1的TCP 1002的流量則有問題:TCP三次握手已經完成,但是session随後卡住,不久之後session timeout(圖4),需要找出原因并給出解法。
圖3(TCP1001流量正常)
圖4(TCP1002流量:TCP三次握手成功,但是随即卡住并Timeout)
解題思路:
1.
首先通看一遍出題者給的R2的配置,沒發現什麼大問題。因為既然用戶端(172.16.1.10)和服務器(1.1.1.10)之間的TCP 1001和1002兩種流量的TCP三次握手都成功完成了,那就說明了無論是路由,PBR,GRE隧道,還是PAT等等的配置都沒有任何問題。
2. 重新讀一遍題目的背景信息,其中第二條引起了我的注意:“R2和R3的interface tunnel的MTU被人為地從1476改為1440”。衆所周知,GRE隧道的header是24 Byte,所以通常來說GRE隧道端口的MTU是1500-24=1476 Byte (前提是配置GRE之前,物理端口使用的MTU是默認的1500),那麼再被人為地改為1440之後有什麼影響呢?這裡有很重要的一點要考慮,那就是用戶端(172.16.1.10)是否開啟了PMTUD(Path MTU Discovery),也就是“路徑MTU發現”的功能,因為這直接影響到用戶端的IP包在經過R3時會不會因為前後MTU的不匹配而導緻被R3進行Fragmentation (IP數據包分片),因為通常來說,Fragementation有一個很大的缺點,那就是它大大降低了網絡的傳輸性能,會引起很多諸如丢包,延時,線路不穩定,甚至連接失效的問題,對于這個問題,因為出題者在背景信息裡沒有明确說明,我特此詢問了他,得到的回答是,在他的實驗環境裡,用戶端(172.16.1.10)實際上是一台跑FreeBSD的服務器,他在用戶端通過PMTUD探測到了GRE的MTU(1476)之後,故意關閉了PMTUD,并給我解釋他之所以沒在背景信息裡給出這個條件,目的就是為了提高這道題的難度,并說我能考慮到這點,說明我的思路是對的,叫我繼續做下去。
3.順着這個思路繼續往下看,現在用戶端的MTU是1476(PMTUD被關閉之前學到的),PMTUD被關閉後,用戶端無法重新探測到R2和R3的GRE隧道的新MTU(1440),所以用戶端還是照舊把1476的包丢給R3,又因為1476大于1440,導緻這時R3不得不對用戶端的包做IP分片了。這就導緻了R2從R3接收到的用戶端的包其實是一大堆fragments(IP碎片)。考慮到這裡後,雖然自己清楚IP分片會導緻各種各樣的鍊路問題,但針對這道題來說,究竟是什麼導緻了TCP1002流量的問題,自己曾一時毫無頭緒。
4. 既然用戶端的包有被R3做IP分片的事實存在,那麼為什麼走R3-R2-R1的TCP 1001的流量沒有問題,唯獨走R3-R2-ISP-R1的TCP 1002卻有問題呢?帶着這個疑問,回頭再看R2的配置,下面這個被PBR用來分流的ACL引起了我的注意。
ip access-list extended ACL_USE_BACKDOOR
permit tcp host 172.16.1.10 host 1.1.1.10 eq 1001
exit
這個ACL表達的意思一目了然:匹配所有從用戶端172.16.1.10去往服務器1.1.1.10,TCP端口為1001的數據。乍一看沒有任何問題,實則這裡面隐含了一個巨大的玄機,那就是當4層ACL遇到IP碎片時所産生的一些列“化學反應",要搞清楚這個,必須先弄明白IP碎片到底是怎麼一回事,為此我特意畫了下面兩個圖來說明。圖5為正常情況下,沒有被路由器fragmented的一個完整的IP包(MTU為1500),圖6則是這道題裡,已經被R3(MTU 1440)做了IP分片後的用戶端的包(MTU 1476),分别為“第一個碎片”和“第二個碎片”
圖5:完整IP報文
圖6:IP報文第一個碎片和第二個碎片
5.圖5很好理解,通常一個完整IP包的MTU是1500 Byte,扣去3層的IP header (20 Byte,藍色部分)和4層的TCP header (20 Byte,橙色部分),剩下的data payload為1460 Byte, 這個1460 Byte在TCP裡又叫做MSS (Maximum Segment Size,注意隻有TCP有MSS,UDP沒有這個東西),MSS是後話,暫且不表。
6. 圖6是解出這道題的關鍵所在。第一個碎片(1440 Byte)和第二個碎片(56 Byte)的區别一目了然,第一個碎片有4層header(橙色),第二個碎片沒有,這種情況對1001和1002的包有什麼影響呢?詳解如下:
首先再回顧一次這個ACL,看它對TCP 1001和TCP 1002兩種IP碎片包産生了什麼影響:
ip access-list extended ACL_USE_BACKDOOR
permit tcp host 172.16.1.10 host 1.1.1.10 eq 1001
exit
TCP 1001的第一個碎片,Src IP = 172.16.1.10, Dst IP = 1.1.1.10, Src tcp port = any, Dst tcp port = 1001,符合ACL的條件,R2對這個碎片做PBR,即将它丢給R1。
TCP 1001的第二個碎片,Src IP = 172.16.1.10, Dst IP = 1.1.1.10, 依然符合ACL的條件,R2對這個碎片做PBR,即将它丢給R1。
TCP 1002的第一個碎片,Src IP = 172.16.1.10, Dst IP = 1.1.1.10, Src tcp port = any, Dst tcp port = 1002,不符合ACL的條件,R2對這個碎片做PAT,将它丢給ISP。
TCP 1002的第二個碎片,Src IP = 172.16.1.10, Dst IP = 1.1.1.10, 符合ACL的條件,R2對這個碎片做PBR,即将它丢給R1。
結論:
A.TCP 1001的第一個和第二個碎片都滿足ACL,都被R2的PBR丢給了R1,R1再将兩個碎片包傳給服務器1.1.1.10,所以TCP 1001的流量正常。
B.TCP 1002的第一個碎片(1440 Byte)沒有滿足ACL,被R2的PBR丢給了ISP,第二個碎片(56 Byte)滿足了ACL,被R2的PBR丢給了R1,現在兩個碎片被活生生的拆散開了,兩個碎片包“分道揚镳”的結果造成了TCP 3次握手成功,但是随即timeout的問題。
解法:
前面已經很系統地分析出了問題所在:因為用戶端關閉了PMTUD,再加上R3和R2的MTU從1476被改小到1440,導緻MTU不匹配,從而引發了R3對用戶端的包進行Fragmentation(IP 分片)的行為,而又因為R2上配置的4層ACL導緻了TCP 1002的第一個和第二個碎片包被R2分别丢去了ISP和R1,導緻碎片無法複原,最終造成TCP 1002數據的連接問題。
弄清楚了問題出在哪裡後,接下來就是對症下藥了,這道題解法有多種,一一解釋如下。
解法1
用戶端172.16.1.10開回PMTUD,讓用戶端學習到新的MTU(1440),從而避免fragmentation。這是最直接也是最簡單的解法,這也是為什麼出題者在背景信息裡沒有給出“關閉了PMTUD"這個條件,不然的話,每個人都回答“開回PMTUD",那這道挑戰CCIE的題還有什麼挑戰性可言?
解法2
在R3端口上修改MSS,命令為ip tcp adjust-mss,避免fragmentation。
前面簡單提到過MSS這個東西,關于MSS,一些總結如下:
1. MSS出現在TCP的SYN包裡, 它和UDP無關。
2.MSS和MTU的區别在于,MSS是TCP數據包每次能夠傳輸的最大數據分段,它永遠比MTU小40 Byte,這40 Byte是什麼?前面的圖5已經解釋過了,即3層包頭(20 Byte)和4層包頭(20 Byte)。以這道題為例,用戶端包的MTU 為1476,那麼它TCP SYN包裡的MSS就為1436。
3. 顧名思義,思科的ip tcp adjust-mss這個命令的作用就是用來修改MSS大小的,以這道題為例,在R3上配置ip tcp adjust-mss 1300,當用戶端的包(MSS 1436)到了R3上後,因為1436>1300,這時R3就會把用戶端TCP包的MSS修改為1300,然後丢給R2, R2看到1300<1400,也就不會再對這個包做IP分片了,從而避免了fragmentation。
4. ip tcp adjust-mss這個命令是在端口下配置,至于配置在哪個端口,沒有硬性規定,就這道題來說,把它配置在直連用戶端的端口或者連接R2的端口上都可以,效果一樣。
解法3
修改PBR的ACL,讓TCP 1002的碎片也走R3-R2-R1。
Ip access-list extended ACL_USE_BACKDOOR
permit tcp host 172.16.1.10 host 1.1.1.10 eq 1001
Permit tcp host 172.16.1.10 host 1.1.1.10 eq 1002
這個解法不完美,主要有兩個原因:
1. 違反了題目的規定,即TCP 1002的流量要走R3-R2-ISP-R1。
2. 這個解法治标不治本,因為将來如果遇到其他TCP端口的類似需求怎麼辦,一直違背分流的初衷?
解法4
修改PBR的ACL,逼迫TCP 1002的碎片被PAT,然後走R3-R2-ISP-R1。
ip access-list extended ACL_USE_BACKDOOR
deny tcp host 172.16.1.10 host 1.1.1.10 eq 1002
permit tcp host 172.16.1.10 host 1.1.1.10 eq 1001
這個解法同樣不完美,原因很簡單,TCP 1001的第一個碎片沒問題,但是第二個碎片也被丢給了ISP,同樣的問題又發生了,隻是這次出問題的是TCP 1001。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!