内部名を一つ要求したときだけトンネルが開き、次のアプリが同じくらい必要としても閉じたままになる。これはアプリの不具合ではなく、ドメインルールの形そのものだ。Apple の on-demand 構成は接続を確立する条件を記述し、その条件のドメイン形式は、パケットが一つも動く前にシステムリゾルバへ問い合わせる。常に混同される二つの問いがある。トンネルをいつ立ち上げるか、そして存在したトンネルが何を運ぶかだ。前者はトリガー、後者はルートとリゾルバのポリシーであり、一つのプロファイルが通常どちらも同じ payload に設定するため、正しいドメインルールでも誤ったネットワークに留まることがある。

トリガーと通信の選択は別の層にある

on-demand ルールは VPN payload の on-demand 辞書に置かれる。順序付きのルール一覧で、各ルールはアクションと一致条件の集合を持つ。システムは接続状態が変わったとき、または何かがネットワークに到達しようとしたときにそれらを評価し、アクションがトンネルを起動するか、評価するか、切断するか、無視するかを決める。これはすべてプラットフォームのネットワーク層で、アプリがソケットを持つ前に起こる。

その後に続くのは別のキー群だ。トンネルの IPv4 と IPv6 の設定、含めるルートと除外するルート、DNS サーバーのアドレス、そして iOS と iPadOS ではどのアプリがトンネルを使えるかを決めるアプリ単位のマッピングである。プロファイルは広いトリガーと狭いルートを組み合わせることも、狭いトリガーと既定ルートを組み合わせることもできる。片方だけ読むと、もう片方が故障に見える。

私のラボ用プロファイルは、内部ドメイン配下の何かが要求されるたびに接続するが、トンネルには /16 を一つだけ流す。payload に書かれたとおりに動くが、これはチケットを生む種類のプロファイルでもある。接続済みのトンネルとは、通信がその中にあるという意味だと人は思い込む。

ドメインルールが実際にリゾルバへ問うこと

connect-if-needed と呼ばれることの多いルールのドメイン形式は、パケットの payload を検査せず、URL も監視しない。名前が解決されるとき、システムはそれをルール内のドメインと比較し、一致するとその名前がトンネルの提供する DNS サーバーで解決できるかを問い合わせる。トンネルのリゾルバが答えれば、その名前は内部と見なされ接続が始まる。代わりにローカルのリゾルバが答えれば、名前は外部として扱われトンネルは現れない。Apple の展開の概要はこれをネットワーク検出とそれに続く接続評価と説明している。

そこから二つの帰結が生じる。プロファイルはトンネル内の DNS サーバーを指定しなければならない。トンネルのリゾルバがないドメインルールには比較対象がなく、期待する一致は得られない。そして問い合わせはシステムリゾルバに届かなければならない。独自の暗号化 DNS を動かすアプリやブラウザ、ローカルで応答する拡張機能、リテラルアドレスへの接続は、ルールが待っていた名前解決を決して生まない。私が過ごした最も長い午後の一つは、トンネルの手前のクライアントが DNS over HTTPS を使っていたと分かったときに終わった。

キャッシュもトリガーを奪う。すでにキャッシュにある名前は、トンネルを起動したはずのプローブなしで応答されることがあり、昨日動いていたルールが再起動後や、トンネルがしばらく上がったままだと失敗する。macOS では sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder が状態をリセットし、iOS では機内モードの切り替えやデバイスの再起動が同等のきれいな状態をもたらす。

一致の範囲: 名前、アプリ、ネットワーク

ドメイン一致はいくつかある種類の一つだ。ルールはインターフェース種別(Wi-Fi、セルラー、Ethernet)や特定の SSID にも一致でき、アプリ単位や Safari ドメインのエントリはトンネルを一つのワークフローに結びつける。この結びつきが、一つのアプリだけが他と違う動きをする奇妙な体験を説明する。他のアプリはトンネルの範囲外なので、トンネルのアイコンが接続済みと言っていてもローカルの経路を使い続ける。

順序は人が思う以上に重要だ。ルールは順に評価され、最初に一致したものがアクションを与える。したがって狭いドメインルールの上に置かれた広い「どの Wi-Fi でも接続」ルールは静かに勝ち、ドメインルールをテスト不能にする。ドメイン一覧を書き換える前に、以前のルールがすでに一致していないことを確認する。

always-on が単に厳しい on-demand ルールではない理由もここにある。always-on の強制は別の展開モードであり、独自の監視と管理の要件を持つ。名前へ反応するのではなく、トンネルを開いたままにする。決して落ちないトンネルが必要なら、ドメインルールは間違った道具だ。

壊れたルールに見える障害

ドメインルールが動かないという報告のほとんどは五つの場所のどれかに落ち、そのうち最後のものだけがルールの文面だ。

What you seeLayerFirst check
Tunnel comes up, internal site still failsroute or resolver after connectnetstat -rn, scutil --dns
Tunnel never comes up for that nametrigger pathfresh lookup, cache flush, private DNS
Tunnel comes up for every appscope, or an earlier rulerule order, per-app mapping
Tunnel drops and will not return on the same Wi-Fiinterface or SSID match, admissioncaptive portal, SSID string, auth prompt
Tunnel returns after you disconnect itprofile ownershipprofiles show

キャプティブポータルは独自の行に値する。ホテルや空港の Wi-Fi は、ルールが依存するまさにその問い合わせを傍受するからだ。ポータルがデバイスを通すまで、トンネルの DNS サーバーには届かず、プローブは失敗し、障害はドメインの綴り間違いのように見える。認証ももう一つの静かな事例だ。ルールは発火し、トンネルは接続を始めても、期限切れの証明書や別のディスプレイに出るプロンプトで接続が死ぬ。

IPv6 は誤診しやすい変種を生む。両方のアドレスファミリーを持つ名前がまず AAAA レコードで応答される一方、トンネルのルート一覧は IPv4 しか運ばないことがある。あるブラウザは成功し、別のブラウザは失敗し、ドメイン一覧はまったく無実だ。

実際の要求で、この順に試す

推測する前にポリシーを読む。macOS では sudo profiles show -type configuration が VPN payload を含むインストール済みプロファイルを出力し、scutil --nc list がサービスの状態を示し、scutil --nc show <service> がシステムが使っている on-demand 辞書を出力する。管理された iPhone や iPad では同じ payload が管理コンソールや MDM レポートから届く。ネットワークログは macOS では log stream --predicate 'subsystem == "com.apple.networkextension"' で、電話を接続したときはデバイスコンソールで見られる。

次に、そのセッションでまだ問い合わせていないホスト名で試す。トンネルの DNS ゾーン内で内部解決されると分かっている名前を選び、一度だけ要求してトンネルが現れるか見る。同じ問い合わせを二度実行する。二度目はキャッシュ経路を通り、二つの差がトリガーが解決なのかルーティングなのかを教えてくれる。

トンネルが上がったら、二つの層を別々に確認する。netstat -rn -f inet と netstat -rn -f inet6 は各プレフィックスの向き先を示し、scutil --dns はリゾルバの順序とどのインターフェースが各リゾルバを持つかを示し、nettop -m route はどのインターフェースがバイトを運んだかを示す。トンネルが上がっていてリゾルバも正しいのにリソースが失敗するなら、ルールの編集をやめる。サーバー側の認可と戻りルートを確認する。

ルールが他人のもののとき

切断した後にトンネルが再び現れるなら、ルールは通常アプリではなくプロファイルに属する。MDM で配布された構成、残った個人プロファイル、別のクライアントが入れたプロファイルだ。sudo profiles show -type configuration と on-demand キーの検索で絞り込め、削除の道はプロファイルであり、メニューバーのスイッチではない。サービス項目やアプリを削除してもルールは残り、次のインストールがまた引き継ぐ。

一つのテストで所有が決まる。切断し、待ち、もう一度内部名を要求する。トンネルが戻ればトリガーは設計どおりに動いており、開いた問いは誰が管理しているか、その範囲が望みどおりかだ。

これを不具合として報告する前に、同じ五つの確認を通す。payload にトンネルのリゾルバアドレスがあるか、キャッシュされていない名前か、以前のルールがすでに一致していないか、ルート一覧が AAAA 経路を覆っているか、アプリがトンネルの範囲内か。五つすべてが成り立てばルールは仕事をしており、障害は経路のもっと先にある。

関連記事