デプロイスクリプトのどこかで、コピーを始める前にトンネルが上がっているかを確認しています。使える答えは三つあり、同じことを意味しません。scutil が報告するサービスの状態、カーネルが選んだルート、そして相手側が実際に応答するかどうかです。これらを突き合わせることこそ、コピーを予測する確認と、ログを飾るだけの確認の違いです。

VPN が上がっているかへの三つの答え

サービスの状態はコントロールプレーンの事実です。macOS は、設定が接続済みだとクライアントプロセスが言ったので接続済みだと知っています。ルートはデータプレーンの事実です。カーネルはこの宛先をそのインターフェース経由で送ります。到達性はエンドツーエンドの事実で、他の二つには見えない理由で失敗することがあります。

SignalAnswersBlind spot
scutil --nc statusIs the service connected?Third-party clients, wrong routes
route -n getWhere would this go?The peer may be down
A request to the far sideDoes it work now?Slow, and it changes state

役に立つ確認は最初の二つを組み合わせ、三つ目を他の二つが嘘をついていなかった証拠として使います。どれか一つだけでは、時刻を添えた推測にすぎません。

表示名ではなく識別子を読む

scutil --nc list
scutil --nc status "Office"

一覧はサービスごとに一行を出力し、各行には括弧入りの状態、続いてサービスの識別子、種類、表示名が並びます。スクリプトは識別子に対して書いてください。表示名は誰かがシステム設定に入力したもので、予告なく変わるからです。status コマンドは一語を出力し、一部のサービスの種類ではその後に統計が続きます。名前を出力全体から探すのではなく、その最初の一語を照合してください。名前は他の場所にも現れます。

サービスの起動は認可の確認を出したり、プロファイルが管理されている場合はそのまま拒否されたりします。その拒否はトンネルの故障ではありません。誰が起動してよいかというポリシーの表明です。

サードパーティのクライアントは一覧に出てこない

一覧が空でも VPN がないわけではありません。システム自身のネットワーク設定で作った構成はここに出ますが、ベンダーのクライアント、管理プロファイル、サードパーティ製アプリは、このコマンドが決して見ないトンネルを保持できます。自分のサービスの権威は自分のツールです。登録したことのないクライアントについて scutil に尋ねても何も返らず、何も返らないことは切断と同じ答えではありません。

一覧が空なのに通信が明らかに暗号化されているときは、インターフェースを探してください。想定範囲のアドレスを持つ utun や ppp のデバイスは、何かがトンネルを張った証拠です。これはサービスの状態より弱い信号なので、インターフェースを身元の証明として扱うのではなく、ルートの確認と組み合わせてください。複数のクライアントが複数のそうしたインターフェースを作ることがあり、意図したトンネルに属するのはそのうちの一つだけです。

状態と経路は別物

接続済みのサービスはトンネルが存在すると言います。宛先がそれを使っているとは言いません。アドレスを読み、次にカーネルへ直接尋ねてください。

ifconfig | grep -A4 utun
netstat -rn -f inet
route -n get 10.40.0.20

フルトンネルのクライアントはトンネル経由のデフォルトルートを入れ、スプリットトンネルのクライアントは特定のプライベートプレフィックスを入れます。どちらも Connected と報告し、状態だけを見るスクリプトは平気で間違った経路を走ります。トンネルを止めても、別のクライアントが入れたルートが必ず消えるわけではありません。接続済みのサービスと古いルートが同時に残るのは、そのためです。気にしている宛先を見てください。ルート表全体ではなく。

名前解決は別の問題

アドレスは通じるのに他のマシンが名前で Mac に届かない、という話は VPN の不具合として報告されます。ローカルホスト名、ホスト名、DNS レコードは三つの別物です。scutil --get LocalHostName は Bonjour 名を表示し、sudo scutil --set HostName mac-office はシステムが報告する名前を設定します。

どちらの設定もオフィスのゾーンにレコードを作りません。他のホストが DNS で名前を解決しなければならないなら、ゾーンの所有者がレコードを追加するか、スクリプトがアドレスを使うべきです。安定した名前を設定すると告知は一貫しますが、リゾルバーが答えるようにはなりません。

スクリプトにサービスの識別子と想定するルートの形を一緒に記録し、コピーの前に両方を確認してください。上がっていても経路が間違っているトンネルは、トンネルがないのとまったく同じように失敗し、Connected と書かれたログ行は次の人を間違った場所へ送ります。

関連記事