首頁 運維 安全 透過QUIC協議,來看看怎麼學習網路協議

透過QUIC協議,來看看怎麼學習網路協議

Mar 01, 2022 am 09:57 AM
協定 網路協定

這篇文章帶大家了解QUIC協議,並以QUIC協議為例,來聊聊如何學習網路協議,希望對大家有幫助!

透過QUIC協議,來看看怎麼學習網路協議

在先前發布的關於 s2n-quic 的文章中,有讀者問我如何學習像 QUIC 這樣的網路協定。對於大部分網路從業者來說,雖然大家每天都在跟網路打交道,但很少有人會(需要)關心HTTP 之下的網路協定的細節,大部分時候,了解個大概,知道如何使用就可以了。如果你對QUIC 一點概念都沒有,那麼,下面這個圖能幫助你很好地了解QUIC 在HTTP/3 生態中的地位:

透過QUIC協議,來看看怎麼學習網路協議

那麼,如果你就是要詳盡地了解QUIC 的知識,該如何入手呢?

作為一個曾經的網路協定和網路設備的開發者,我自己的心得是:從 RFC 入手,輔以 wireshark 抓包,來快速掌握目標協定。

對於 QUIC 而言,我們首先需要閱讀的是 RFC9000。協議的閱讀是非常枯燥的事情,需要一定的耐心,如果英文不太好,可以用 google translate 將其翻譯成中文,快速瀏覽一番(泛讀)。第一遍閱讀主要了解裡面的主要概念,以及主要流程。

之後,我們就可以撰寫使用 QUIC 協議的程序,然後透過 wireshark 抓包,透過研究實際的報文,對比 RFC 協議中的內容(精讀),來更深入地理解協議的本質。

我們還是以上一篇文章中的程式碼為基礎,建構 echo 用戶端和伺服器。為方便大家閱讀,我把程式碼也貼上來。有興趣的同學可以自行 clone 我的 repo,並執行 client/server 程式碼。

客戶端程式碼(請參閱github: tyrchen/rust-training/live_coding/quic-test/examples/client.rs):

透過QUIC協議,來看看怎麼學習網路協議

#服務端程式碼(見github: tyrchen/rust-training/live_coding/quic-test/examples/server.rs):

透過QUIC協議,來看看怎麼學習網路協議

這兩段程式碼建構了一個最簡單的echo server。我們可以使用 wireshark 監聽本地 loopback 介面下的 UDP 包,進行抓包。要注意的是,對於 QUIC 這樣使用了 TLS 協定的流量,即便抓到了包,可能只有頭幾個包可讀,後續的包都是加密內容,無法閱讀。因此,我們在建置 client/server 時,需要想辦法把伺服器和客戶端之間協商出來的 session key 抓取下來,供 wireshark 解密使用。一般 SSL/TLS 函式庫都會提供這個功能。例如對於 Rustls,我們可以在 tls config 中使用 key_log。如果你仔細看上面server 的程式碼,你會看到這句話:

let config = Builder::new()
    .with_certificate(CERT_PEM, KEY_PEM)?
    .with_key_logging()? # 使能 keylogging
    .build()?;
登入後複製

使用了key_log 後,在啟動server 的時候,我們只需要指定SSLKEYLOGFILE 就可以了:

SSLKEYLOGFILE=session.log cargo run --example server
登入後複製

在抓包完成後,打開wireshark 的preference,選擇TLS 協議,把log 的路徑放進去就可以了:

透過QUIC協議,來看看怎麼學習網路協議

以下是一次完整的客戶端和伺服器的交互的抓包,我們看到,所有「protected payload」 都被正常顯示出來了:

透過QUIC協議,來看看怎麼學習網路協議

#因為我們的echo client 只做了最簡單的動作(只開了一個bidirectional stream),所以透過這個抓包,我們專注於可以研究QUIC 協定建立連線的過程。

客戶端發送的首包

我們看客戶端發送的第一個訊息:

透過QUIC協議,來看看怎麼學習網路協議

#這個報文包含了非常豐富的資訊。首先,和TCP 握手不同的是,QUIC 的首包非常大,有1200 字節之多(協議要求UDP payload at least 1200 bytes),包含QUIC 頭,一個255 字節的CRYPTO frame,以及890 字節PADDING frame。從 header 可以看到,這個 QUIC 套件的型別是 Initial。

QUIC 封包類型

#對於QUIC 套件來說,Header 是明文,之後的所有frame payload 都是密文(除了頭幾個包)。我們看到這個首包是一個 Long Header 報文,在 RFC9000 的 17.2 節中,定義了 Long Header Packet:

Long Header Packet {
   Header Form (1) = 1,
   Fixed Bit (1) = 1,
   Long Packet Type (2),
   Type-Specific Bits (4),
   Version (32),
   Destination Connection ID Length (8),
   Destination Connection ID (0..160),
   Source Connection ID Length (8),
   Source Connection ID (0..160),
   Type-Specific Payload (..),
 }
登入後複製

感興趣的可以自行去閱讀 RFC 相應的章節。對於 Long Header 報文,有以下幾種類型:

透過QUIC協議,來看看怎麼學習網路協議

既然有 Long Header packet,那么就有 Short Header packet,Short Header packet 目前的版本只有一种:

1-RTT Packet {
   Header Form (1) = 0,
   Fixed Bit (1) = 1,
   Spin Bit (1),
   Reserved Bits (2),
   Key Phase (1),
   Packet Number Length (2),
   Destination Connection ID (0..160),
   Packet Number (8..32),
   Packet Payload (8..),
}
登入後複製

为什么需要 connection id?

在我们捕获的这个报文头中,我们看到有 Source Connection ID(SCID)和 Destination Connection ID(DCID)这个新的概念。你也许会好奇:QUIC 不是基于 UDP/IP 的协议么?底层的协议已经有五元组(src ip / src port / dst ip / dst port / protocol)来描述一个连接(connection),为什么还需要 connection id 这样一个新的概念?

这是为了适应越来越多的移动场景。有了 QUIC 层自己的 connection id,底层网络(UDP/IP)的变化,并不会引发 QUIC 连接的中断,也就是说,你从家里开车出门,即便手机的网络从 WIFI(固网运营商分配给你的 IP)切换到蜂窝网络(移动运营商分配给你的 IP),整个 UDP/IP 网络变化了,但你的 QUIC 应用只会感受到细微的延迟,并不需要重新建立 QUIC 连接。

从这个使用场景来看,QUIC 底层使用无连接的 UDP 是非常必要的。

首包中就包含了 TLS hello?

我们接下来看看 CRYPTO frame:

透過QUIC協議,來看看怎麼學習網路協議

可以看到,QUIC 在建立连接的首包就把 TLS Client Hello 囊括在 CRYPTO frame 中。并且使用的 TLS版本是 1.3。在 Client Hello 的 extension 中,QUIC 协议使用了一个 quic_transport_parameters 的 extension,用来协商 QUIC 自己的一些初始值,比如支持多少个 stream,这个连接中可以最多使用多少个 active connection id 等等。

QUIC 支持哪些 frame?

现在我们已经见到了两种 Frame:CRYPTO 和 PADDING。下表中罗列了 QUIC 所有支持的 frame:

透過QUIC協議,來看看怎麼學習網路協議

服务器的回包

我们来看 server 的回包:

透過QUIC協議,來看看怎麼學習網路協議

这里有一些新东西。首先,一个 UDP 包内部可以包含若干个 QUIC payload,我们看到 server 回复了一个 QUIC Initial 报文和一个 QUIC Handshake 报文。在 Initial 报文中,我们看到了一个 ACK frame,可见 QUIC 虽然构建于 UDP,但在 QUIC 协议内部构建了类似 TCP 的确认机制。

我们之前看到,在 Initial 报文的 CRYPTO frame 中,客户端发送了 TLS Client Hello,同样的,服务器在 Initial 报文的 CRYPTO frame 中发送了 TLS Server Hello。这个我们就略过不看。

在 Handshake 报文中:

透過QUIC協議,來看看怎麼學習網路協議

服务器发送了自己的证书,并结束了 TLS handshake。

客户端结束 Handshake

我们再看第三个包,客户端发送给服务器结束 TLS 握手:

透過QUIC協議,來看看怎麼學習網路協議

这个包依旧包含两个 QUIC 报文,其中第一个就是一个 ACK frame,来确认收到了服务器的 Server Hello 那个 QUIC 报文;第二个包含一个 ACK frame,确认服务器的 Handshake,随后有一个 CRYPTO frame 结束客户端的 TLS handshake。

TLS 握手结束之后,客户端和服务器就开始应用层的数据交换,此刻,所有数据都是加密的。

客户端发送一个 “hello” 文本

在我们的  echo client/server 代码中,客户端连接到服务器后,就可以等待用户在 stdin 的输入,然后将其发送到服务器。服务器收到客户端数据,原封不动发回,客户端再将其显示到 stdout 上。在这个过程的前后,客户端和服务器间有一些用于连接管理的 QUIC 报文,比如 PING。我们就略过,只看发送应用层数据的报文。下图是客户端发送的包含 “hello” 文本的报文:

透過QUIC協議,來看看怎麼學習網路協議

可以看到,這裡 QUIC 訊息是個 Short Header packet,除了 ACK frame 外,它還有一個 STREAM frame。這個 stream 的 stream ID 最低兩位是 00,代表是客戶端發起的,雙向的 stream。由於使用了兩位來表達類型,所以QUIC 的stream 有以下類型:

透過QUIC協議,來看看怎麼學習網路協議

我們來看STREAM frame 的length(6) 和Data(68 65 6c 6c 6f 0a )。 Data 裡的內容如果用 ASCII 表示,剛好是 “hello”,它的長度是 6 個位元組。

伺服器回覆「hello」文字

#最後是伺服器echo back:

透過QUIC協議,來看看怎麼學習網路協議

# #這個和上面的報文如出一轍,就不解釋了。

賢者時刻

相信透過上面對照著wireshark 抓包進行的QUIC 簡介,能讓你對QUIC 協議有一個初步的認識。上篇文章,我們說 QUIC 支援多路復用,並且解決了傳輸層隊頭阻塞的問題。透過這篇文章的介紹,你能回答以下兩個問題麼?

  • QUIC 透過哪個 frame 類型來做多路復用的?

  • QUIC 如何解決傳輸層隊頭阻塞的?

相關推薦:

web伺服器安全性

以上是透過QUIC協議,來看看怎麼學習網路協議的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1657
14
CakePHP 教程
1415
52
Laravel 教程
1309
25
PHP教程
1257
29
C# 教程
1230
24
vivo快充屬於哪個協議 vivo快充屬於哪個協議 Sep 06, 2022 pm 02:43 PM

vivo快充主要有兩個協議:1、「QC 2.0」快充協議,「QC2.0」就是「Quick Charge 2.0」技術,是高通公司發布的快充技術2.0版本,可以輸出5V、9V、12V 、20V四組電壓;2、PD快充協議,是由“USB-IF”組織制定的一種快速充電規範,是目前主流的快充協議之一,可以使目前默認最大功率“5V/2A”的“type-c”介面提高到100W。

pd3.0快充協議最高多少w pd3.0快充協議最高多少w Nov 08, 2022 pm 04:04 PM

pd3.0快充協定最高支援「100W」。 2015年11月,USB PD快充迎來了大版本更新,進入到了USB PD3​​.0快充時代;PD3.0協議支援5V3A、9V3A、12V3A、15V3A、20V5A輸出,最​​大功率可以到100W,不僅可以用在手機充電上,還可以用筆記本或是顯示器供電。

5種工業通訊協議是什麼 5種工業通訊協議是什麼 Sep 28, 2022 am 11:52 AM

5種工業通訊協議:1、Modbus協議,是應用於電子控制器上的一種通用語言;2、RS-232協議,是一種串行物理接口標準;3、RS-485協議,是在RS232的基礎上發展來的;4、HART協議,是一種用於現場智慧儀表和控制室設備之間的通訊協議;5、MPI協議,是一個跨語言的通訊協議,用於編寫並行電腦。

Go 語言中的網路協定有哪些? Go 語言中的網路協定有哪些? Jun 10, 2023 pm 02:06 PM

近年來,Go語言作為一種高效、輕量級、並發性優異的程式語言,受到越來越多人的關注與喜愛。在網路程式設計方面,Go語言擁有豐富的網路協定支持,能夠幫助開發者快速、方便地建立網路應用。下面就讓我們來了解一下Go語言中的網路協定有哪些。 1.TCPTCP(TransmissionControlProtocol,傳輸控制協定)是一種在電腦網路中常用的傳輸協

Java網路程式設計有哪些常見的協定? Java網路程式設計有哪些常見的協定? Apr 15, 2024 am 11:33 AM

Java網路程式設計中常用的協定包括:TCP/IP:用於可靠資料傳輸和連線管理。 HTTP:用於Web資料傳輸。 HTTPS:HTTP的安全版本,使用加密傳輸資料。 UDP:用於快速但不穩定的資料傳輸。 JDBC:用於與關聯式資料庫互動。

PHP中的SOAP協定指南 PHP中的SOAP協定指南 May 20, 2023 pm 07:10 PM

隨著互聯網技術的不斷發展,越來越多的企業級應用需要向其它應用程式提供介面以實現資料和業務的互動。在這種情況下,我們需要一種可靠的協定來傳輸資料並確保資料的完整性和安全性。 SOAP(SimpleObjectAccessProtocol)是一種基於XML的協議,可用於在Web環境中實現應用程式之間的通訊。而PHP作為一種流行的Web程式語言,

qc4+快充協議是什麼 qc4+快充協議是什麼 Aug 18, 2022 pm 03:49 PM

QC4+快充協定是USB PD PPS協定和QC3.0/2.0快充協定的綜合體,是一種多功能、多協定的快充技術。 QC4+充電協定對USB PD3​​.0(PPS)進行了相容,同時向下相容USB PD2.0、QC3.0、QC2.0、BC1.2等協定。支援USB PD、QC4+的首要前提,是兩端皆有USB-C介面的支援和基於USB-C介面中的CC(配置通道)的電力協商封包。

網路協定的三要素有哪些 網路協定的三要素有哪些 Dec 09, 2020 am 10:23 AM

網路協議的三要素:1、語義,即解釋控制訊息每個部分的意義;它規定了需要發出何種控制訊息,以及完成的動作與做出什麼樣的回應。 2.語法,即使用者資料與控制資訊的結構與格式,以及資料出現的順序。 3、時序,即事件發生順序的詳細說明。

See all articles