同じルートを奪い合う二つのスクリプトは、Linux VPN の問題がルーティングのバグとして報告されるときの典型的な形です。あるコンポーネントがトンネルデバイスを作り、別のコンポーネントがデフォルトルートを追加し、三つ目がリゾルバの設定を書き換え、四つ目がファイアウォールのルールを再読み込みします。どれも他の仕事を取り消すことができ、勝者は単に最後に実行されたものです。答える価値のある問いは、どのパッケージを入れるかではなく、状態のどの部分をどのコンポーネントが所管するかです。

その地図を一度書けば、再接続の失敗のほとんどは謎ではなくなります。重要な対象は四つです。デバイスとそのアドレス、ルートとポリシールール、DNS 設定、そしてファイアウォールです。

デバイスとそのアドレス

トンネルデバイスは、プロファイルを知っているマネージャが作るか、誰かが手動で起動したデーモンが作ります。どちらの構成も単独では機能しますが、混ぜると機能しません。NetworkManager がプロファイルを所有しているなら、デバイスも所有させ、同じトンネル名に対して管理外の OpenVPN プロセスを起動しないでください。

セッションが終わったときに誰がデバイスを削除するかを記録します。セッションより長く生き残るデバイスは、古いアドレスとその後の混乱の最も一般的な原因です。

ルートとポリシールール

ルートこそ、所有権の衝突が目に見える被害をもたらす場所です。接続マネージャはトンネル用のデフォルトルートと、リモートネットワーク用のより具体的なルートを設定します。そのあと手書きのスクリプトが別のメトリックで独自のデフォルトを追加し、タイミング次第で静かに勝ったり負けたりします。どのエントリが接続に紐づき、どれが恒久的なポリシーで、どのコンポーネントが再接続後にそれらを更新するのかを決めます。そして他のコンポーネントをそのテーブルから遠ざけてください。

ポリシールールにも同じ明快さが必要です。誰も埋めないテーブルを指すルールは、死んだトンネルとまったく同じに見えるブラックホールを作ります。トラフィックをどこかへ押しやるためのルールがあるなら、それが選ぶテーブルは同じ所有者が保守しなければなりません。

DNS は常に別の所有者です

リゾルバのデーモンは独自のアイデンティティで独自のプロセスとして動くので、トンネルのルーティング判断を偶然に継承することはありません。VPN が DNS サーバーを押し付けるとき、それをリゾルバが尊重するリンクごとの設定に変換する何かと、後でそれを取り除く何かが必要です。

ここでの誤解は、プロファイルにネームサーバーを書くとクエリの行き先が変わるというものです。変わるのはリゾルバに伝えられる内容であって、リゾルバが上流で使うソケットではありません。ファイルを信じるのではなく、クエリとルート検索で試してください。

ファイアウォールの状態と、それを誰が復元するか

ファイアウォールのルールは、VPN ホストで最も頻繁に上書きされる対象です。マネージャは接続ごとに NAT や転送のルールを追加できますが、起動時のファイアウォールサービスが保存されたルールセットを再読み込みしてそれらを消します。ポリシーの権限を一つ選び、もう一方をその利用者にするか、再起動が挙動を静かに変えることを受け入れてください。接続に紐づく例外は、同じ所有者が読み込むファイルに入れるもので、トラブルシューティング中に打ち込む iptables コマンドではありません。

ルールが再接続を生き延びる必要があるなら、明示してください。必要ないなら、それも明示してください。次のエンジニアは都合のよい答えを前提にするからです。

ライフサイクル:起動、再接続、解体

その三つの時点それぞれに所有者を与えます。起動時には、何が前提条件を整えるのか、どの順序かを決めます。ソフト再起動では、デバイスは生き残ってもセッション状態は生き残らないかもしれないので、作成者ではなく検証者を走らせる必要があります。解体時には、この接続が作ったものだけを削除します。すべてのルートをリセットしたりファイアウォール全体を流したりするのは、一つのトンネルを退役させるのとは違います。

観測には ip monitor link address route がカーネルの変更を起きたそばから表示しますが、それは意図ではなく出来事を報告します。削除されたルートは、どのプロセスが削除したかを何も語りません。所有権の地図と組み合わせれば、混乱するシャットダウンは候補の短いリストになります。

除外にもコストがかかります。衝突から逃れるためにデバイスクラス全体を管理外と印付けるのは、その状態を誰にも渡さないことであり、修正ではなく決定です。

関連記事