HTTP/3のCONNECT-UDPを利用したWebRTC通信

Proxying Listener UDP in HTTP」という提案仕様がIETFに提出されている。

これは、HTTP/3のCONNECT-UDPを介してWebRTC通信を可能にするための提案である。まだ議論の呼び水と鳴るdraftであるため、ここから仕様は大きく変わると思うが、ざっと眺めていく。

HTTP/3のCONNECT-UDP

本論に入る前に、まずCONNECT-UDPについて説明します。

IETFではすでに「Proxying UDP in HTTP」という仕様が議論されている。これが通称CONNECT-UDPと呼ばれているものである。実は、AppleのPrivate Relayでもすでに使用されているものである。

これは、Proxyと確立したHTTP/3コネクションをトンネリングしてUDPパケットを中継させる機能です。

この通信は第三者からはただのHTTP/3通信としてか観測できないという特徴があります。確立した通信路を通して自由なUDPパケットを中継させることが出来ます。

このCONNECT-UDPでは、H3-Datagramという仕様でUDPパケットを扱います。詳しくは以前書いた記事を参照ください。
asnokaze.hatenablog.com

Proxying Listener UDP in HTTP

通常のCONNECT-UDPではProxyを中継して通信する相手は1つでしたが、WebRTCはSTUNと通信した上で、通信相手のブラウザからもパケットを受け付ける必要があります。そこで、既存のCONNECT-UDP拡張機能として「Proxying Listener UDP in HTTP」が登場しました。

(提案者はユースケースとしてWebRTCをあげていますが、それに限定されるものでは有りません)

主な通信の流れ

上記の図に沿って通信の流れを説明します。

CONNECTリクエストとレスポンス

まずは、ブラウザAと中継サーバとでHTTP/3のコネクションを確立したのち、中継の要望を出す。

通常のCONNECT-UDPのように、拡張CONNECTメソッドを用いる(:protocolにconnect-udpが指定される)。

connect-udp-listenヘッダを付けることで、Proxying Listener UDP in HTTP の通信であることを明示する。ヘッダの値は使用するH3-DatagramのContext-IDを指定する。

HEADERS
  :method = CONNECT
  :protocol = connect-udp
  :scheme = https
  :path = /.well-known/masque/udp/*/*/
  :authority = proxy.example.org
  connect-udp-listen = 2
  capsule-protocol = ?1
|<<

中継サーバは、200番のレスポンスを返し、CONNECTリクエストの受け入れる意志を示す。

>||
HEADERS
  :status = 200
  capsule-protocol = ?1
STUNサーバへのUDPパケットの中継

ブラウザA側は、H3-DatagramUDPパケットを中継サーバに送信する。このとき、中継先となるターゲットのIPとポートを付加して送る。

 DATAGRAM
   Quarter Stream ID = 11
   Context ID = 2
   IP Version = 4
   IP Address = 192.0.2.42
   UDP Port = 1234
   UDP Payload = Encapsulated UDP Payload

中継サーバは、指定されたIP宛にUDPパケットを中継する。

中継サーバはSTUNサーバから応答となるUDPパケットを受け取ると、ブラウザA側に中継する。このときもH3-DatagramでUDPパケットを中継することになる。

このときのH3-Datagramでは、どこからきたUDPパケットなのかが付加されている。

DATAGRAM
  Quarter Stream ID = 11
  Context ID = 2
  IP Version = 4
  IP Address = 192.0.2.42
  UDP Port = 1234
  UDP Payload = Encapsulated UDP Payload

ブラウザBからのUDPパケットの中継

STUNとのやり取りが終わって、ブラウザAとブラウザBがやりとりを開始します。ブラウザBから送られるUDPパケットも、中継サーバがブラウザAに中継を行います。このときもH3-DatagramでUDPパケットを中継することになる。

DATAGRAM
  Quarter Stream ID = 11
  Context ID = 2
  IP Version = 4
  IP Address = 203.0.113.33
  UDP Port = 4321
  UDP Payload = Encapsulated UDP Payload

一般ユーザに払い出すと危険なサブドメインやメールアドレス

ユーザに対して、そのユーザ名のサブドメインやメールアドレスを払い出すWebサービスがあります。

しかし、特定のサブドメインやメールアドレスは特別な用途で使われているものもあります。そのようなサブドメインやメールアドレスを一般ユーザに払い出してしまうと危険です。

現在、IETFでは仕様上利用用途が決められている、それらのラベルをとりまとめる「Dangerous Labels in DNS and E-mail」というdraftが提出されています。

今回はそれを眺めていきます。

(あくまでIETFの取り組みであり、仕様上定義されているものをとりまとめています。クラウドサービスや特定ベンダーで特別利用しているものは現在含まれていません。)

サブドメイン

ここでとりあげるサブドメインは、利用用途が決まってるため一般ユーザに払い出すべきではありません。(例: mta-sts.example.com)

(なお、_example のように、アンダースコアで始まるものはRFC 8552ですでにまとめられています。ここでは紹介はしません。)

  • mta-sts: RFC8461で定義される、SMTP MTA Strict Transport Securityポリシーファイルの設置に利用
  • openpgpkey: 「OpenPGP Web Key Directory」でOpenPGP certificateの参照と検証に利用
  • root-key-sentinel-is-ta-(key-tag): RFC8509で、信頼するDNSSECルートキーを示すのに利用
  • root-key-sentinel-not-ta-(key-tag): RFC8509で、信頼しないDNSSECルートキーを示すのに利用
  • www: ブラウザがWebサイトが動作していると想定して利用する

メールアドレス

ここでとりあげる文字列は、利用用途が決まってるため、メールアドレスのローカルパートとして一般ユーザに払い出すべきではありません。(例: webmaster@example.com)
(なお、大文字小文字は区別しません)

  • abuse: RFC2142で、不正利用時の連絡先として指定
  • administrator: 証明書の発行用途で利用 (CA/B Forum)
  • admin: 証明書の発行用途で利用 (CA/B Forum)
  • hostmaster: RFC2142及び、証明書の発行用途で利用 (CA/B Forum)
  • info: 証明書の発行用途で利用 (参考)
  • is: 証明書の発行用途で利用 (参考)
  • it: 証明書の発行用途で利用 (参考)
  • noc: RFC2142で、ネットワークに関する連絡先として指定
  • postmaster: RFC2142及び、証明書の発行用途で利用 (CA/B Forum)
  • root: システムの問い合わせや、証明書の発行に利用?
  • security: RFC2142で、セキュリティ関係の連絡先として指定
  • ssladministrator: 証明書の発行用途で利用(参考)
  • ssladmin: 証明書の発行用途で利用 (参考)
  • sslwebmaster: 証明書の発行用途で利用(参考)
  • sysadmin: 証明書の発行用途で利用(参考)
  • webmaster: Web関連の問い合わせ先及び、証明書の発行用途で利用 (CA/B Forum)
  • www: webmasterのエイリアスとして使用

CA Browser ForumのBaseline Requirementsは、証明書発行に関するガイドラインです。CAやクラウドサービスでも、メールアドレスベースの検証ではこれらに準拠しており、これらのメールアドレスを検証に用いてますね。

おわり

もちろん今回は仕様で利用用途が定義されているものにフォーカスしています。

他にも危険なものとかありそうだけど、まとまってるのかな?

デフォルトでCookieをオリジンに紐づける、ChromeのOrigin-Bound Cookies

Blinkの開発者メーリングリストで「Intent to Prototype: Origin-Bound Cookies」という議論が行われています。

Cookieをより安全にするために、デフォルトでCookieをオリジンに紐づけるようにする提案です。Cookieをset-cookieしたオリジン以外からは、そのCookieにアクセスできないようになります。

詳しい背景や仕組みについては次のページから確認できます。
github.com

かんたんに、Origin-Bound Cookiesの動作をみていきましょう。

オリジンは、スキーム、ホスト名、ポートの組です。それらのうち一つでも異なれば、オリジンが異なることになります。

例えば、次のようになります。

オプトアウト

議論されているOrigin-Bound Cookiesでは、デフォルトの動作を変更します。オリジンを超えてcookieを共有するために、オプトアウトする仕組みが提供されています。

domain属性を付与することで、オプトアウトできます。オプトアウトすることで、異なるホスト名、ポートとcookieを共有することが出来ます。ただし、異なるスキームに共有することは出来ません。

例えば、https://example.comからセットされたcookieでも「Domain=example.com」が設定されていてれば、https://example.com:1234https://sub.example.comにはcookieが送信されます。ただし、スキームが異なるhttp://example.comには共有されません。

Webサイトのバグの報告先を示す contributing.txt

Webサイトのバグを見つけたとしても、その報告先を知る統一的な方法は現状ありません。

たとえば、脆弱性についてはsecurity.txt があります。https://www.facebook.com/security.txt などで使われています。
asnokaze.hatenablog.com

同様の仕組みで、contributing.txt という形式でバグの報告先を示せるようにする仕組みが提案されています。提案仕様は「a simple way to provide informations for contributors」としてIETFに提出されています。

contributing.txtをWebページの最上位階層に配置します (例: https://example.com/contributing.txt )

そのファイルは次の情報を含めることが出来ます。

Admin: Valentin Binotto
Bugs: bugs@vauly.net
Open Source: github.com/valentinbino
License: Creative Commons Attribution 4.0 Int. Public License
Guidelines: github.com/valentinbinotto/v434/guidelines.txt
# Valentin Binotto
# Hello, world!
  • Admin: Webサイトの管理者
  • Bugs: バグレポートを出せるメールアドレスまたはURL
  • Open Source: GithubやGitlabなどより議論するのに適切なURL
  • License: ウェブサイトのコンテンツに適応されるライセンス
  • Guidelines: このWebサイトにコントリビューションするためのガイドラインのURL
  • #~~ : コメント

ChromeのCache Transparencyに関するメモ

Chromeではキャッシュの効率改善を目的とした「Cache Transparency」という仕組みが検討されているようです。

これは、「Double-keyed HTTP cache」によってキャッシュヒット率低下を緩和します

まだまだ実験を行っている段階ですが、簡単にメモとして残しておく

背景: Double-keyed HTTP cache

Double-keyed HTTP cacheは、ユーザのプライバシーを保護するために、HTTPのキャッシュをサイトごとに分離する仕組みです。

簡単な例で見ていきましょう

この時、https://cdn.exampleから読み込んだリソースをキャッシュするわけでが、同一のリソースであったとしてもa.example用とb.example用でキャッシュ領域を分けます。

こうしておかないと、a.example側はアクセスしたユーザがb.exampleにすでにアクセスしたことがあるのか、リソースの読み込み速度から類推することができしていまいます。

この時、キャッシュのキーが 『読み込んだサイト(URLバーに表示されてるURL)』+『読み込んだリソースのURL』と2つのキーになることからDouble-keyed HTTP cacheと呼ばれています。

Chromeの分析では、Double-keyed HTTP cacheによりキャッシュのヒットミスが3%増えたという分析がなされています。

Cache Transparency

Cache Transparencyは、Blink-devメーリングリストの下記のスレッドで議論されています
groups.google.com

主な目的は、Double-keyed HTTP cache導入によって上がったキャッシュのヒットミス率の低減があげられています。

その方法としては、一般に広く利用されているリソースであれば、Single-Keyキャッシュで扱ってもユーザのプライバシーには影響しないという仮説に基づいています。

"一般に広く利用されているリソース" は、Google独自の方法(Chromeのテレメトリ, クローラー)で調査され、Pervasive Payloads listとしてリスト化されます。Pervasive Payloads listには、リソースのURLとペイロードハッシュ値が含まれ、それに一致するリソースはSingle-Keyキャッシュとして保存されます。

まだ事前の効果測定を行う段階で、実験として以下の条件を満たすリソースを対象にすることが議論されていますが。まだFixはしてなさそうです。

  • 少なくとも500のサイトに含まれる
  • 月に少なくとも1,000万回フェッチされたもの

終わりに

Double-keyed HTTP cacheによる、キャッシュミスヒット率の緩和策として出てきたCache Transparency。

まだまだ話が始まったところなのでどうなるかはわからないが、Webサイトのデベロッパーとしては、JSやCSSは共通のCDNをURLからダウンロードしたほうがお得になるかもしれない...

どうなるんだろう

NICからの割り込みを適切なCPUに振り分けるための、IPヘッダオプション

NICからの割り込みを適切なCPUに振り分けられるようなHintをIPヘッダオプションとして定義する「Multiple Core Performance Hint Option」という提案が提出されています。(特許としても申請中とのこと)

ざっくり眺めて見ようかと思います。ここらへん詳しいわけではないので、間違いがあればご指摘ください。

背景

10Gbpsなどのトラフィックを処理する場合、NICからの割り込みを一つのCPUコアで処理しきれないことがあります。

NICからの割り込みを複数のCPUコアで分散する仕組みとして、Linuxでは「Receive Side Scaling (RSS)」、「Receive Packet Steering (RPS)」、「Receive Flow Steering (RFS)」などの仕組みがあります。

このとき、同じ通信フローの処理は同じコアで処理するのが好ましいです。TCPなど、処理するパケット順番が変わってしまうと、Head-of-Line-Blockingにつながります。

同一フローを同一コアに割り振るために、割り振りの方法として、送信元IP・送信先IP・送信元ポート・送信先ポートのハッシュから割当先を決める方法があるようです。


Multiple Core Performance Hint Option

先述の通り、CPUコアへの割り振りにL4の送信元ポート・送信先ポートを使用します。しかし、それらの値が取得できないケースがあります。例えば次の場合です

  • パケットがフラグメントしてる場合
  • IPSecを使用している場合

Multiple Core Performance Hint Option」では、そのような場合でも同一の通信フローを適切に割り振れるようにIPヘッダオプションを定義します。

MCPHINT

新しいIPヘッダのオプションとして、MCPHINTを定義します。
MCPHINTはIPv4, v6ともで利用でき、2バイトのデータ領域 (Differentiation Data)を持ちます。

このDifferentiation Dataを用いてフローを識別し、CPUに割り振ることを想定しています。
(送信側がフロー毎に異なるDifferentiation Dataを格納するという仕組み)

感想

実用性がどこまであるのかちょっと実感がないが、面白い提案だなとおもった。

NIC割り込み処理の割り振り先を決定するためのヒントとして、IPヘッダにオプションを新しく定義するとは、なるほど。

QUICのマルチキャスト拡張

QUICを使ってマルチキャスト配信を可能にする「Multicast Extension for QUIC」という仕様が、AkamaiのJake Holland氏らによって提案されています。

マルチキャストでデータを配信することで、よりネットワーク帯域を効率用使うことが出来ます。

まだ最初の提案であり、まだTBDとなってるところもあり、これから変わりそうだが一旦目を通しておく。

背景/関連動向

まず、この「Multicast Extension for QUIC」登場と、関連状況について簡単に説明します。

AkamaiのJake Holland氏はWebでマルチキャストを使うために幅広く活動されています。今回の「Multicast Extension for QUIC」もWebでコンテンツを配信するための流れでの提案となっています。(もちろんただのQUIC拡張ですので、用途はそれに限りません)

W3Cでは「Multicast Community Group」を設立しています。
asnokaze.hatenablog.com

また、実際にブラウザ(chromiumのfork)でマルチキャストデータを受信可能にするAPIを実装していたりします。
github.com

関連仕様

関連する仕様は次のとおりです

これらに、マルチキャストでアプリケーションデータを配信するためのQUIC拡張が追加されたというながれです。

Multicast Extension for QUICの仕様

Multicast Extension for QUIC」の仕様について眺めていきます。

ユニキャストで通常のQUICコネクションを確立した後に、マルチキャストチャネルとしてマルチキャストでデータ(1-RTTパケット)を送信できるようになります。もちろんマルチキャストチャネルはサーバ側からの一方向でしかQUICパケットを送れません。なお、マルチキャストの識別にはRFC4607で定義される(S,G)を用います。(マルチキャストルーティングについては下位層の話なので、この仕様では言及されません)

特徴としてはざっくりこんな感じ

  • QUICコネクションはRFC9000で定義された通り
  • マルチキャストデータは暗号化される(マルチキャストチャネル用の対象鍵により、他の参加者も同じデータを受信し処理できる)
  • マルチキャストチャネルのデータがパケットロスした場合は、QUICコネクション経由で再送してもらえる (なお、DATAGRAMフレームも使える)

この仕様では、拡張機能ネゴシエーション、クライアントのマルチキャストチャネルの参加/離脱、フロー制御などについて定義しています。またそのために、新しい拡張フレームやエラーコードを定義します(MC_で始まる一連の拡張フレーム)。

大まかな流れ

マルチキャストでデータ受信の大まかな流れ

  • クライアントは、QUICコネクション確立時にmulticast_client_paramsトランスポートパラメータで初期値をサーバに伝える
  • サーバは、MC_CHANNEL_ANNOUNCEフレームを送信し今存在するマルチキャストチャネルの情報をクライアントに送信します。
  • サーバは、MC_CHANNEL_JOINフレームでマルチキャストチャネルに参加を呼びかけます
  • クライアントは、サーバからの要求に対しMC_CLIENT_CHANNEL_STATEフレームを返します。MC_CLIENT_CHANNEL_STATEフレームは"参加"、"拒否"、"離脱"をサーバに伝えることが出来ます
  • クライアントは、マルチキャストチャネルでのデータ受信を開始します
  • その後サーバがMC_CHANNEL_LEAVE でクライアントに離脱を要求するか、もしくはクライアントが自発的に離脱するとマルチキャストチャネルのデータ受信が完了します
パケロス

マルチキャストチャネルのパケロスに対して、クライアントはユニキャストのQUICコネクションで再送を要求します。

MC_CHANNEL_ACKをクライアントから送ることで、パケロスしたパケットをサーバに伝えます。サーバは、ユニキャストのQUICコネクションで該当パケットのデータを再送します (QUICでは、パケロスしてもそのパケットをそのまま送り直すのではなく、再送が必要なデータのみを送ります)。

マルチキャストチャネルで受信可能なフレーム

マルチキャストチャネルで受信可能なフレームは次のとおりです。

  • PADDING Frames ([RFC9000] Section 19.1)
  • PING Frames ([RFC9000] Section 19.2)
  • RESET_STREAM Frames ([RFC9000] Section 19.4)
  • STREAM Frames ([RFC9000] Section 19.8)
  • DATAGRAM Frames (both types) ([RFC9221] Section 4)
  • PATH_CHALLENGE Frames ([RFC9000] Section 19.17)
  • MC_CHANNEL_PROPERTIES
  • MC_CHANNEL_LEAVE (however, join must come over unicast?)
  • MC_CHANNEL_INTEGRITY (not for this channel, only for another)
  • MC_STREAM_BOUNDARY_OFFSET
  • MC_CHANNEL_RETIRE

おわりに

今回はほんの一部の紹介でしたが、また機会があればフレームレベルで紹介したいと思います。

Webでのマルチキャスト配信は夢がありつつ、まだまだ熱量が高い領域ではありません。今後の動向が気になるところです。
技術的には大変おもしろいので追っていきたい。