Androidのアプリ別VPN:アプリを除外することは遮断ではない
画面に表示されるアプリ別リストは1つのトンネル所有者に属しており、アプリを除外するとそのトンネルを迂回させるだけで、ネットワークから外すわけではない。まずそこから始めよう。
二人が同じ質問をし、相容れない答えを得る。立っている場所が違うからだ。一人はシステムのVPN設定画面を開いてアプリの一覧を編集している。もう一人はエディタでVpnService.Builder.addDisallowedApplication()を書いている。どちらもそれをアプリ別VPNフィルタと呼ぶ。その制御を実際に所有しているのは片方だけで、しかも二人とも何も遮断していない。
ユーザーが見る画面から始める
設定を開き、VPNの項目を探し、実際に有効な接続を見る。クライアントがアプリ別リストを提供しているなら、そのリストはクライアント自身のトンネルに属する。プラットフォームは、無関係なアプリが別のVPNのアプリ選択を読み書きできる汎用APIを公開していない。だから二つ目のアプリがユーザーのためにそのリストを直すことはできない。
ここが手順の最初の分岐点だ。インストール済みのVPNにその設定がなければ、コードで回避すべきものは何もない。トンネルを所有する製品にその機能が存在しないのだ。設定があるなら、正しい修正はその画面で、それを開ける人が行う。
パケットをトンネルの中へ追う
自分のアプリがトンネルを構築するとき、TUNインターフェースを作り、どのアプリのトラフィックがそこに入るかを宣言する。メンバーシップの呼び出しはインターフェースが確立される前に行われ、その後はそのセッションのルールセットが固定される。
val builder = VpnService.Builder()
builder.addAddress("10.8.0.2", 32)
builder.addRoute("0.0.0.0", 0)
builder.addDisallowedApplication("com.example.bypass")
val tun = builder.establish() // membership decided hereこれらの呼び出しは、自分のアプリが今作ったトンネルにだけ適用され、それ以外には何の影響もない。デバイス全体のポリシーではなく、他のクライアントのために残ることもなく、他人のVPNに届くこともない。パッケージを解決できないためにビルダーの呼び出しが例外を投げると、インターフェースは決して確立されない。これは静かな失敗ではなく、きれいな失敗だ。
除外が遮断に見えた理由
除外されたアプリは、あなたのトンネルを迂回して下位のネットワークへ流れる。それは遮断の反対だ。トラフィックは今もデバイスを出ており、ただ自分が制御するインターフェースの外に出ているだけだ。ファイアウォール型のアプリは逆のことをする。アプリのトラフィックを自分のトンネルに受け入れ、そのうえでパケットを捨てるか転送を拒否する。インターフェースは同じで、ポリシーの向きが反転している。
その反転の裏側にある作業は、設定フラグではない。トンネルのディスクリプタからIPパケットを読み、フローごとに判断し、保護されたソケットで転送するか破棄する。扱わなかったものは単に止まる。だから作りかけのトンネルは、動くフィルタではなく壊れたネットワークに見える。目的が遮断なら、パケット処理、フォアグラウンドサービス、分類できないトラフィックのための文書化されたポリシーを見込んでおくべきだ。
自分で作ると壊れるところ
Androidは通常、同時に一つのVPNしか許可しない。そのため、製品がチェーンをサポートしていない限り、フィルタ用のトンネルとプライバシー用のトンネルは同じ場所を取り合う。接続をブロックする常時接続VPNは、失敗の仕方を変える。トンネルに入れないトラフィックは直接送られる代わりに破棄される。これは漏えい防止の設計が望むことであり、デバッグの場面がほとんど予期しないことでもある。
パッケージの可視性が二つ目の罠だ。アプリのパッケージ名の解決はNameNotFoundExceptionで失敗することがあり、新しいAndroidでは見えるパッケージの集合が宣言したクエリに依存する。すべての名前が解決すると仮定せず、例外を処理すること。そしてアプリがインストールされたり削除されたりしたら、リストを永久にキャッシュせず読み直すこと。
管理されたデバイスは三人目の所有者を加える。企業のモビリティポリシーはアプリ別VPNや常時接続プロファイルを設定でき、通常のアプリはそれを上書きできない。自分のコードをデバッグする前に、デバイスが管理されているか確認すること。その場合、変更しようとしているリストは、端末を持っている誰にも編集できないかもしれない。
自分が制御するアプリで試す
フィルタしようとしているアプリで試してはいけない。ネットワークの挙動を観察できる二つ目のアプリを使い、そのトラフィックがあなたのトンネルを通って出る一方で、対象のトラフィックは出ないことを確認する。両方が中に残るならポリシーは機能しており対象は除外されている。どちらも出ないならトンネル自体が間違っており、アプリのリストは問題ではない。
そのうえで、三つのうちどれを作っているのかを決める。アプリ別トンネルはビルダーAPIであり、リストはプロファイルの一部だ。デバイスのファイアウォールはパケット処理に加えて、説明できるライフサイクルが要る。他人のVPNを変えることはそもそもサポートされた道ではなく、そこでの正直な答えは、その設定はその製品に属するということだ。