HTTPS DNS レコードのalpn情報からHTTP/3に繋げに行くchromiumのUseDnsHttpsSvcbAlpn feature

TLDR;

chrome://flags#use-dns-https-svcb-alpnから有効化できるUseDnsHttpsSvcbAlpn機能を紹介します。

この機能を有効にすると、HTTP/3 をサポートすることを示す HTTPS DNS レコードを受信した場合、Chrome は HTTP/3 プロトコルを使用してサーバーに接続します。

chrome 105 からこのコミットが反映されるっぽい。

 

いろいろ間違っていたらすいません。

DNS HTTPSレコード

DNS HTTPS Records を用いたHTTP/3 接続

あるサイトにはじめて接続する場合、HTTP/3 (QUIC) で動作するのかどうか知らないためHTTP/2 で接続してからAlt-SvcヘッダによってAlternate ServiceとしてHTTP/3の存在を教えてもらってから、次のリクエストからHTTP/3につなげに行く。

従来は一度 HTTP/2 で接続してからAlt-SvcヘッダによってAlternate ServiceとしてHTTP/3の存在を教えてもらってからHTTP/3につなげに行く。これはいきなり HTTP/3 でリクエストしても QUICに対応しているかわからないため、このような仕様になっている。*1 

 

もし最初のリクエストから HTTP/3 で接続させたければ、リクエストよりも先に HTTP/3 がサポートされている旨を知る必要があります。ここで活躍するのが DNSDNS HTTPS Recordsです。

draftはdraft-ietf-dnsop-svcb-https

datatracker.ietf.org

DNS HTTPSレコード

DNS HTTPSレコードはいくつかの利点があります。勝手に重要だと思ったものを挙げると

  • 平⽂ HTTP による接続を防⽌ (http: → https:) 
  • はじめから HTTP/3 (QUIC) による接続を可能に (alpn) 
  • ECH (Encrypted Client Hello) の公開鍵等の取得 (ech)

今回は上記のうち二つ目の利点、はじめから HTTP/3 (QUIC) による接続を可能に (alpn) というところを用いています。

 

自分の理解が追いついていないのでいつかちゃんとdraftを読んでブログを書きたいです。

参考になりそうな yuki さんのブログ。

asnokaze.hatenablog.com

自分のサイトを対応させたJxckさんの話

自分のサーバをHTTP3 対応し、Alt-Svc ヘッダおよび DNS HTTPS Resource Record によってそれをアドバタイズするJxckさんの話。

blog.jxck.io

## HTTPS Resource Record の章から HTTP/3 に最初っからつなげに行くように設定した話があります。勉強になりました。

 

他のブラウザの状況

Safari (iOSmacOS) は対応済みでとくに何もしなくても使えるらしいです。

Firefox実装済みだが、Firefox の設定画面から DoH を有効にする必要があるらしいです。

(自分で試してないのでよくわかりません)

 

chromium の UseDnsHttpsSvcbAlpn feature

chromium DNS HTTPS Records

もともとDNS HTTPS Recordsについては以下のDesign Doc を見ることができます。(オープンになってるdocumentよめるchromiumすごい!)

docs.google.com

今回該当する話が書かれているのはそのうちのProtocol upgradeの箇所

 

Curret Status

Intent to Ship: HTTP->HTTPS redirect for HTTPS DNS records

ericorth@chromium.orgさんの昨日(8/5)のnet-devメーリスへのメール

Current status: We are partway through a gradual rollout of the feature, to be complete in approximately one month.  So Chrome will currently request HTTPS records and perform scheme upgrades accordingly for some but not all users.

commit: Support HTTP/3 protocol upgrade for HTTPS DNS records

commit: 

https://chromium.googlesource.com/chromium/src.git/+/d81149603836e06f5a3aa0ba048eb376f81fa92c

 

コミット文より

Support HTTP/3 protocol upgrade for HTTPS DNS records

This CL introduces UseDnsHttpsSvcbAlpn feature which can be enabled at chrome://flags#use-dns-https-svcb-alpn. When this feature is enabled, Chrome will connect to the server using the HTTP/3 protocol if Chrome receives a HTTPS DNS record indicating HTTP/3 support.

This CL changes the behavior of HttpStreamFactory::JobController as follows:

Currently, if Chrome has received an Alt-Svc header from the origin, JobController creates two Jobs to compete for connection establishment. [1] Main job for HTTP/1 or HTTP/2 [2] Alternative job for HTTP/3 (Note: This job can use HTTP/2 when the enable_http2_alternative_service parameter is enabled. But this parameter is not enabled in Chrome.) The main job waits for a while before starting the race if Chrome knows that QUIC works on the current network. The waiting time is determined based on recent QUIC connection performance in QuicStreamFactory::GetTimeDelayForWaitingJob().

This CL introduces a new Job. [3] DNS alpn job: This job tries to use HTTP/3 noly if Chrome receives a HTTPS DNS record indicating HTTP/3 support. Otherwise it fails with ERR_DNS_NO_MACHING_SUPPORTED_ALPN. This DNS alpn job is created only when the new UseDnsHttpsAlpn feature is enabled, and the URL scheme is HTTPS, and QUIC is enabled, and proxy is not used, and the alternative job can’t use an existing Quic session, and Chrome has not recognised that the QUIC connection to the server is broken. If the DNS alpn job can use an existing QUIC session, other jobs are canceled. Additionally, if the destination of both the alternate job and the DNS alpn job are the same, the DNS alpn job is canceled to avoid redundant jobs. The main job waits for a while before starting, just like its current behavior.

いままでchromeには

  1. HTTP/1 か HTTP/2 で繋げに行くメインジョブ
  2. 既存のQuicセッションがある場合に繋ぎに行くHTTP/3ジョブ

の二つが競争をしていました。

今回の変更により

が追加されました。DNS alpn job は HTTPS レコード情報よりHTTP/3が使用可能であることを知っているので初めからQUICで繋ぎにいきます。

  1. HTTP/1 か HTTP/2 で繋げに行くメインジョブ
  2. 既存のQuicセッションがある場合に繋ぎに行くHTTP/3ジョブ
  3. DNS alpn job

の三つのjobが存在しますが、実際に繋ぎに行くときは以下のようになるかと思います。

 

1. 初めてのサイトでHTTP/3 へ繋げられることをHTTPSレコードによって広告していない場合

  • HTTP/1 か HTTP/2 で繋げに行くメインジョブ のみ

 

2. 初めてのサイトでHTTP/3 へ繋げられることをHTTPSレコードから得られる場合

  • HTTP/1 か HTTP/2 で繋げに行くメインジョブ
  • DNS alpn job

の2つのジョブが競争。

 

3. 以前QUICで繋ぎに行ったサイトに繋ぎに行くとき

  • HTTP/1 か HTTP/2 で繋げに行くメインジョブ
  • 既存のQuicセッションがある場合に繋ぎに行くHTTP/3ジョブ

の2つのジョブが競争。(DNS alpn jobは余分なjobを減らすためキャンセルされる)

 

2. 3. 二つの場合において、HTTP/1 か HTTP/2 で繋げに行くメインジョブ はHTTP/3 を優先させるために少し待ちます。この待ち時間はQuicStreamFactory::GetTimeDelayForWaitingJob() から得られる直近のQUICコネクションパフォーマンスによって決められます。

 

せっかくなので3つのジョブが作られる場所のコードを見てみましょう。

この3つのジョブは chromium の net/http/http_stream_factory_job_controller.cc というファイルの HttpStreamFactory::JobController::DoCreateJobs() という関数内でそれぞれ作られています。

https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_stream_factory_job_controller.cc;l=793

  • main_job_ = job_factory_->CreateJob(
  • alternative_job_ = job_factory_->CreateJob(
  • dns_alpn_h3_job_ = job_factory_->CreateJob(

と書いてある部分でjobが作成されているのが確認できます。

commit: Support HTTPS records aliased by CNAME records

上記のcommitのみでは CNAME レコードによってaliaseされたHTTPSレコードには対応できていなかったので対応させたというコミット。(まだきちんと理解できていないのでまた読み直したい)

コミット文

Support HTTPS records aliased by CNAME records

Currently Chrome can't use the alpn information of HTTPS records which
are aliased by CNAME records. This is because ExtractHttpsResults() is
ignoring the aliased HTTPS records.

To support such case, this CL do the followings:
  1. Change ExtractHttpsResults() to allow the HTTPS record which
     service name is the canonical name of the record.
  2. Introduce ConnectionEndpointMetadata.target_name which keeps the
     target of the metadata.
  3. Introduce HostCache.Entry.canonical_names which keeps the canonical
     names of A/AAAA records.
  4. Change HostCache::Entry::GetEndpoints() to return the metadata only
     when A and AAAA records are at the same canonical name and that
     matches the metadata target name.

 

UseDnsHttpsSvcbAlpn featureをchromeで使うためには

バージョン105以のchromiumが必要です。

chrome canary から手に入れれます。

(か、いつも使ってる Google Chrome が 105になるまで待つ。今現在は104で105は8月 30日にリリースされるらしいですね)

 

chrome://flags/ に行く。

(直接このフラグを変える場合は chrome://flags/#use-dns-https-svcb-alpn )

Version 105.0.5164.0 (Developer Build) よりスクショ

DefaultをEnabledに変える。

 

 

*1:Happy Eyeballsアルゴリズムによって最初っからつなげに行くことについて議論してる論文もある Network | Free Full-Text | Implementation and Evaluation of HTTP/3 Connectivity Check Using Happy Eyeballs Algorithm