1. 程式人生 > >TCP/IP 系列之 Header 篇

TCP/IP 系列之 Header 篇

這是 TCP/IP 系列的第二篇,閱讀目標是建立對網路包結構的初步認識。

上一篇裡,我們提到一次完整的 TCP 會話其實是一個位元組流,只不過我們可以按照一定的規則來切割這個位元組流,從而劃分出一個個的網路包。我們經常說抓包分析網路故障,這個抓包裡所指的包在不同的語境下其實意義並不相同,首先我們得對包的構成形成具象的認知。

再看七層協議

前幾年,大家都喜歡在簡歷上寫「精通 TCP/IP 協議」,面試被問起時就必答三次握手和 OSI 七層模型,再多就說不出來了。問七層模型是什麼就機械式的從上至下背誦一遍,這離精通還差了一本【TCP/IP 詳解】。

我在完整的學習過一遍網路協議棧之後,深感所謂的七層模型是偏工業的說法,看到七層協議圖之後,其實很難明白這七層是如何一層層互相構成的,更符合大腦感官的是另一種認知形式,是一種洋蔥形的結構,層層疊疊互相包裹,可以用下圖表示:

左邊是教材上的結構,右邊是我所說的洋蔥式的結構。如果以一個 HTTP 請求為例,右圖中 Application 部分就代表我們用 Charles 抓包時所感知的部分,這一部分要最後轉化為光訊號,在光纖中傳輸,還需要經過一層層的轉化,這個轉化過程說白了,就是在每一層加上一個 header。

  • Application 層(HTTP)的資料在經過傳輸層(TCP Layer)的時候,會加上 TCP 的 header,成為一個 TCP Segment。
  • 傳輸層(TCP)的 Segment 在經過網路層(IP Layer)的時候,會加上 IP 的 header,成為一個 IP Packet。
  • 網路層的 IP Packet 在經過鏈路層(Link Layer)的時候,會加上Link Layer 的 header,成為一個 Frame。
  • 最後 Frame 會在物理層,將數字訊號轉化為物理訊號傳輸。

這裡值得特別注意的是,在每一層,有不同的英文術語來對應包的概念,比如在 TCP 層的包叫做 Segment,在 IP 層的叫做 Packet,在鏈路層的叫做 Frame,另外和 TCP 位於同一層的 UDP 包我們一般叫做 Datagram,不同協議層裡術語並不一樣,好處是,在交流的時候,我們選擇不同的英文單詞就能預先確立是在那一層討論協議。而 Segment、Packet、Frame、Datagram 等翻譯成中文的時候,都是譯為「包」,大家說讀英文原版資料是不是更好,這些術語我們需要特別記憶,可以對照下圖:

 +-------------+-------------------------+
 | Application |  HTTP Packet            |
 +-------------+-------------------------+
 | Transport   |  TCP Segment            |
 +-------------+-------------------------+
 | Network     |  IP Packet              |
 +-------------+-------------------------+
 | Link        |  Frame                  | 
 +-------------+-------------------------+         光纖
 | Physical    |  Bits                   | ====================> 
 +-------------+-------------------------+

不過有些場景下,我們也會用 Packet 來泛指每一層的包,但是用每一層自己的術語會更準確和專業,這些行話和習慣我們也需要了解。

我們可以用一個公式來表示每一層協議的構成:

Packet = Protocol Header + Payload

每一層的包都可以用這個公式來表示。Payload 指傳入這一層的資料內容,比如:

TCP Segment = TCP header + HTTP data

有了這個認知之後,對於每一層協議的學習,最後就落實到每一層 header 的學習上了,學習 TCP 就是研究 TCP header 的構成,header 裡的每一個 bit 位都有特別的用處,來實現協議層對於網路傳輸的控制。這也是為什麼我經常會說,所謂的網路協議學習就是 header 學習,這也是本文標題的含義所在。

深入 Header

【TCP/IP 詳解】大致有 1000 頁,通讀的過程會很漫長且枯燥,知道每一層協議都是關於 header 的設計之後,大家其實可以先跳躍式的閱讀,先學習感興趣的部分,有了收穫知識的正向反饋之後,在回過頭來填補更多的知識細節。比如大家一般都對 TCP 協議比較感興趣(確實也是最有意思的部分,後面的文章也重點分析),那麼可以先跳到第十二章:

Chapter 12 TCP: The Transmission Control Protocol(Preliminaries)

或者第十三章,真正明白所謂的三次握手:

Chapter 13 TCP Connection Management

由於每一層的設計都是獨立的,所以先學習傳輸層並不會有什麼障礙,這也是分層架構的意義所在,各層各司其職,互不依賴具體的實現。

我們的學習行為,大致上可以分為兩類,理解(理解思想)和記憶(強行記憶)。對於 header 的學習,除了理解 header 每個 bit 的意義之外,還需要一些記憶行為,對於一些關鍵資訊的強制性記憶,有助於我們形成更深刻的認知。我們以 TCP 的 header 為例:

上圖是一個 TCP header,以下是一些需要「死記硬背」的資訊點:

一個 TCP Header 一般有 20 個位元組,如果啟用了 options,header的長度可以達到 60 個位元組。上圖中每一行是 4 個 bytes,32 個 bits。我先帶大家學習下前 5 行,每一行是 4 Bytes,五行剛好是 20 個 bytes。計算機世界中,通常會以 bit,byte,word(4 個 byte)等不同粒度來描述資訊,header 的學習一般是以 4 個位元組為一個單位來展示的。

  • 第一行,由 Source port 和 Destination port 構成,二者各佔 2 個位元組,剛好一起佔據第一行的 4 個位元組。這兩個欄位分別表示 TCP 連線中的,傳送方埠號和接收方的埠號,既然一個 port 只佔 2 個 bytes,那麼埠值的範圍自然就是 0~65535 啦。
  • 第二行,Sequence number,表示傳送方的序列號。這個序列號表示的是什麼呢?一個 TCP 流是有無數個 0 和 1 構成,這些 0 和 1 以 8 個 bit 為單位,可以分割成一個個的 byte,TCP 是可靠傳輸協議,每一個 byte 都是有標號的,因為我們需要追蹤每個 byte 是否被成功傳輸了,每個 byte 的標號就是我們這裡的 sequence number。假設我們建立 TCP 連線的時候,發一個 sync 包,我們就以 0 標記 sync 包的第一個位元組,那麼 sync 包中的 Sequence 值就是 0。實際應用中,處於安全考慮,TCP 流的第一個 Sequence number 一般不會是 0,而是一個隨機數。Sequence number 佔據 4 個位元組,也就是 2 的 32 次方,這個數字並不算大,每個包都會用掉一些,如果達到最大值之後,就取餘從 0 重新開始。
  • 第三行,Acknowledge number,表示接收方 ack 的序列號。接收方收到傳送方一個的 TCP 包之後,取出其中的 sequence number,在下一個接收方自己要傳送的包中,設定 ack 位元位為 1,同時設定 acknowledge number 為 sequence number + 1。所以接收方的 acknowledge number 表示的是,接收方期待接收的下一個包起始位元組的標號,大家可以仔細理解下這一句話。所以 acknowledge number 和 sequence number 是配對使用的。
  • 第四行,這一行尤其重要,出於篇幅的考慮,其中細節會在後續的文章中講解。這裡簡單提下從 CWR 到 FIN 的 8 個 bit,這 8 個 bit 裡每一位都是一個標記位,用來標記當前 TCP 包的特殊含義。比如我們所說的三次握手,第一個 sync 包,就是將 SYN 位置為 1。第二個 syn + ack 包就是將 header 的 ACK 和 SYN 位都置為 1。第三個 ack 包即將 ACK 位置 1。剩餘的幾個 bit 位暫時不展開講了,大家可以自己看書先學習下。
  • 第五行,這一行只有兩個欄位,即 Checksum 和 Urgent pointer。checksum 是個通用的計算機概念,做完整性校驗之用,在很多協議(IP,UDP,ICMP)中都有應用,這個值有包的傳送方去計算,之後由包的接收方取出來校驗。Urgent pointer 為兩個位元組的偏移量,加上當前包的 sequence number,用來標記某一個範圍內的 bytes 為特殊用途資料。

怎麼樣、其實沒有多少資訊量對不對?這麼跟著理解一遍 header 中的每一個 bytes 之後,是不是加深了對 TCP 的理解呢?

同理,學習完 TCP 的 header 之後,大家可以再去把 IP 的 header,frame 的 header 都搜尋出來,對照關鍵欄位去理解學習,最後再配合【TCP/IP 詳解】一書閱讀效果更好。

Tcpdump 實戰

上面是理論部分,可能有些枯燥,大家可以在理解之後,使用 tcpdump 抓包實戰下,進一步加深理解。我們就來抓包,基於上面 tcp header 的學習,抓下三次握手的包 ?

我們可以用如下命令來抓三次握手的包:

| sudo tcpdump -i en0 “tcp[tcpflags] & (tcp-syn | tcp-ack) != 0” |

輸出結果為:

  • 18:18:45.687476 IP 192.168.3.7.65284 > 59.37.116.101.https: Flags [S], seq 3942311653, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 589105996 ecr 0,sackOK,eol], length 0

  • 18:18:45.719744 IP 59.37.116.101.https > 192.168.3.7.65284: Flags [S.], seq 303118583, ack 3942311654, win 14280, options [mss 1412,sackOK,TS val 1712930033 ecr 589105996,nop,wscale 8], length 0

  • 18:18:45.719986 IP 192.168.3.7.65284 > 59.37.116.101.https: Flags [.], ack 1, win 4112, options [nop,nop,TS val 589106029 ecr 1712930033], length 0

你能根據上面 tcp header 的學習,理解上面 tcpdump 命令的含義嗎?tcpflags 指的是 header 中的哪些位呢?

對於 tcpdump 的使用還不太瞭解的同學,可以翻閱我之前的一篇介紹文章。

當然 TCP 裡還包含著很多有趣的知識點,大家可以先行閱讀,後面我會逐步講解,比如 TCP 的 ARQ 機制,Flow Control 等。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大傢俱有一定的參考學習價值,同時歡迎大家進入小編交流群:624212887,一起交流學習,謝謝大家的支援