HTTP/3入門

第4章実践HTTP/3 ~ 実装を触り、通信を観測し、理解を深める

プロトコルやクライアントとサーバの動作を理解するには、実際に動かすことが大事です。そこで本章では、実際にHTTP/3に触ってみます。ブラウザやCurl、Wiresharkなどを使ってHTTP/3通信を確認する方法と、nginxを使ってHTTP/3サーバを構築する方法を紹介します。

なお、本章で紹介する以外にも、さまざまなQUICやHTTP/3の実装が公開されています。QUIC Implementationsに一覧がまとまっています。

Chromeによる確認

Chrome、Firefox、Safariでは、特別な設定をせずともHTTP/3通信が行われます。本節では、Chromeの最新版(執筆時点では91.0.4472.77)を用いてHTTP/3通信を確認します。

ChromeのデベロッパーツールのNetworkペインでは、そのタブで行われた通信を確認できます。このペインを開いた状態でhttps://www.google.com/にアクセスすると、ブラウザが送信したリクエストの一覧が表示されます図1⁠。

図1 ChromeデベロッパーツールのNetworkペイン
画像

Protocolのカラムで、使用したプロトコルを確認できます。図1では、HTTP/3の草案29版の実装を示すh3-29と表示されています。正式なHTTP/3では、h3と表示されるでしょう。

Curlによる確認

CLICommand Line InterfaceからHTTP/3通信を行うツールもあります。本節では、HTTP/3に対応しているCurl(執筆時点ではバージョン7.77.0)を試します。

GitHubのCurlのリポジトリのページに、HTTP/3を有効にしたビルド方法についての解説があります。Tatsuhiro Tsujikawaさんが開発しているngtcp2を用いる方法と、Cloudflareが開発しているquicheを用いる方法があります。今回は、手順の短いquiche(執筆時点ではリビジョン56edda7を使用した流れを紹介します。暗号ライブラリであるBoringSSL(執筆時点ではリビジョン47cefedも利用します。

BoringSSLのビルド
# 次の行はRustのインストール
$ curl https://sh.rustup.rs -sSf|sh
$ git clone https://github.com/cloudflare/quiche \
  --recursive
$ cd quiche
$ cargo build --release \
  --features ffi,pkg-config-meta,qlog
$ mkdir deps/boringssl/src/lib
$ ln -vnf $(find target/release \
  -name libcrypto.a -o -name libssl.a)\
  deps/boringssl/src/lib/

// Curlのビルド
$ cd ..
$ git clone https://github.com/curl/curl
$ cd curl
$ ./buildconf
$ ./configure \
  LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" \
  --with-ssl=$PWD/../quiche/deps/boringssl/src \
  --with-quiche=$PWD/../quiche/target/release
$ make

// HTTP/3通信
$ ./src/curl https://google.com --http3 -v
(省略)
* h3 [:method: GET]
* h3 [:path: /]
* h3 [:scheme: https]
* h3 [:authority: google.com]
* h3 [user-agent: curl/7.76.1-DEV]
* h3 [accept: */*]
* Using HTTP/3 Stream ID: 0 (easy handle 0x5570514cf2f0)
> GET / HTTP/3
> Host: google.com
> user-agent: curl/7.76.1-DEV
> accept: */*
 (省略)

補足情報

Curlのビルド手順が更新されています。2022年6月現在の手順は次のとおりになります。

$ curl https://sh.rustup.rs -sSf|sh
$ git clone https://github.com/cloudflare/quiche \
 --recursive
$ cd quiche
$ cargo build --release \
 --features ffi,pkg-config-meta,qlog
$ mkdir deps/boringssl/src/lib
$ ln -vnf $(find target/release \
 -name libcrypto.a -o -name libssl.a)\
 deps/boringssl/src/lib/

$ cd ..
$ git clone https://github.com/curl/curl
$ cd curl
$ ./buildconf
$ ./configure \
 LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" \
 --with-ssl=$PWD/../quiche/deps/boringssl/src \
 --with-quiche=$PWD/../quiche/target/release
$ make

なお、Curlのビルドの最新手順は公式であるHTTP3 (and QUIC)を参照してください。

Wiresharkによる確認

マシンで行われている通信のパケットをキャプチャし、パケットの中身をプロトコルにあわせて人間が読める形で表示してくれるWiresharkというツールがあります。Wiresharkを使うと、QUICやHTTP/3のストリームやフレームの情報も確認できます。

Wiresharkは、公式サイトからダウンロードしてインストールしてください。執筆時点のバージョンは3.4.5です。

復号の準備

HTTP/3が下位層で使用するQUICは通信を暗号化するので、Wiresharkで復号する必要があります。そのためには、通信を行うアプリケーションから復号用の鍵を取り出す必要があります。なお、QUICが用いるTLS 1.3では短期利用の鍵ephemeral keyを用いるので、いわゆるサーバ証明書と紐付く秘密鍵では復号できません。

ここでは、Chromeから復号用の鍵を取り出します。そのためには、OSの環境変数にSSLKEYLOGFILEを設定します。変数値はファイルの出力先パスです。Windowsの場合は、⁠コントロールパネル」「システムとセキュリティ」「システム」「システムの詳細設定」「環境変数」と進んで設定します図2⁠。macOSの場合は、次のようにターミナルから環境変数を付けてChromeを起動してください。

Macにおける環境変数を設定したChromeの起動
$ SSLKEYLOGFILE=~/Desktop/sslkey.log "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
図2 Windowsの環境変数の設定
画像

続けて、Wiresharkの設定です。⁠編集」「設定」と進み、TLSの「(Pre)-Master-Secret log filename」SSLKEYLOGFILEで設定したファイルを指定します図3⁠。

図3 Wiresharkの設定
画像

パケットキャプチャ

ここまで設定できたら、Wiresharkでパケットキャプチャを開始し、Chromeでhttps://www.google.com/にアクセスしてください。図4のように、HTTP/3通信の中身がWiresharkに表示されます。

図4 WiresharkによるHTTP/3通信の確認
画像

図4では、QUICパケットが暗号化されていることを示すProteceted Payloadと表示されています。パケット番号(PKN)が5のパケットを例にパケットの中身を説明すると、ストリームIDが3のQUICストリームでQUICのSTREAMフレームが送信されています。そのSTREAMフレームには、HTTP/3のSETTINGSフレームが格納されています。

図4上でパケットを選択することで、パケットの詳細を確認することもできます。

qvisによるQUIC通信の可視化

本節では、qlogをわかりやすく表示するツールであるqvisを紹介します。

qlogは、QUIC用のログ形式です。Main logging schema for qlogとして、IETFで標準化が検討されています。qlogでは、パケットだけでなく、通信内容やエンドポイントの状況が記録されます。

qlogで記録するには、アプリケーションがqlogに対応している必要があります。先述したCurl、quicheなどが対応しています。今回はCurlを使用します。

Curl通信の可視化

Curlでqlogを出力する場合、環境変数にQLOGDIRを設定します。

QLOGファイルの出力
$ QLOGDIR=./ ./src/curl  https://localhost --http3
(省略)
$ ls ./*.qlog
./01e6104c677b671c3d32f6a07c7080742e92ed89.qlog

これで、指定したディレクトリに~.qlogというファイルが出力されます。このファイルをqvisで可視化します。

qvisは作者のWebサイト上でも使用できます。

https://qvis.quictools.infoにアクセスし、qlogファイルをアップロードすると、図5のようにQUIC通信の様子を確認できます。

図5 qvisによるQUIC通信の確認
画像

図5の上2つの矢印を例に見方を説明します。まず、クライアントから、QUICのCRYPTOフレームをパケット番号0のInitialパケットで送信しています。次に、サーバから、QUICのCRYPTOフレームとACKフレームをパケット番号0のInitialパケットで返しています。

表示されている項目をクリックすると、QUICパケットの詳細や、クライアントやサーバで発生したイベントを確認できます。図6は、図5でクライアントが最初に送信しているInitialパケットの詳細を表示したものです。

図6 qvisの詳細イベント表示
画像

通信内容をアップロードしたくない場合は、GitHubからqvisをダウンロードしてインストールしてください。

nginxサーバの構築

HTTP/3サーバの実装はいくつかありますが、本節ではnginxでHTTP/3サーバを動かしてみます。

なお、nginxのHTTP/3実装は実験段階であるため、今後変わる可能性があります。ビルドおよび設定の最新情報は、nginxのページを参照してください。

ビルド

nginx(執筆時点ではリビジョンe6c26cb4d38bを自前でビルドします。ここでは、Ubuntu 20.04を使用した手順を紹介します。

boringsslのビルド
# 必要なパッケージのインストール
$ sudo apt install mercurial ninja-build \
  libpcre3 libpcre3-dev
$ git clone https://boringssl.googlesource.com/boringssl
$ cd ./boring/
$ mkdir build
$ cd build
$ cmake -GNinja ..
$ ninja
$ cd ../../

// nginxのビルド
$ hg clone -b quic https://hg.nginx.org/nginx-quic
$ cd nginx-quic
$ ./auto/configure \
  --with-debug --with-http_v3_module \
  --with-cc-opt="-I../boringssl/include" \
  --with-ld-opt="-L../boringssl/build/ssl \
  -L../boringssl/build/crypto" \
  --prefix=./
$ make

設定

nginxでHTTP/3を有効にするために、サーバ証明書を作成し、./conf/nginx.confに設定を追記します。

証明書の作成
$ openssl genrsa 2048 > ./conf/server.key
$ openssl req -new -key ./conf/server.key \
  > ./conf/server.csr
$ openssl x509 -days 30 -req -signkey \
  ./conf/server.key < ./conf/server.csr \
  > ./conf/server.crt
./conf/nginx.conf
http {
(省略)
# httpディレクティブ内に以下を追記
    server {
        listen 443 http3 reuseport;
        listen 443 ssl;

        ssl_certificate server.crt;
        ssl_certificate_key server.key;
        ssl_protocols TLSv1.3;

        location / {
            add_header Alt-Svc 'h3=":443"; ma=60, h3-29=":443"; ma=60, ';
        }
    }
# ここまで追記
}

なお、ここで準備した証明書は、公的な認証局に署名してもらったものではないため、ブラウザで閲覧すると警告が出ます。実際に使う際は、正規の証明書を使用してください。

動作確認

nginx-quicディレクトリに移動し、nginxを起動します。

nginxの起動
$ sudo ./objs/nginx -c ./conf/nginx.conf

HTTP/3に対応したCurlを使うと、ちゃんとアクセスできます。

Curlを使用したアクセス確認
$ ./src/curl https://localhost --http3 -v
*   Trying 127.0.0.1:443...
* Connect socket 5 over QUIC to 127.0.0.1:443
* Sent QUIC client Initial, ALPN: h3-29,h3-28,h3-27
* Connected to localhost () port 443 (#0)
* h3 [:method: GET]
* h3 [:path: /]
* h3 [:scheme: https]
* h3 [:authority: localhost]
* h3 [user-agent: curl/7.76.1-DEV]
* h3 [accept: */*]
* Using HTTP/3 Stream ID: 0 (easy handle 0x559e232a62f0)
> GET / HTTP/3
> Host: localhost
> user-agent: curl/7.76.1-DEV
> accept: */*
>
< HTTP/3 404
< server: nginx/1.19.9
< date: Sun, 11 Apr 2021 17:29:12 GMT
< content-type: text/html
< content-length: 153

まとめ

本章では、ブラウザやサーバで実際にHTTP/3通信を確認しました。また、HTTP/3サーバの構築も行いました。

おすすめ記事

記事・ニュース一覧