一つのアダプターに二つのリゾルバーを並べると、あるドメインを一方のサーバーへ、別のドメインをもう一方へ送れるように見えますが、リゾルバーの一覧はそういうふうには動きません。Windowsは名前で解決し、どのサーバーに問い合わせるかという判断は、順序付きのアドレス一覧ではなくポリシーオブジェクトから来ます。置き換えるべき思考モデルは待ち行列です。ドメインA用の一番目のサーバーやドメインB用の二番目のサーバーというものはありません。名前空間ごとにサーバーを明示するルール群があり、そのルールが存在すればアダプターの一覧は興味の対象ではなくなります。

誤解: 二つのアドレスが二つのドメインを分ける

この信念が残るのは、一つのサーバーが何でも応答し、二つ目が単なるフォールバックであるときに偶然うまくいくからです。クライアントは最初のサーバーに問い合わせ、そのサーバーが転送または再帰を行い、応答が返りますが、どちらのリゾルバーが実際にゾーンを保持していたかは誰も気にしません。二つの名前空間が相互転送のない別々のプライベートゾーンに置かれた瞬間に幻想は崩れます。最初のサーバーはそのとき、名前が存在しないと権威的に答えるからです。最初のサーバーからの否定応答はフォールバックを起動しません。クライアントは失敗ではなく決定的な応答を受け取っているからです。

順序付きの一覧にはドメインという概念がないため、意図を表現できません。一覧が実際に制御するのは、どのサーバーを最初に問い合わせ、どちらを二つ目に試すかであり、そのどちらの答えもすべての名前に等しく適用されます。

Windowsが選択に実際に使うもの

名前解決ポリシーテーブルは、名前を構成済みの名前空間と照合し、その一致に対するサーバーとオプションを選択します。ルールはローカルで構成することも、グループポリシーで配信することも、VPNプロファイルから提供することもでき、実効ポリシーは単一の一覧ではなく組み合わせです。だから最初の診断は常に実効状態です。ローカルで作ったルールが管理ポリシーに負けると、構成が示すのとはまったく違う動作をする実験環境になります。ルールは具体性でも照合されるため、広い名前空間のエントリが狭いエントリを覆い隠すことがあり、それは構成済み項目の一覧からは見えません。実効順序を読むことが、どのルールが勝つかを知る唯一の方法です。

Get-DnsClientNrptRule
Get-DnsClientNrptPolicy -Effective

最初のコマンドはマシン上で構成されている内容を一覧表示し、二つ目はクライアントが実際に適用する内容を、他の場所から来たエントリも含めて示します。実効出力に管理された名前空間が含まれているなら、変更を依頼すべき正しい場所はそのポリシーの所有者であり、ローカルのルール一覧ではありません。どちらのコマンドも状態を読むだけなので、誰かが変更に同意する前に実行しても何も失いません。

名前空間ごとに一つのルール、オブジェクトを保持する

実効状態を理解したら、名前空間ごとに一つのルールを作成し、各コマンドが返すオブジェクトを保存します。表示名は人間向けのラベルであり、返されたオブジェクト内の一意な識別子が、後で確実に削除する対象になります。名前空間とリゾルバーを記録する同じ変更メモに両方の識別子を書き込みます。作成したセッションが後片付けをするセッションになるとは限らないからです。

$svcRule = Add-DnsClientNrptRule -Namespace ".svc.internal.example" -NameServers "10.60.0.53" -DisplayName "VPN lab services" -PassThru
$resRule = Add-DnsClientNrptRule -Namespace ".research.internal.example" -NameServers "10.61.0.53" -DisplayName "VPN lab research" -PassThru
$svcRule | Select-Object Name, Namespace, NameServers
$resRule | Select-Object Name, Namespace, NameServers

先頭のドットはサフィックス一致を意味するため、ルールはapp.svc.internal.exampleとその配下のすべてを対象にします。ここにある二つのアドレスはこの実験環境自身のルーティング計画に属し、ルールはゾーンを作らず、ルートをインストールせず、最終的に接続するアプリケーションを承認するものでもなく、そしてAdd-DnsClientNrptRuleのリファレンスには、どのパラメーターが何をするかが正確に記載されています。

これらのコマンドがしないことに注意してください:マシン全体に適用され、VPNセッションに限定されません。また、ウィンドウを閉じても残ります。これを忘れた実験環境は、トンネルが消えた後にポリシーを残します。

クライアントがサーバーを選んだことを証明する

特定のサーバーに名前を知っているか尋ねることは、そのサーバーが応答できることを証明しますが、クライアントがそのサーバーを選んだという主張とは同じではありません。重要なテストは、通常のクライアント経路で実際の名前を解決し、その後どのリゾルバーが処理したかを確認するもので、理想的にはルートを提供するトンネルが上がっている間に行います。トンネルが落ちている場合、正しくスコープされたルールでも到達できないサーバーを指したままで、それはポリシーではなくルーティングの問題です。後で区別できるように、両方の状態をテストしてください。

Resolve-DnsName app.svc.internal.example
Resolve-DnsName build.research.internal.example
Resolve-DnsName app.svc.internal.example -DnsOnly -NoHostsFile

ルールが存在する前の期間のキャッシュされた応答に注意し、独自の暗号化DNSでシステムリゾルバーを完全に迂回するアプリケーションにも注意してください。検索サフィックスはさらに別の機能です。ルールは完全な名前に対してリゾルバーを選べますが、裸のホスト名をその名前空間に展開するようWindowsに教えるわけではありません。

作成したものだけを削除する

後片付けは、実験環境が教訓話になるところです。マシン上のすべてのルールを削除するのは速く、他の誰かが依存するポリシーまで取り除いてしまうので、ルール作成時に取得した識別子を使い、後で実効状態を読み直してマシンが元の状態に戻ったことを確認します。作成したセッションがもうない場合、変更メモが識別子の存在する唯一の場所です。だから最初のコマンドを実行する前に書き留めるのであり、後ではありません。

Remove-DnsClientNrptRule -Name $svcRule.Name -Force
Remove-DnsClientNrptRule -Name $resRule.Name -Force
Get-DnsClientNrptPolicy -Effective

実験環境ではなく展開の場合、有効期間の問いはルールと同じくらい重要です。VPNプロファイルは名前空間ルールを運び、接続後も保持するかどうかを選べます。リゾルバーに到達できない間に保持されるルールは、クライアントに死んだサーバーを優先させ、接続スコープのルールはトンネルとともに消えます。これらの動作のどれがサービスに必要かを決め、ルールの所有者を明示し、権限の分割をプロファイルの隣に文書化しておき、誰かの実験環境の記憶に置かないでください。

関連記事