トンネルを接続し、非公開のダッシュボードを開くと、名前は見たことのないアドレスに解決されます。逆のことも起こります。ブラウザは動き続けるのに、コマンドラインのツールが突然何も解決しなくなります。どちらの結果も同じ変更から生じますが、多くの人は「VPNが独自のDNSを使う」という一言で説明しますが、これは切り分けにも検証にも足りません。その一言には二つの問いが隠れています。このプロファイルはどの照会を引き受けるのか、そして端末はそれを与えられたリゾルバへ実際に送ったのか。両者を分けて扱うことが方法そのもので、混ぜたテストは、どちらの向きにも自信ありげな誤答を出します。

プロファイルがリゾルバを渡す理由

トンネルの内側では、遠端の先にある名前はふつうそのネットワークにしか存在しないアドレスへ解決されます。corp.internal のような非公開ゾーンには公開委任がないため、それを答えるリゾルバはトンネルの内側から到達できなければなりません。同じ仕組みは第二の目的にも役立ちます。照会が本来プロバイダ経由で外に出る場合、遠端側のリゾルバが問い合わせを暗号化経路の内側に留めます。DNSサーバのアドレスが、端末に対して一度だけ選ぶ全体設定ではなく、接続ポリシーの一部として届くのはそのためです。

アドレスそのものは何も決めません。リゾルバはそこへの経路があるときだけ応答できます。最も多い故障は、トンネルが上がっている間しか到達できないリゾルバです。トンネルが落ちてポリシーが残ると、照会は経路のないアドレスへ向かい、症状はきれいなエラーではなくタイムアウトになります。この違いは次のテスト結果を読むときに重要です。タイムアウトは、まったく関係のない転送設定へ人を向かわせるからです。

応答を比べる前に二つの設計を比べる

全トンネルと分割DNSは正反対の期待を生みますが、どちらも不具合ではありません。全トンネルではすべての照会がプロバイダや企業のリゾルバへ移りうるので、接続後に公開名が違う応答を返すのは想定内です。分割DNSでは一覧にあるドメインだけが非公開リゾルバへ行き、それ以外はローカルに残ります。Windowsではドメイン一覧が Name Resolution Policy Table に、macOSではDNS設定の一致ドメインに、systemd-resolved のホストではリンクごとのルーティングドメインにあります。

まず行うべきはこの比較です。何を不具合と見なすかが決まるからです。分割DNSでは、新しいリゾルバから応答する公開名こそ調べる価値があり、正しく応答する内部名はシステムが仕事をしているだけです。全トンネルでは、いまもプロバイダのリゾルバから応答する公開名が異常です。Microsoft の VPN 名前解決に関するドキュメント は、この規則の Windows での順序を説明し、一致するポリシー項目がアダプタ自身のサーバより先に参照される仕組みにも触れています。

部屋には忘れやすい第三のリゾルバがあります。ブラウザの安全なDNSは自分で名前を解決し、トンネルが OS のポリシーを変えた後も応答を続けられます。つまりページが読み込めたことはブラウザのリゾルバが動いた証拠であって、プロファイルが適用された証拠ではありません。ブラウザの表示だけを比べていると、半分の時間は違う層を試していることになります。

変える要素を一つにして基準を記録する

トンネルを変えます。同じ手順で名前、ツール、検索サフィックスまで変えないでください。照会が許されている名前を選び、使ったアプリケーションを書き留め、返ってきたアドレスか正確なエラーのどちらかを記録します。Windows では Get-DnsClientServerAddress -AddressFamily IPv4 がアダプタごとのサーバを、Get-DnsClientNrptPolicy がポリシー項目を出力します。systemd-resolved を使う Linux では resolvectl status がリンクごとの DNS サーバとルーティングドメインを示します。macOS では scutil --dns がシステムの実際に従うリゾルバ順を出力します。

そのうえでクライアントの通常の操作で接続し、まったく同じコマンドを繰り返します。最初の出力は記憶ではなく保存してください。比較が要点であり、キャッシュを消した後の二度目の読み取りはすでに別の測定だからです。基準をブラウザを前面にして取り、接続後の実行をターミナルで行うなら、比べているのは二つのリゾルバであって、一つのリゾルバの二つの状態ではありません。

明示的な問い合わせとアプリの照会は別のテスト

特定のサーバに nslookup name 10.20.0.1 や dig @10.20.0.1 name で問い合わせると分かるのは一つだけです。名指ししたサーバに到達できるとき、それが応答するということです。選択の論理は完全に迂回するので、システムがこの名前にそのサーバを選んだかどうかは分かりません。割り当てられたリゾルバに到達できるかの確認に使い、ポリシーの確認には使わないでください。

ローカルリゾルバ経由の照会は選択を実際に働かせます。resolvectl query name は同じルーティングドメインの規則をたどり、どのプロトコルが応答したかを報告します。Windows の Resolve-DnsName はポリシーテーブルとクライアントキャッシュを通り、scutil --dns は照会が従う順序を示します。両方を実行し、メモの別の列に分けて残してください。明示的な問い合わせが成功してアプリの照会が失敗するなら、それは経路か選択の問題であり、動作を拒むリゾルバではありません。

キャッシュはあなたと応答の間に立ちます。OS、ローカルのスタブリゾルバ、ブラウザ、否定キャッシュがすべて結果を保持するので、パケットが一つも端末を出ずに照会が成功することがあります。何かを消す前に結果を記録してください。ipconfig /flushdns、resolvectl flush-caches、macOS なら sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder です。この段階で広範なネットワークリセットは避けてください。集めている証拠を壊してしまいます。

その違いが意味すること

記録した二行を比べ、設定に一つも触れる前に変化を分類してください。

Observation after connectMost likely causeNext step
Answer moves to a private address rangeExpected under split DNS or a private zoneConfirm the suffix is in the effective policy, then test the service
Lookup times out while connected, works after disconnectThe assigned resolver has no route from this machineProbe it with an explicit query, then re-read the policy
Internal name fails, public names workWrong namespace or a suffix missing from the policyQuery the fully qualified name and check the domain list per platform
Internal name returns a public addressSplit DNS not applied; a public resolver answeredCheck browser secure DNS first, then the per-link domain list

一行は強調に値します。解決する名前は動くサービスではなく、DNSの成功が言えるのはアドレスが見つかったことだけです。転送やファイアウォール規則、アカウントがそのサービスを使えるかどうかは何も語りません。失敗がひとりでに去ったと決めつけず、実際のアプリケーションを試して締めくくってください。

基準に戻し、検証する

プロセスを殺すのではなくクライアント自身の操作で切断し、同じ三つのコマンドを読み直します。リンクごとのサーバ、ポリシー項目、テスト名の応答は、先に書いた基準へ戻るはずです。きれいに切断した後に残るポリシー項目は記録に値する実際の不具合です。生成されたリゾルバファイルを手で編集するのが悪い習慣である理由も同じで、ファイルは書き直されて編集は消えるか、編集が残って経路のないリゾルバを固定してしまいます。

この一覧を一度、順番にたどってください。どの設計をプロファイルが実装しているかを、結果を判断する前に決めます。二回の実行で名前、ツール、サフィックスを固定します。明示的な問い合わせとアプリの照会を分けます。応答だけでなく有効なポリシーを読みます。比較を書き終えてから最後にキャッシュを消します。実際のアプリケーションで検証し、その後一度再起動して、切断状態がまだきれいか確かめます。

関連記事