OpenVPN がプッシュした DNS が無視される:どのコンポーネントが適用するのか
プッシュされた DNS オプションは、環境変数としてしかクライアントに届きません。Linux、Windows、macOS で名前解決を所有するのは誰かを確認し、経路を検証してください。
ログにはサーバーがプッシュしたオプションがあり、トンネルも上がっているのに、内部名の解決は失敗し続ける。リゾルバーへ直接問い合わせれば応答するのだからサーバーは正常だが、どのアプリケーションもローカルルーターに問い続けている。クライアントに届いたのは提案であってリゾルバーの変更ではなく、名前解決を所有するコンポーネントは Linux、Windows、macOS で異なる。オプションと所有者を切り分ければ、ほぼすべての報告は四つの障害に収まる。フックがない、二つのフックが競合している、分割 DNS が設計どおりに動いている、短い名前に必要なのはサーバーではなくサフィックスである、のいずれかだ。
プッシュされたオプションは提案であり、インストールではない
サーバー側では二つのディレクティブが効果ではなく意図を表す:
push "dhcp-option DNS 10.8.0.1"
push "dhcp-option DOMAIN corp.example"
クライアントが受け取るのは設定済みのリゾルバーではない。環境変数、 foreign_option_1 以降を受け取り、各行につき一つずつで、ローカルの何かがそれを読んで OS のリゾルバー状態を書き換えなければならない。Linux では既定で何もせず、それゆえ正しいサーバーと接続済みクライアントでも LAN 経由の解決が続く。
両端の間には三つの段階がある:プッシュが届き、クライアントが公開し、フックが適用する。中間段階はクライアントのログ、最終段階はリゾルバーの状態で読み、決して逆にしないこと(ログの一行が証明するのは最初の二つだけだ)。
プッシュが届いたことを確認し、所有者を見つける
まず起動方法を特定する。素の openvpn コマンドか、systemd のインスタンスか、NetworkManager か、ベンダーのクライアントか。これでフックを置ける場所が決まる。systemd-resolved のあるホストでは、 resolvectl status が各リンクを実際に使う DNS サーバーと検索ドメインとともに一覧し、トンネルのリンク名が常に tun0 とは限らない。
プッシュされたアドレスがログにあってどのリンクにもなければ、統合が欠けている。リンクにありながら問い合わせが別へ出ていくなら、問題は どの問い合わせがそのリンクを選ぶかにある。NetworkManager は dns=dnsmasq を /etc/NetworkManager/NetworkManager.conf に置くとローカルのフォワーダーを動かし、分割 DNS を意図的に実装する。VPN ドメイン内の名前は VPN リゾルバーへ行き、それ以外は従来の経路を保つ。すべての通信が移ると期待しているとこの挙動は障害に見えるが、接続ごとの設定を nmcli connection show "My VPN"で確認し、 ipv4.dns と ipv4.dns-search がデバイスの表示の背後にある値を持つことを確かめてから壊れていると断じること。本当にすべての問い合わせを VPN リゾルバーへ届けるべきなら、 dns=dnsmasq を NetworkManager.conf から外して NetworkManager を再起動すると、名前解決は接続設定に戻る。そうでなければ分割 DNS を維持し、プッシュされたドメイン一覧を直す。
Linux:オプションをリゾルバーに渡す
ディストリビューションのパッケージはこのためのフックを同梱しており、クライアントにその実行を許可する必要がある。systemd-resolved のないホストでの典型的な構成は次のとおり:
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf
systemd-resolved があると、古い resolv.conf スクリプトは重要な何も変えないかもしれない。stub リゾルバーがリンクごとの状態を持つからだ。 update-systemd-resolved ヘルパーは up-restart と down-preを使うフック形式を文書化しており、これはインターフェースが一回の接続試行より長く生きる場合に意味を持つ。どれを選ぶにせよ、状態を所有するコンポーネントは一つでなければならない。NetworkManager の隣に無関係なフックを足すと同一リンクに書き手が二人でき、結果は設定ではなく順序に左右される。
NetworkManager がプッシュされたオプションを完全に無視し、接続の IPv4 設定にサーバーアドレスを入力して初めてリゾルバー状態に現れた、という事例もある。スクリプトを書き直す前に試す価値がある。問題がシェルのフックから、トンネルをすでに運ぶ接続プロファイルへ移るからだ。
Windows と macOS は別の部分を適用する
Windows クライアントは VPN アダプターの DNS サーバーを確かに設定するが、Windows は依然メトリックでインターフェースを選び、短い名前を展開するにはサフィックスが要る。プロファイルではなくアダプターの状態を確認すること:
Get-DnsClientServerAddress -InterfaceAlias "My VPN"
Get-DnsClientNrptPolicy
アドレスがなければ次で設定し、 Set-DnsClientServerAddress -InterfaceAlias "My VPN" -ServerAddresses 10.8.0.1 のちアダプターの IPv4 プロパティにサフィックスを追加して fileserver となるようにする。 fileserver.corp.exampleマシン全体の SearchList の値は Tcpip\Parameters の下でも同じ働きをする。長い名前は解決し裸の名前は解決しない場合、リゾルバーはすでに正しく、検索リストが原因だ。修正は順に、 DOMAIN をプッシュしてクライアントにサフィックスを学ばせ、そのサフィックスをアダプターか接続の検索リストに加え、暫定策として名前を hosts に固定する。Windows なら LMHOSTS でもよい。NetBIOS の参照はルーターを越えないため、社内 LAN で短い名前を見つけるブロードキャストはトンネルのクライアントには決して届かない。
block-outside-dns block-outside-dns は Windows クライアントの挙動であり、移植可能なプロファイル行ではない。Linux や macOS のプロファイルに写してもそこで再現はしない。Windows で公開名は解決し内部名が失敗するなら、詳細設定のアダプター順序を ipconfig /all と比較すること。macOS ではサービスごとのリゾルバー順序はシステムに属するので、 scutil --dns を使ってどのドメインにどのリゾルバーが問われるかを見て、報告された単一のプロファイル修正は一般的ではなくクライアント依存として扱う。
同じノート PC 上の仮想マシンはこれを何も継承しない。ゲストに内部ドメイン用の独自のリゾルバー項目を与えるか、ハイパーバイザーの NAT にホスト経由で問い合わせを転送させる。後者はホストのトンネルが上がっている間だけ正しい。
履歴が三つ目の原因だ。以前のプロファイルの DNS サーバーやサフィックス設定は再接続を生き延びることがある。アダプターが正しく見えるのに照会が失敗するなら、稼働中のアダプターを Get-VpnConnection と比べ、サーバーに触れる前に古い項目を消すか上書きすること。
問い合わせがどこへ行ったかを証明する
一回の照会中のキャプチャが決着をつける: tcpdump -ni eth0 port 53 が物理インターフェース上の問い合わせを示すなら、それはトンネルの外へ出ており、リゾルバーは切り替わっていない。 dig @10.8.0.1 name.corp.example は残る二つの場合を分ける。直接の問い合わせが応答すればリゾルバーは動いておりクライアントは使っていない;タイムアウトするならリゾルバーはトンネル経由で到達できず、ローカルの変更では解決しない。
まだ使われているリゾルバーがプロバイダー配布のものなら、トンネルは通信を暗号化しても名前はそのプロバイダーに見えている。これは機能ではなく漏えいの問題で、同じキャプチャが答える。物理インターフェース上の問い合わせはトンネルの外の誰かへ向かっている。
到達性には VPN ホストのファイアウォールも含まれ、プールからの UDP と TCP 53 を許可する必要がある。閉じたポートは壊れたプッシュと全く同じに見え、トンネル網の内側からしか応答しないリゾルバーも同じだ。一度切断して再接続した後にキャプチャを繰り返すこと。最初の接続で現れ二回目で消える設定は、欠けたオプションではなくフックのライフサイクル障害である。
所有者を一つに保ち、順に検証する
推定したトンネル状態でアダプターの DNS を書き換えるスクリプトは、プロファイルがすでに持つ設定を二重化し、推測が初めて外れたときに静かに失敗する。接続自身の DNS 設定か、文書化された一つのフックを選び、どちらを選んだかを記録して次の人が二つ目を足さないようにする。
四つの確認でループを閉じる。プッシュされたアドレスがトンネルのリンクにあること、内部名が完全修飾名として解決すること、同じ名前がサフィックスなしで解決すること、そして再接続後も両方が成り立つこと。一回のキャプチャで四つのどれが失敗したか分かる。 OpenVPN 2.6 のマニュアル は dhcp-option とスクリプトディレクティブをプラットフォーム別の注記とともに列挙している。