OpenVPN クライアントが強制終了された後も DNS が解決を続けられなくなり、最初に思いつくのは /etc/resolv.conf を書き換えることです。その編集は動作中のリゾルバを壊すことがあり、本当の古い状態は別の場所にあります。まず決めるべき問いは、トンネルが設定した DNS を誰が所有しているのか、そしてクリーンアップを飛ばした終了が実際に重要だったのかどうかです。

修復を決めるのは三つの条件です。プロセスを終わらせたシグナル、設定を受け取ったリゾルバの構成要素、そしてトンネルのリンクがまだ存在するかどうかです。この順に答えれば、通常はグローバルなファイルに触れずに修正が決まります。

どの種類の終了が起きたのかを判断する

Community 版の OpenVPN では、SIGINT も SIGTERM も穏やかな終了要求です。SIGKILL は捕捉できません。ブロックも処理もできないため、シャットダウン処理が実行される機会はありません。前面の端末で通常の Ctrl+C を押すと SIGINT が発生しますが、待機を諦めたスーパーバイザは通常 SIGKILL へエスカレートします。違いが重要なのは、二番目の場合だけフックが飛ばされたことが確実になるからです。

screen や tmux の内部で実行しても、Ctrl+C が送るシグナルは変わりません。端末が通常どうするかではなく、プロセスが実際に何を受け取ったかを確認してください。

サービスや接続マネージャがトンネルを実行している場合は、pid を kill するのではなく、その接続を所有者経由で停止してください。マネージャはプロセスを再び起動し、新しいトンネルと混乱したリゾルバ状態を残すことがあります。単独のプロセスは、クリーンアップを実行するために通常の終了要求だけで十分です。

リゾルバを誰が所有しているかを判断する

systemd-resolved、resolvconf 形式のスクリプト、単純なファイル書き換えは三つの異なる所有者です。一つ目はリンク単位の設定をメモリに保持し、インターフェースが消えると破棄します。二つ目は何かが削除するまで残る記録を保持します。三つ目はファイルを書き、復元を書いた人に任せます。

修復コマンドを選ぶ前に所有者を特定する。同じ症状でも、どれが使われているかによって三つの異なる正解があります。

NetworkManager が管理する VPN がすでにリゾルバの変更を所有していることがあります。その上に二つ目のヘルパーを足すと、同じリンクを奪い合う二つの所有者が生まれ、敗者の状態が次の再接続で再び現れます。マネージャが担当しているなら、スクリプトではなくマネージャ側で設定を直してください。

down フックにできることとできないこと

スクリプト down は TUN/TAP デバイスが閉じた後に一度だけ実行されます。追加すると down-pre はその順序を反転し、デバイスがまだ存在する間にスクリプトを実行します。これは生きたリンクを必要とするヘルパーが求める動作です。

どちらのディレクティブも SIGKILL 後にフックを実行させません。特権も down-pre では復元されません。デーモンが user や group に降りるか chroot に入ると、フックはそれが残したアクセス権で実行されます。呼び出されたフックがリゾルバの更新に失敗することもあります。OpenVPN リファレンス はシグナルとコールバックのライフサイクルを扱っています。

プロセスの終了ステータスの隣で、フック自身のエラーを確認してください。クリーンアップの欠落とクリーンアップの失敗は、リゾルバでは同じに見え、ログでは異なって見えます。

実際に残っている状態を確認する

systemd-resolved を使うシステムでは、resolvectl status により、どのリンクがまだ VPN の DNS サーバーやルーティングドメインを運んでいるかがわかります。そのリンクは、すでに消えた接続のものか、まだ稼働中の別のトンネルのものかもしれません。

消えるインターフェースはリンク単位の設定を一緒に持っていくため、飛ばされたフックがきれいな DNS と共存することもあります。リンクがまだ登録されていて、停止した接続だけが所有しているなら、所有するマネージャがそれを削除すべきです。古いスクリプトがグローバルなリゾルバファイルを書き換えていた場合は、代わりにそのスクリプトの文書化された復元手順を探してください。

別のリンクを奪わずに復旧する

リンク単位の設定を自分で管理する場合、resolvectl revert はリンク名を受け取り、そのインターフェースの実行時 DNS 設定を消去します。これはプロファイル編集ではなく実行時の操作なので、永続的な接続設定はそのまま残ります。間違ったリンクを指定すると動作中のトンネルの DNS を消してしまうため、名前はステータスの出力から取ります。

編集する前に /etc/resolv.conf が管理されたシンボリックリンクであることを確認し、その後もう一度クライアントを通常どおり停止して DNS を再度確認してください。二度目の停止で片付くなら、以前の問題は設定ではなく強制終了でした。

関連記事