iphone(iOS 11)でMultiPath TCPを使う

すでにアナウンスされているとおり、iOS11よりMultipathTCP (MPTCP)のAPIサードパーティデベロッパーに公開されます。

実はiPhoneをお使いの人はすでに、iOS7からsiriでMPTCPが使われていたので裏ではすでに使われておりましたが、実際にみんなが試せるような状況になってきました。

MultiPathTCP (MPTCP)とは

MultipathTCPは複数のインターフェースを用いてTCPコネクションをはる事のできる、TCP拡張の一つです。例えばスマートフォンであればLTEWi-Fiといった2つのインターフェースを用いてコネクションをはり、両方の経路それぞれを併用してデータ通信をします。

大きなメリットとしては、使える帯域が増えるということだけではなくアプリケーション側からは1つのTCPコネクションに見えており仮に片方のコネクションが切れたとしてもTCPコネクションは維持できる点です。

Appleの発表では上記ios7のsiriにおいて、95パーセンタイル 20%の高速化と、接続失敗を5分の1に出来たようです。

ハンドシェイクと仕様

MultiPathTCPを使用するためにはクライント・サーバ両方が対応している必要があり、その際はTCP 3ウェイハンドシェク時にオプションとしてMP_CAPABLEが指定されてます。

もちろん既存のTCPコネクション(MP_CAPABLEが有効)に、別経路の通信(subflow)を追加する場合、経路上の機器からは一見ただのTCP 3ウェイハンドシェクが行われたように見えます(MP_JOINオプションが有効になってます)。

詳しくは、RFC6824を読まれるのが良いかと思います(改訂作業中:RFC6824bis)

(もちろん帯域公平性や、悪意あるユーザによるsubflowの追加を防ぐ機能があります (参考:TCP.next // Speaker Deck))

iOS11におけるMPTCP

すでにbeta版で試せるようですが、残念ながら手元に試せる環境がないため、すでに試されている人のコードを拝借させていただきます。
MPTCP experiments on iOS 11 beta — MPTCP

let config = URLSessionConfiguration.ephemeral

config.multipathServiceType = URLSessionConfiguration.MultipathServiceType.handover
let session = URLSession(configuration: config)

let url = URL(string: "http://multipath-tcp.org/data/uml/vmlinux_64")

let task = session.dataTask(with: url!, completionHandler:{...})

task.resume()

URLSessionConfiguration.MultipathServiceTypeは4つのmodeがあり、違いは以下のとおりです

  • none: MultipathTCPを使用しない
  • handover: Wi-Fi回線を優先します。LTEなどのキャリア回線からコネクションを維持したままシームレスにWi-fiにハンドオーバーします
  • interactive: レイテンシを最小にするような経路を使用します。データ量が少ない場合のみ仕様すべきで
  • aggregate: 両方の経路を使用してスループットを向上させます(デベロッパーのみが使用できます)

大まかにデベロッパーがモードを選択できることがわかります。

しかし、ファイアウォールなどによりMP_CAPABLEやMP_JOIN付きハンドシェイクがブロックされてしまったときの挙動や、レイテンシの向きの考慮(参考:One Way Latency Considerations for MPTCPdraft-song-mptcp-owl-01 - One Way Latency Considerations for MPTCP)や、NAT64下での問題(参考pdf)など、実際に試してみないと分からない気はします。


LinuxでのMPTCP対応

実際に試す場合はサーバサイドも準備する必要がありますので、少々古い記事ではありますが参考までに
asnokaze.hatenablog.com

Happy Eyeballs Version 2 の仕様 (RFC8305)

2017/12/22 RFC8305として標準化されました。
なお、下記内容は標準化中の内容につき一部古いかと思われます。


IPv4IPv6両方が利用可能なデュアルスタック環境において、通信する際にIPv6IPv4を並列的に試してより早く通信の確立が出来た方を試す Happy Eyeballs という仕組みがあります。

より環境の良い方を使うだけでなく、IPv6で通信を試みてからうまくいかない場合にIPv4にフォールバックするのでは無いためより早く通信通信の確立ができます。

Happy EyeballsはRFC 6555で標準化されておりますが、Appleの人によって提案されているHappy Eyeballs Version 2の仕様がIETFで議論されているので簡単に読みます。

Happy Eyeballs Version 2

Happy Eyeballs Version 2は、RFC 6555の頃より何点か変更があります。

まず、大きなところで、名前解決について非同期名前解決の方式が追加されました。今まで名前解決についての規定はありませんでした。AとAAAAを同期的に名前解決する実装もありましたが、早く名前解決出来た方から通信を開始すべき(SHOULD)ということになりました。

従来実装

提案方式

(3月に行われたIETF98の資料(pdf)より)

この非同期式名前解決が実施できない場合は(APIがない場合)、IPアドレスファミリごとに別スレッドを使って同等の事ができる。

その他

  • Happy Eyeballs中に、名前解決の結果が変わった場合の対応について。削除された場合は施行を継続、アドレスが増えた場合は適宜施行リストに追加
  • 以前の通信結果(IPアドレス毎のRTTや、以前TCP Fast Openを使った)などにより、通信施行順番の変更が可能に
  • NAT64 と DNS64を持つIPv6 only環境について

今後

3月に行われたIETF98では、議事録を読む限り興味を持ってる人も多く、またその後にWG Draftに昇格していることからも引き続きホットな議論になるものと思われる。

今月7月に行われるIETF99のv6ops WGのAgendaにもHappy Eyeballs Version 2の議論が行われる予定と鳴っている。

.internal ドメインを予約する提案仕様

IETFのdnsop WGで .internal ドメインを予約する「The .internal TLD.」という仕様が、GoogleのWarren Kumari氏によって提案されています。

DNSに関しては詳しくないのですが、ざっと読んだので簡単にメモ。

.internal

.internalというドメインを内部的に使用しているという方もおられるでしょう。

.internal TLDは、ICANNの「DNS名前衝突ブロックリスト」に含まれており、gTLDになることはありません。その事に関しては以下のINTERNET Watch様の記事が詳しいです。

萌えドメインなのに……「anime.moe」の登録をICANNが禁じている理由とは -INTERNET Watch Watch

しかし、この.internalはIANA(ポート番号や識別子を管理する組織)には登録されていません。現在ドメイン名で特別に予約されているドメインは、.exampleや.localなどがあります。一覧はIANAのWebページから確認できます。

.internal の予約

すでに.internalは使用されており、root DNSへもクエリが漏れてるのだとは思いますが
DNSプロトコルとして .internalを内部利用のために予約する提案が「The .internal TLD.」です。

この提案では、背景、なぜ他の登録済みドメインを利用しないのか、DNSSEC利用時の取扱、それぞれの.internalの扱いについて書かれています。

利用者/オペレータ/レジストラの.internalの扱いは以下のようになるようです

  • アプリケーション及びソフトウェアの作者は .internal を特別に扱う必要はありません
  • キャッシュDNSは .internal を特別扱いしても良いです。ローカルのゾーン情報を使用すべきですが、権威サーバにフォワードしても良いです。
  • 権威サーバは .internal を特別扱いしてはいけません。ローカルでのみ特別な意味を持ちます。
  • DNSオペレータは、.inteenal へのクエリはグローバルなものでないことに注意し、外部にリークされることに注意してください。
  • DNSレジストリ/レジストラは .internal を登録する要求を許可してはいけません。

すでにdnsop WGメーリングリストですでに議論はあったようですが、ドラフトは出たばっかりですのでまだまだ議論が続くことでしょう。

Nginxのリバースプロキシでバックエンドとhttp2通信する

以前書いたとおり、ApacheではリバースプロキシでバックエンドとHTTP2通信することができます。

asnokaze.hatenablog.com

f:id:ASnoKaze:20170531004524p:plain:w450

Nginxの場合は、開発者のメーリングリストGoogleの人が書いてる「ngx_http_v2_upstream」パッチを利用することでバックエンド(upstream)とHTTP2通信することが出来るようになります。

ビルド

環境はUbuntu16.04

$ hg clone http://hg.nginx.org/nginx/
$ cd ./nginx
$ hg update -r 7039

# 順番にパッチを当ててく
$ patch -p1 < ./1.patch
...

$ ./auto/configure  --with-http_ssl_module --with-http_v2_module
$ make

#今回はインストールしてしまう
$ sudo make install

設定

proxy_http_versionに2.0が指定できるようになります。
proxy_passにhttp://を指定すると、h2cダイレクトでバックエンドと接続しに行きます
(証明書は適当に準備)

#nginx.conf
    proxy_http_version 2.0;

    upstream backend {
        server 127.0.0.1;
    }

    server {
        listen       443 ssl http2;
        server_name  localhost;

        ssl_certificate      /home/yuki/server.crt;
        ssl_certificate_key  /home/yuki/server.key;

        location / {
          proxy_pass http://backend/test;
        }
    }

その他、h2cダイレクトではなくhttpsでプロキシする際に、ALPNを使うように出来るようですがちょっと動作が怪しいようです....

proxy_ssl_alpn on;

動作確認

バックエンドはh2cで接続できるようにしておきます。

#nginx.conf
    server {
        listen       80 http2;
        server_name  localhost;
    }

ブラウザでサーバにアクセスすると、バックエンド(/proxy/)もHTTP/2.0で接続できている事が確認できました

$ tail /var/log/nginx/access.log
127.0.0.1 - - [02/Jul/2017:16:36:40 +0000] "GET /proxy/ HTTP/2.0" 404 571 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
192.168.0.104 - - [02/Jul/2017:16:36:40 +0000] "GET / HTTP/2.0" 404 571 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"

Webページを丸ごとパッケージングする Web Packagingとは

20180824追記
Loading Signed Exchangesについて記事を書きました
Loading Signed Exchangesの仕様 (WebPackaging) - ASnoKaze blog

20180208追記
Bundled HTTP Exchangesについて記事を書きました
Bundled HTTP Exchanges とは (WebPackagingの議論より) - ASnoKaze blog

20180121追記
署名の仕組みとして Origin-Signed HTTP Exchanges を利用する方向のようです
HTTP/2 クロスオリジン サーバプッシュを可能にする提案仕様 - ASnoKaze blog

20171001追記
IETF99にてユースケースについてまずまとめるべき気というフィードバックが有り、それをうけて「Use Cases and Requirements for Web Packages」が提出されています


Webページを丸ごとパッケージングする、Web Packagingの仕様がIETFで提案されています

オフラインやローカル環境で共有出来るようになっており、主な特徴は

  • 証明書及び署名がつけられるため、そのパッケージの真正性が確認できる
  • HTTPリクエスト/HTTPレスポンスも含まれている(HPACKを利用)
  • サブパッケージが利用でき、複数のオリジンをパッケージング可能
  • データはCBORで表現される (RFC 7049 - Concise Binary Object Representation (CBOR))
  • Index化されており、オフセットを用いて各リソースにランダムアクセス可能

以上の点で、ZIPで固めて保存するのとはまったく違うことがわかるかと思います。

ユースケース

幾つかユースケースがありますが、主なものは以下のとおりです

  • ローカル環境での共有。SDカードでの共有から、Physical Webと言ったその場でのBluetoothを用いた配信など
  • Webのスナップショット保存。そのページをスナップショットとして保存する(署名無し)
  • CDNでの配布。CDNや別の場所から再配布することが可能。この場合は署名をつけての配布が可能となる

提案仕様と経緯

6月30日に、GoogleのJeffrey Yasskin氏より「Web Packaging」という提案がIETFにて出されました。おそらく議論はDispatch WGで行われ、今月実施されるIETF99
https://www.ietf.org/meeting/99/
でもオフラインでの議論があるかもしれません。

もともと、Webページをパッケージングする仕様は、W3Ctag「Packaging on the Web」というものがありましたが、そこから署名などの機能を追加し整理した「Web Packaging」という仕様がW3CのWICGで議論されておりました。

このW3C WICGの仕様は、データフォマットが要でありIETFで標準化していくのが適切ではないかとIETFに持ち込まれた形になります。

フォーマット

webpackageのフォーマットは以下の通りである

webpackage = [
  magic1: h'F0 9F 8C 90 F0 9F 93 A6',  ; 🌐📦 in UTF-8.
  section-offsets: { * (($section-name .within tstr) => offset) },
  sections: ({ * $$section }) .within ({ * $section-name => any }),
  length: uint,                        ; Total number of bytes in the package.
  magic2: h'F0 9F 8C 90 F0 9F 93 A6',  ; 🌐📦 in UTF-8.
]
  • magic: 先頭と最後に挿入されるMagicコード。意味はない
  • section-offsets: 各セクションへのオフセット値が与えられる。必須ではない
  • sections: ここにManifestや実際のコンテンツが格納される(manifest, indexed-content)
  • length: データ長

manifest及び、indexed-contentは以下で説明します。

manifest

sectionsに格納されるmanifestデータ。必須ではない。

日付、オリジン名、証明書、署名が格納される。また、アレば別オリジンのパッケージをサブパッケージとして読み込むことが出来る。

具体的には以下のパラメータです

  • metadata: 日付、及びオリジンが記述される。また、あればサブパッケージの指定
  • resource-hashes: 各リソースのハッシュ値
  • signatures: 署名
  • certificates: 証明書

    "manifest": {
      "manifest": {
        "metadata": {
          "date": 1(1494583200),
          "origin": 32("https://example.com")
        },
        "resource-hashes": {
          "sha384": [
            h'3C3A03F7C3FC99494F6AAA25C3D11DA3C0D7097ABBF5A9476FB64741A769984E8B6801E71BB085E25D7134287B99BAAB',
            ...
          ]
        }
      },
      "signatures": [
        {
          "keyIndex": 0,
          "signature": h'3044022015B1C8D46E4C6588F73D9D894D05377F382C4BC56E7CDE41ACEC1D81BF1EBF7E02204B812DACD001E0FD4AF968CF28EC6152299483D6D14D5DBE23FC1284ABB7A359'
        }
      ],
      "certificates": [
        DER(
          Certificate:
              ...
              Signature Algorithm: ecdsa-with-SHA256
                  Issuer: C=US, O=Honest Achmed's, CN=Honest Achmed's Test Intermediate CA
                      Public Key Algorithm: id-ecPublicKey
                          Public-Key: (256 bit)
                          pub:
                              ...
        ),
        DER(
          Certificate:
              ...
        )
      ]
    },
indexed-content

sectionsに格納される、indexed-content。ここにコンテンツの中身が格納される。
各リソースに対するHTTPリクエスト及びHTTPレスポンスが合わせて格納されており、ヘッダに関してはそれぞれHPACKでエンコードされている。

    "indexed-content": [
      [
        [ hpack({
            :method: GET
            :scheme: https
            :authority: example.com
            :path: /index.html
          }), 1]
        [ hpack({
            :method: GET
            :scheme: https
            :authority: example.com
            :path: /otherPage.html
          }), 121],
        [ hpack({
            :method: GET
            :scheme: https
            :authority: example.com
            :path: /images/world.png
          }), 243]
        ],
      ],
      [
        [ hpack({
            :status: 200
            content-type: text/html
            date: Wed, 15 Nov 2016 06:25:24 GMT
            expires: Thu, 01 Jan 2017 16:00:00 GMT
          }),
          '<body>\n  <a href=\"otherPage.html\">Other page</a>\n</body>\n'
        ]
        [ hpack({
            :status: 200
            content-type: text/html
            date: Wed, 15 Nov 2016 06:25:24 GMT
            expires: Thu, 01 Jan 2017 16:00:00 GMT
          }),
          '<body>\n  Hello World! <img src=\"images/world.png\">\n</body>\n'
        ],
        [ hpack({
            :status: 200
            content-type: image/png
            date: Wed, 15 Nov 2016 06:25:24 GMT
            expires: Thu, 01 Jan 2017 16:00:00 GMT
          }),
          '... binary png image ...'
        ]
      ]
    ]

セキュリティについて

オフラインの利用を想定しているため、証明書の失効確認については難しいところがあります。Webパッケージの利用者は正当性を確認する際は、オンライン時はOCSPを利用して失効確認が可能ですが、オフラインのときはブラウザによって判断されることになるでしょう(1週間だけ有効など)。

そこの部分については今後の議論になるかと思われます。

TLS1.3の0-RTT通信と、HTTP 425 ステータスコードの提案仕様(RFC8470)

20190502 追記
動いた

20180922 追記
RFC8470として標準化されました

無事Too Earlyのステータスコードが 425になりました (URL)

本記事は、draft-00時点の記述の通り、未定を示す4NNのままとしておきます。


2020/01/19追記

#http_tokyo で詳しい説明をしました。あわせてどうぞ

www.slideshare.net



TLS1.3では、0-RTTハンドシェイクの際にearly_dataとしてアプリケーションデータを送信できます。しかし、この0-RTTハンドシェイクで送信するデータには、リプレイ攻撃のリスクがあります。
そのリスクをさけるための機能をHTTPに追加する提案が出ています。

提案仕様は、「Using TLS Early Data in HTTP」で公開されており、著者はMartin Thomson, Mark Nottinghamらである。

この仕様ではHTTPに以下の機能を追加します

背景

現在標準化の大詰めを迎えているTLS1.3の機能の一つに 0-RTT Data というものがります。

これは、一度TLSハンドシェイクを行ったサーバに対して再度ハンドシェイクを行う際は、ClientHelloと共にアプリケーションデータも送信する手順です。通常のフルハンドシェイク手順よりも早くアプリケーションデータを送信し始めることができます。パケットの往復を待たずに送りたいデータを送ることから、0-RTTハンドシェイクとも呼ばれます。

具体的な手順は、TLS1.3の仕様の2.3節で示されています
f:id:ASnoKaze:20170618234412p:plain:w350

この0-RTTハンドシェイクで送信されるアプリケーションデータはもちろん暗号化されていますが、リプレイ攻撃が可能です。0-RTTハンドシェイクのClientHelloのパケットを観測し、再度サーバに送りつけ多重にリクエストを処理させることができます。

そのため、この0-RTTハンドシェイクで送信するアプリケーションデータはべき等なもの、つまり、なんど処理をしても結果が変わらないものに限られるべきです。HTTPで言えばGETメソッドなどがそう言えるでしょう(そうでないものも多いですが)。

4NN (Too Early)と、Early-Dataヘッダ

この 0-RTT Dataのリスクを軽減するために「Using TLS Early Data in HTTP」という提案がでています。この仕様ではHTTPに以下の機能を追加します

4NN (Too Early)

4NN (Too Early)は、サーバがリプレイ攻撃の危険性がある0-RTTハンドシェイクのearly_dataデータを処理したくないことをクライアントに通知するステータスコードです。

このステータスコードを受け取ったクライアント(User-Agentやプロキシ)は自動でリクエストを再試行すべきではありません、全く新しいコネクションとしてサーバに接続する必要があります。

418 VS その他

具体的なステータス番号については、Author間で議論がありました。まだIANAに登録されていない418を使うという提案がありましたが、Hyper Text Coffee Pot Control Protocolで「418 I'm a teapot」として使用されています。

「418 I'm a teapot」は https://www.google.com/teapot 実際にデプロイされておりますが、HTCPCPはジョークRFCであり、HTTPとは別のプロトコルであるためステタース番号はかぶっても良いという意見です。

また、ジョークRFCによって貴重な番号が消費される事についても意見がついているようです。

しかし最終的には関係者と議論して決めるようです。

Early-Dataヘッダ

TLSを終端するサーバとアプリケーションサーバが別れている構成は一般的です。もちろんCDNクラウドサービスのTLS終端サービスはそのHTTPリクエストがリプレイ攻撃されても問題ないか判断はできません。

そのため、TLS終端したサーバはそれが元々0-RTTハンドシェイクで送られてきたデータなのか区別できるようにする必要があります。

仕様では、HTTPリクエストが0-RTTearly_dataで送信されていることを示すEarly-Dataヘッダが定義されています。0もしくは1であり、1がearly_dataで送信されていることを示します。

TLSを終端しているサーバがEarly-Dataヘッダを付与します。"Early-Data"ヘッダーフィールドは、ユーザーエージェント(つまり最初のリクエストを送った者)が使用するためのものではありません。

f:id:ASnoKaze:20170619000602p:plain

この時、4NNを受け取った場合の終端サーバはクライアントにそれを転送しなければなりません。

またEarly-Dataヘッダは、4NNステータスコードを理解できることも示しています。

QUIC標準化現状確認メモ

2018/2
asnokaze.hatenablog.com


Googleの考案したQUICは現在IETFで標準化が進められており、多くの人々によって議論されております。QUICの中身よりも現在の状況について、自分用に整理する。

Issueが追えてないので残念感ある。

概要

UDP上で信頼性のある暗号化されたHTTP/2通信を行うQUICは、もともとはGoogleが考案・実装・実証をすすめられていた。

IETFの会合で数度のBoF(WG設立前の議論)の開催へて、2016年にQUIC WGが出来QUICの標準化を進めることが決定した。

QUIC WGのゴールはCharterにかかれている通り、大まかに以下のとおりである

  • アプリケーションのために、コネクション及びトランスポートの遅延を最小化すること
  • head-of-lineブロッキングの無い多重化を提供すること
  • エンドポイントの変更のみでデプロイ可能とすること
  • マルチパスとFEC(forward error correction)を拡張機能として有効にする
  • TLS1.3を使用した常時暗号を提供すること

また、マイルストーンとしては主要な4つの仕様は 2018年ごろにほぼほぼ標準としては固まった状態となり、IESGに提出される予定になっている

  • Mar 2018 Core Protocol document to IESG
  • Mar 2018 Loss detection and Congestion Control document to IESG
  • Mar 2018 TLS 1.3 Mapping document to IESG
  • Nov 2018 HTTP/2 mapping document to IESG
  • Nov 2018 QUIC Applicability and Manageability Statement to IESG
  • May 2019 Multipath extension document to IESG

7月に行われるIETF99において、以下にあげる仕様(draft04)で相互接続通信ハッカソンが行われる予定になっている。しかし、フル実装ではなく1RTTハンドシェイクにフォーカスしたものである (Home · quicwg/base-drafts Wiki · GitHub)

仕様・ドキュメント

主要仕様

現在の仕様、主要な4つに関してはWGドラフトとなりすでに改版が進んでいる。直近で6/13にdraft-04となっている

Ops

Opsに関して、すでにAdopetされている個人ドラフト

個人ドラフト

その他個人ドラフト

ドキュメント

その他仕様ではないが、参照されるもの

Google QUIC

その他Google QUIC側の資料は「Chromiumのプロジェクトページ」から辿れる。すべての資料ではないが、YoutubeにおいてFECを有効にした際の評価についての資料などもある。

議論/発表資料

直近の議論と、発表資料についてまとめる

IETF QUIC Working Group Interim Meeting

6/6~8にかけて行われた、IETFの本会合との間に設けられているQUIC WGの中間会議

議事録」の通りとなるが、Implementation Draftの議論、幾つかのIssueについての熱い議論及び、下記の発表があった

過去のIETF/Interimの議事録・発表資料はGithubで公開されている
https://github.com/quicwg/wg-materials

The HTTP Workshop

6/12~13にかけて行われた、標準化の場ではないが、仕様の著者、ブラウザベンダ、ミドルウェア実装者、CDNや大手サービスがHTTPについて議論するWorkshopであり、QUICに関する発表もあった。

Next IETF

次のIETFは7/16~21であり、もちろんQUIC WGのセッションもある。スケジュールはすでに公開されており、QUICのセッションは20, 21である。

余談だが、リモートでの参加は誰でも無料で出来る、深夜帯ではあるが興味ある方は下記記事を参照頂ければと思う
qiita.com