Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Freigeben: 2022-03-01 10:09:02
nach vorne
3219 Leute haben es durchsucht

Dieser Artikel führt Sie zum Verständnis des QUIC-Protokolls und erläutert anhand des QUIC-Protokolls anhand eines Beispiels, wie man Netzwerkprotokolle lernt. Ich hoffe, dass es für alle hilfreich ist!

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

In einem früheren Artikel über s2n-quic fragte mich ein Leser, wie man ein Netzwerkprotokoll wie QUIC lernt. Obwohl sich die meisten Internet-Praktiker täglich mit dem Internet befassen, kümmern sich nur wenige um die Details des Netzwerkprotokolls unter HTTP. Meistens reicht es aus, ein allgemeines Verständnis zu haben und zu wissen, wie man es verwendet. Wenn Sie keine Ahnung von QUIC haben, kann Ihnen das folgende Bild helfen, die Position von QUIC im HTTP/3-Ökosystem gut zu verstehen:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Wenn Sie also nur im Detail mehr über QUIC erfahren möchten, erfahren Sie hier, wie Sie es erhalten angefangen?

Als ehemaliger Entwickler von Netzwerkprotokollen und Netzwerkgeräten ist meine eigene Erfahrung: Beginnen Sie mit RFC, ergänzt durch Wireshark-Paketerfassung, um das Zielprotokoll schnell zu beherrschen.

Für QUIC müssen wir als Erstes RFC9000 lesen. Das Lesen der Vereinbarung ist sehr langweilig und erfordert ein gewisses Maß an Geduld. Wenn Ihr Englisch nicht sehr gut ist, können Sie es mit Google Translate ins Chinesische übersetzen und schnell durchblättern (ausgiebiges Lesen). Die erste Lektüre dient hauptsächlich dem Verständnis der Hauptkonzepte und Hauptprozesse.

Danach können wir ein Programm mit dem QUIC-Protokoll schreiben und die Pakete dann über Wireshark erfassen. Indem wir die tatsächlichen Nachrichten untersuchen und sie mit dem Inhalt des RFC-Protokolls vergleichen (intensives Lesen), können wir ein tieferes Verständnis davon erlangen die Essenz des Protokolls.

Wir werden den Echo-Client und -Server basierend auf dem Code im vorherigen Artikel erstellen. Damit es für alle leichter lesbar ist, habe ich auch den Code gepostet. Interessierte Studenten können mein Repo klonen und den Client/Server-Code ausführen.

Client-Code (siehe github: tyrchen/rust-training/live_coding/quic-test/examples/client.rs):

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Server-Code (siehe github: tyrchen/rust-training/live_coding /quic -test/examples/server.rs):

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Diese beiden Codeteile bilden den einfachsten Echo-Server. Wir können Wireshark verwenden, um UDP-Pakete unter der lokalen Loopback-Schnittstelle zu überwachen und Pakete zu erfassen. Es ist zu beachten, dass bei Datenverkehr, der das TLS-Protokoll wie QUIC verwendet, selbst wenn die Pakete erfasst werden, möglicherweise nur die ersten paar Pakete lesbar sind und nachfolgende Pakete verschlüsselt sind und nicht gelesen werden können. Wenn wir einen Client/Server erstellen, müssen wir daher einen Weg finden, den zwischen dem Server und dem Client ausgehandelten Sitzungsschlüssel zu erfassen, damit wireshark ihn entschlüsseln kann. Im Allgemeinen stellen SSL/TLS-Bibliotheken diese Funktion bereit. Für Rustls können wir beispielsweise key_log in der TLS-Konfiguration verwenden. Wenn Sie sich den Servercode oben genau ansehen, sehen Sie diesen Satz:

let config = Builder::new()
    .with_certificate(CERT_PEM, KEY_PEM)?
    .with_key_logging()? # 使能 keylogging
    .build()?;
Nach dem Login kopieren

Nach der Verwendung von key_log müssen wir beim Starten des Servers nur SSLKEYLOGFILE angeben:

SSLKEYLOGFILE=session.log cargo run --example server
Nach dem Login kopieren

Nachdem die Paketerfassung abgeschlossen ist, öffnen Sie die Wireshark-Einstellung und wählen Sie aus das TLS-Protokoll und geben Sie den Protokollpfad ein:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Das Folgende ist eine vollständige Paketerfassung der Interaktion zwischen dem Client und dem Server. Wir sehen, dass alle „geschützten Nutzlasten“ normal angezeigt werden

Da unser Echo-Client nur die einfachste Aktion ausführt (nur einen bidirektionalen Stream öffnet), können wir uns durch diese Paketerfassung auf die Untersuchung des Prozesses des Verbindungsaufbaus über das QUIC-Protokoll konzentrieren.

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Das erste vom Client gesendete Paket

Schauen wir uns die erste vom Client gesendete Nachricht an:

Diese Nachricht enthält sehr umfangreiche Informationen. Erstens ist das erste Paket von QUIC im Gegensatz zum TCP-Handshake sehr groß, bis zu 1200 Bytes (das Protokoll erfordert UDP-Nutzdaten von mindestens 1200 Bytes), einschließlich des QUIC-Headers, eines 255-Byte-CRYPTO-Frames und 890-Byte. Byte-PADDING-Frame. Wie Sie der Kopfzeile entnehmen können, ist der Typ dieses QUIC-Pakets „Initial“.

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

QUIC-Nachrichtentyp

Bei QUIC-Paketen ist der Header Klartext und alle nachfolgenden Frame-Nutzlasten sind Chiffretext (mit Ausnahme der ersten paar Pakete). Wir sehen, dass dieses erste Paket eine Long-Header-Nachricht ist. In Abschnitt 17.2 von RFC9000 ist Long-Header-Paket wie folgt definiert:

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 (..),
 }
Nach dem Login kopieren
Wenn Sie interessiert sind, können Sie das entsprechende Kapitel von RFC selbst lesen. Für Nachrichten mit langem Header gibt es die folgenden Typen:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

既然有 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..),
}
Nach dem Login kopieren

为什么需要 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:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

可以看到,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:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

服务器的回包

我们来看 server 的回包:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

这里有一些新东西。首先,一个 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 报文中:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

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

客户端结束 Handshake

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

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

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

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

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

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

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Wie Sie sehen können, ist die QUIC-Nachricht hier ein Short-Header-Paket. Zusätzlich zum ACK-Frame enthält sie auch einen STREAM-Frame. Die niedrigsten beiden Ziffern der Stream-ID dieses Streams sind 00, was bedeutet, dass es sich um einen vom Client initiierten, bidirektionalen Stream handelt. Da zwei Bits verwendet werden, um den Typ auszudrücken, hat der Stream von QUIC die folgenden Typen:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Schauen wir uns die Länge (6) und die Daten (68 65 6c 6c 6f 0a) des STREAM-Frames an. Wenn der Inhalt in Daten in ASCII ausgedrückt wird, ist er genau „hello“ und seine Länge beträgt 6 Bytes.

Der Server antwortet mit dem „Hallo“-Text

Schließlich gibt das Server-Echo zurück:

Sehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt

Das ist genau das Gleiche wie die obige Nachricht, daher werde ich es nicht erklären.

Sage Moment

Ich glaube, dass die obige Einführung in QUIC basierend auf der Wireshark-Paketerfassung Ihnen ein vorläufiges Verständnis des QUIC-Protokolls vermitteln kann. Im letzten Artikel haben wir gesagt, dass QUIC Multiplexing unterstützt und das Problem der Head-of-Queue-Blockierung auf der Transportschicht löst. Können Sie in der Einleitung dieses Artikels die folgenden zwei Fragen beantworten?

  • Welchen Frame-Typ verwendet QUIC zum Multiplexen?

  • QUIC Wie löst man die Head-of-Queue-Blockierung auf der Transportschicht?

Verwandte Empfehlungen: Webserver-Sicherheit

Das obige ist der detaillierte Inhalt vonSehen wir uns an, wie man Netzwerkprotokolle mithilfe des QUIC-Protokolls lernt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:微信公众号-程序人生
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!