プライベート DNS 名が VPN クライアントで失敗する理由と確認すべき場所
クライアントがリゾルバーを信頼し、サフィックスが限定され、応答がトンネルを通って戻れるときだけプライベート名は解決できます。
ホテルの部屋でノート PC を開き、クライアントを起動し、社内ファイルサーバーの名前を入力しても何も返ってきません。トンネルは接続済みと表示し、同じサブネット内のアドレスへの ping は今も応答するので、通信自体は問題ありません。失敗しているのは名前だけで、この差は問題を二か所に絞ります。クライアントがどのリゾルバーに聞いたのか、そして得た応答がトンネルを通って戻れるのか。片方を直してもう片方を飛ばせば、障害はただ場所を移すだけです。
プロファイルを編集する前に、クライアントが名前をどう扱うかを確認します。Linux では resolvectl query files.corp.example が、どのリンクとどのリゾルバーが応答を作ったかを表示します。Windows では Resolve-DnsName files.corp.example が、応答したサーバーと返したアドレスを表示します。
何かを変える前に応答を読む
名前が数ミリ秒で NXDOMAIN として返るなら、問い合わせはあなたのゾーンに届いておらず、公共のリゾルバーかホテルのリゾルバーが代わりに答えています。長い間を置いて返るなら、途中の何かが UDP ポート 53 を落としていて、クライアントは最後に代替へ落ちています。正しいアドレスで応答するのに接続が詰まるなら、名前解決は正常で、問題は経路かサービス自体にあります。
この三分割で一時間の当て推量が節約できます。VPN に触れる必要があるかどうかも分かります。正しいプライベートアドレスに解決する名前はすでにリゾルバーの経路を証明しているので、残る作業はデータ経路にあります。
トンネルの内側からリゾルバーを配る
クライアントは二つのグループに分かれます。一つは接続確立時にサーバーからリゾルバーを与えられます。もう一つは設定をローカルファイルに持ち、どのゲートウェイも遠隔では変えられません。
OpenVPN は前者です。サーバー側では push "dhcp-option DNS 10.8.0.53" と push "dhcp-option DOMAIN corp.example" が制御チャネルを流れますが、クライアント設定で pull が有効なままの場合だけです。手で書き換えて pull-filter ignore "dhcp-option" を持つクライアントはそれらを決して見ません。この一行が「サーバーは押し出しているのにノート PC が同意しない」という驚くほど多くの事例を説明します。
WireGuard は後者で、このプロトコルにはオプション交渉がまったくありません。リゾルバーと検索ドメインはクライアント自身の [Interface] ブロックに DNS = 10.8.0.53, corp.example の形で入ります。wg-quick はそれを resolvconf か systemd-resolved 経由で適用し、Windows では公式クライアントがトンネルが上がっている間だけ存在する NRPT 規則をインストールします。Get-DnsClientNrptPolicy がそれらを列挙するので、クライアントがあなたのファイルを実際に適用したかどうかを素早く確認できます。
IPsec/IKEv2 は中間です。strongSwan の attr プラグインはプールから取った DNS サーバーを返せますし、Windows クライアントは通常それを受け入れますが、自前のネームサーバーを固定したプロファイルはゲートウェイの提案すべてに勝ちます。Linux クライアントでの同等の手作業は resolvectl dns wg0 10.8.0.53 の後に resolvectl domain wg0 '~corp.example' です。どちらもインターフェースとともに消えるので、トンネル限定の設定としてはまさに望ましい挙動です。
すべての問い合わせを飲み込むのではなくサフィックスを限定する
クライアントのリゾルバー一覧を丸ごと社内サーバーに向けるのは簡単で、たいてい間違いです。そうすると公共の名前がすべてデータセンターの出口から解決され、CDN は遠いアドレスを返し、リゾルバーが一度落ちれば利用者の閲覧も巻き添えになります。
内側にはプライベートなサフィックスだけを送ります。systemd-resolved では ~ で始まるドメインは経路指定専用なので、~corp.example はそのサフィックス配下の問い合わせがそのリンクのサーバーへ行き、それ以外は物理ネットワークを使い続けるという意味です。Windows は名前空間に限定した NRPT 規則で同じことをし、macOS は /etc/resolver/ 配下の補助リゾルバーファイルで行います。
マルチキャスト名には専用の答えが必要です。.local 名は設計上リンクローカル(RFC 6762)で、ポイントツーポイントの tun インターフェースはそのマルチキャストグループを運びません。だから公共のリゾルバーを足しても公開されず、社内のユニキャストリゾルバーに尋ねても NXDOMAIN が返ります。avahi のようなリフレクターをリフレクターモードで動かせば二つのセグメントを橋渡しできますが、それはクライアントが要求できるものではないサーバー側の判断です。プリンターや NAS に名前で届く必要があるなら、代わりに自分のゾーンに A レコードを置いてください。
応答が戻れることを証明する
到達できないアドレスを指す正しい応答は、経路を確認するまでリゾルバーの問題とまったく同じに見えます。応答がどこへ行くのかをカーネルに尋ねます。ip route get 10.20.5.20 はインターフェースと、より有用なことに使う送信元アドレスを示します。
リゾルバーのアドレスそのものを見ます。DNS = 10.8.0.53 の隣に AllowedIPs = 10.20.0.0/16 があるクライアントは、問い合わせを物理 NIC から外へ出し、そこで静かに死にます。リゾルバーがトンネルの主張するどのプレフィックスにも入っていないからです。この不一致がこの分野で最も多い単一要因の障害で、DNS 設定と許可プレフィックスを行ごとに突き合わせない限り見えません。
範囲が重なると逆向きの障害になります。応答は正しく、経路もあり、それなのに間違ったホストを指すのは、自宅の 192.168.0.0/24 が同じ範囲へのトンネルの経路より具体的だからで、片側を採番し直すかより狭い経路を押し込んだうえで、サービスホストのファイアウォールと戻り経路を確認してください。strongSwan の 転送 に関する記述はその経路の sysctl 側を扱っています。
証明書は別種の身元確認で、人はそれを DNS のせいにします。ブラウザーが解決エラーではなく名前の不一致を報告するなら、名前解決はすでに成功しており、直すべきは証明書の SAN です。HTTPS は名前に対して試し、裸の IP に対しては決して試さないでください。
ゲートウェイではなくクライアントから再テストする
利用者が不満を言うアプリの中で試してください。コマンドラインの検索はブラウザーが同じ経路を通ることの証明にはなりません。Chrome の安全な DNS と Firefox の network.trr.mode はシステムのリゾルバーを完全に迂回でき、そうなるとプライベート名は失敗するか公共のリゾルバーへ漏れます。resolvectl query と手で実行した dig @10.8.0.53 files.corp.example を比べれば、どちらが起きたか分かります。
そのうえで直ったと言う前に切断と再接続を行います。インターフェースに手で入れた設定はインターフェースとともに消え、残ったローカル編集のせいで正しく見えていただけのプロファイルは次の起動で失敗します。
次のマシン向けの短いチェックリストは、名前がトンネルのリゾルバーで解決すること、サフィックスが全体ではなく限定されていること、リゾルバーのアドレスが許可プレフィックス内にあること、応答のホストがサービスポートで応答すること、証明書が利用者の入力した名前を覆っていることです。