アプリをトンネルに通しても、そのアプリが起動したものすべてに経路が引き継がれるわけではなく、画面の見た目はそう示していても実際は違います。リンクは要求を別のプログラムに渡し、そのプログラムが自分のソケットを開き、プラットフォームは表示した側ではなく新しいプロセスに規則を適用します。トンネルポリシーが見ているのはこの二番目のプロセスであり、設定したほうのプロセスではありません。

そのため、対象に含めたアプリがトンネルの外にあるブラウザを開くことがあります。逆に、除外したブラウザがトンネル内のアプリに処理を戻すこともあります。この驚きはどちらの向きも普通の挙動です。

誰も設定していない工程

アプリごとのポリシーは実行ファイルやパッケージの識別子に対して書かれ、接続は作られた瞬間に評価されます。ブラウザ、文書ビューア、メディアプレーヤー、システムの共有シートはそれぞれ別の識別子を持ち、それぞれ別の判定を受けます。ディープリンクが運ぶのはデータであり、ポリシーではありません。

観察結果が気まぐれに見えるのは、同じクリックでもどのハンドラが応答するかで経路が二通りに分かれるからです。トンネル内のメールクライアントがリンクを開くと、トンネル外のブラウザでページが読み込まれ、自宅のアドレスから取得されます。トンネル外のブラウザが文書を開くと、トンネル内のビューアでファイルが届きます。どちらの結果もクライアントの不具合ではありません。

すでに動いているハンドラがあると、事態はさらに悪くなります。ブラウザが開いたままだと、リンクは既存のプロセスへのメッセージになり、そのプロセスは起動時の経路を保ちます。ハンドラを閉じて開き直すと結果が変わるので、この問題は求めても再現しません。

PlatformPolicy objectWhat it is evaluated against
AndroidPer-app VPN allowlistPackage name of the process opening the socket
WindowsApplication traffic filtersApplication path in the filter rule
LinuxUID or cgroup routing rulesOwner of the socket, which can be a different program

実際に接続を作ったのはどのプロセスか

推測するのではなく、受け取る側を測ります。トンネルを上げたまま、無害なリンクをクリックし、新しいプログラムが持つソケットを見ます。

ss -tnp state established '( dport = :443 )'
Get-NetTCPConnection -State Established | Select-Object RemoteAddress,OwningProcess

最初のコマンドは Linux で確立済みのソケットの背後にあるプロセスを名指しし、二番目は Windows で所有プロセス ID を解決して同じことをします。プロセス名をポリシーにある名前と比べてください。名前がブラウザで、そのブラウザが除外されているなら、クリックは不具合ではなく設計どおりにトンネルの外へ出ています。ポリシーの規則を生きたソケットに突き合わせることが、この方法のすべてです。

ハンドラが動いている状態と閉じた状態で、確認を繰り返します。二つの結果は違い得ますし、その差がトンネルから抜けるリンクに関する断続的な報告のほとんどを説明します。

カバレッジは工程の性質である

作業を最初から最後までトンネル内に留める必要があるなら、到達しうる構成要素――起動元、ハンドラ、ビューア、そしてプラットフォームが間に挟む仲介役――をすべてポリシーの内側に入れる必要があります。範囲を広げることが正直な答えであることは多く、共有先を一つずつ監査するより安く済みます。

一つのアプリを直すためにシステムの仲介役を除外するのはよくある誤りです。仲介役は共有されていますから、除外は同じ経路を使う他のすべてのアプリに及び、たいていは数週間後に報告が届くまで誰も気づきません。除外する前に、その構成要素に他に何が依存しているかを読んでください。

識別子と経路も分けて考えます。リンクは、どの出口が要求を受け取るかに関係なく、セッショントークンやアカウント識別子を運べます。正しく経路づけられたクリックでも、誰がそれをたどったかを宛先に正確に伝えられます。

文書化すべきは工程であり、最初のチェックボックスではありません。作業が四つのプログラムにまたがるとき、四つのプログラムを描いた図こそが通信の行き先を予測し、単一アプリの設定はその一行にすぎません。

関連記事