ある利用者は、VPN 経由でイントラネットのホスト名が解決しないと報告している。同じノート PC からの二件目の報告では、漏えいテストで依然としてローカルのリゾルバーが応答したクエリが表示されるという。一つの問題のように聞こえるが実際は二つであり、証拠も異なり、前者に対するいつもの修復が後者を悪化させる。設定に触る前に、この二つを切り分けよう。

一つの障害ではない二つの症状

社内名の解決に失敗するとは、その名前への答えを持たない場所へ問い合わせが行ったということだ。クエリがトンネルの外へ出るとは、答えが得られる状況でも問い合わせが間違った場所へ行ったということだ。これは正反対の故障であり、一つは答えの欠落、もう一つは余分な宛先だ。

罠は、社内リゾルバーをどこにでも追加すると前者は直り、後者が確実に起きることだ。公開リゾルバーをどこにでも追加すると逆になる。

両方の観察をタイムスタンプ付きで記録し、その後で以下の四つの確認を順番に進めよう。

どのアダプターのリゾルバーが問い合わせを受けるか

Windows では、DNS クライアントはアダプターのバインド順に従ってサーバーを選び、トンネルのアダプターが自動的に先頭になるわけではない。アダプターの詳細設定を開き、リモートアクセス接続を物理アダプターより上へ移動し、それから再接続して新しいセッションに変更を反映させる。

バインド順は前半にすぎない。クライアントはどの名前がそのアダプターに属するかも知る必要があり、それは順序ではなくサフィックスの問題だ。

動作しているマシンの ipconfig /all を、トンネルを上げた状態で取得したノート PC のものと並べてみよう。動作しているマシンでは社内アダプターに接続固有の DNS サフィックスが表示されるはずで、ノート PC のトンネル側には何も表示されないことがある。この違いは、サフィックスがなければ短い名前が社内リゾルバーの受け持つゾーンへ補完されないために、「サーバーはすぐそこにあるのに名前が解決しない」という報告の一類を説明する。

短い名前は経路より先にサフィックスを必要とする

修飾なしのホスト名を入力すると、リゾルバーはドメインを推測することになる。その推測は接続に付いたサフィックスの一覧から来ており、その一覧が空ならクエリは単一ラベルとして出ていき、どのプライベートゾーンにも一致しない。

動作しているマシンのサフィックスを、DNS タブにある VPN アダプターの IPv4 プロパティへコピーし、それから再接続する。Linux では相当するのはトンネルリンクの検索ドメインで、systemd-resolved はこれをグローバルではなくリンクごとに公開する。

二つの設定はメモの中で分けておこう。サフィックスは何を問い合わせるかを変え、リゾルバーのアドレスは誰に問い合わせるかを変える。片方を直しても、もう片方が誤っていれば結果は無作為に見える。

まずリゾルバーに直接尋ね、次に名前を尋ねる

社内リゾルバーへの直接クエリ は、クライアントのリゾルバー選択を完全に迂回するため、名前の問題と経路の問題を切り分ける。

nslookup intranet.corp.example 10.20.0.53
nslookup intranet
resolvectl status

最初のコマンドは、特定のサーバーに完全修飾名を尋ねる。答えが返れば、リゾルバーとそこへの経路は正常で、障害は選択かサフィックスにある。タイムアウトすれば、アドレスが誤っているか到達できず、問題は DNS ではなくルーティングだ。二番目のコマンドは短い名前で何が起きるかを示し、三番目は systemd ホストでリンクごとのリゾルバー設定を表示する。

未知の名前に対してそれを返すネットワークもあるので、ワイルドカード応答に注意しよう。もっともらしく見える応答は、意図したサーバーが答えた証拠にはならないので、返ってきたアドレスを社内サービスが実際に使うアドレスと比べる。そのアドレスがパーキングページやプロキシのものであれば、リゾルバーは答えたが答えは自分のものではない。この区別で、ずっと正常だったトンネルを追いかける一時間が節約できる。

Linux では、/etc/resolv.conf を書き換える VPN クライアントが、ローカルのリゾルバーを完全に置き換えてしまう。vpnc は DNSUpdate no を公開してそれを止められ、systemd-resolved は列挙したドメインだけをトンネルリンクへルーティングできる。どちらの方法でも、公開名はローカルのリゾルバーに残しつつ、社内名はオフィスへ送ることになる。

リークはチェックボックスではなくルール

名前解決はポート 53 への UDP のやり取りなので、ウェブのトラフィックは通すが UDP は通さないトンネルは、クエリを物理的な経路に残してしまう。公開名を解決している間に物理 NIC でキャプチャして証明しよう。そのインターフェース上で読める形でクエリが見えれば、トンネルはそれを運んでいない。

sudo tcpdump -ni eth0 -c 20 'udp port 53'
resolvectl query example.com

そのインターフェース上で読める形でクエリが現れるなら、トンネルはそれを運んでいない。修復は、VPN が配布したリゾルバーへのポート 53 だけを許可して他の宛先を落とすルールと、配布されたオプションを黙って捨てないクライアント設定だ。

その最後の部分は見た目より重要だ。OpenVPN を route-nopull で起動すると、プルのフィルターを広げて残さない限り、配布された DNS オプションはルートと一緒に消えてしまう。さらに dhcp-option DNS を無視するクライアントは、以前使っていた設定をそのまま使い続ける。サーバー側の変更は、リゾルバーの一覧がトンネルが上がるときに渡され、古いセッションは古い状態を表示し続けるため、新しいセッションでないと反映されない。

チケットを閉じる前に、実際に観測したのがどちらの故障かを記録しよう。社内の答えがない場合と、クエリがトンネルを抜ける場合とでは必要な修復が異なり、前者を直すサフィックスの変更が後者を静かに悪化させることがある。次にチケットを引き継ぐ人はラベルを信じるので、ラベルは正確にしておこう。

関連記事