OpenVPN が DHCP 更新後に切断される:エンドポイント経路を保つ
DHCP 更新でトンネルのエンドポイントが古いゲートウェイに残ると、ハーフデフォルト経路がトンネルを飲み込む。直すべきはメトリックではなく、その経路の所有者だ。
トンネルが接続したあと、アクセスリンクのリース更新がそれを殺し、ログは経路ではなくタイムアウトを責める。 VPN 設定では何も変わっていない、それが手がかりで、外側の何かが変わったのだ。 DHCP イベントがアドレスかゲートウェイを書き換え、トンネルのエンドポイントを到達可能に保っていたホスト経路が、もう存在しない次のホップを指すようになった。 これは経路の問題である前に所有権の問題だ。
症状をハーフデフォルト経路と突き合わせる
redirect-gateway def1 を使うと、OpenVPN はデフォルト経路を置き換えるのではなく 0.0.0.0/1 と 128.0.0.0/1 をインストールする。 この二つでアドレス空間全体を覆い、プレフィックス長だけで 0.0.0.0/0 に勝つ。 そのため より具体的な一致のない宛先はすべてトンネルに入る。
エンドポイントには例外が要る。 OpenVPN はハーフデフォルトを入れる前に、元のアクセスゲートウェイ経由でサーバーアドレスへのホスト経路を追加し、カプセル化されたパケットが出られるようにする。 その例外が消えるか、もう存在しない次のホップを保持していると、トンネル自身の外側パケットがハーフデフォルトに一致し、トンネルへ送り返される。 結果は次の keepalive やハンドシェイクで死ぬ接続で、ログには経路エラーらしいものは何も残らない。
ほかに触る前にテーブルの形を確認する。 ip route show は両方の半分とサーバーアドレスへのホスト経路を一覧するはずで、ホスト経路が欠けていれば、残りの調査には明白な出発点がある。
メトリックを変えずにハーフデフォルトが勝つ理由
低いメトリックは長いプレフィックスに勝てない。 /1 の経路が勝つのは、カーネルが最初に最も具体的な経路を照合するからで、デフォルト経路のメトリックを上げても、トンネル向けトラフィックがどこへ行くかは何も変わらない。 メトリックを追うのが、この診断で最もよくある間違った曲がり角だ。
ip route get 203.0.113.10 で選択を確認し、実際のサーバーアドレスに置き換える。 答えはカーネルが実際に使うインターフェースと次のホップを示し、テーブルを読んで考えるより情報量が多い。
そのコマンドをトンネル開始前、稼働中、そしてリースイベントの後に実行する。 一つのコマンドから三つの答えが得られ、分岐点が見えてくる。
スナップショットは一つではなく三つ取る
アクセスアドレス、アクセスゲートウェイ、エンドポイントの宛先、選択された経路、ポリシールールを三つの時点で集める、つまりアクセスリンク設定後、VPN 接続後、リースまたはキャリアイベント後だ。 各スナップショットはひと握りのコマンドで、そろって初めて意味を持つ。 障害後の一回だけのスナップショットは、遷移ではなく状態を記録する。 コマンドを小さなスクリプトに書き、どのスナップショットも同じ手順で取る。
スナップショットはタイムスタンプ付きで一つのファイルにまとめる、後で興味深いのは順序だからだ。 DHCP イベントは OpenVPN が経路を更新する前に来たのか、後だったのか。 答えが、誰が直すべきかを決める。 間違った時計のタイムスタンプは無いより悪い、だから経路テーブルを持つホストで取る。
エンドポイントがアドレスではなく名前で設定されている場合は、各スナップショットで名前解決も行う。 アクセスリンクの DNS 変更は、経路に一切触れずにエンドポイントを動かしうる。
どのコンポーネントが例外を更新するかを決める
dhcpcd システムでは、フックはフックディレクトリと終了フックから実行され、マネージャーモードはスコープがインターフェース単位モードと異なる。 フックが何をするにせよ冪等でなければならない、更新はまとめて届くことがあるからだ。
信頼できる所有者は、すでに両側を知っている統合だ、VPN 接続を管理するネットワークマネージャー、あるいはアクセスリンクが上がった後に並べられたユニットである。 フックが追加する静的経路は次のゲートウェイ変更まで機能し、その後はまったく同じように失敗する。 フックを使うなら、今日見たゲートウェイをハードコードせず、実行時に現在のゲートウェイを読ませる。
所有者を設定の中に記録する。 次に再接続をデバッグする人は、例外経路の責任が VPN ではなくフックにあることを知る必要がある。
再接続だけでなくライフサイクルを試す
dhcpcd -n eth0 で、またはリースを解放して取り直すことで更新を強制し、その後エンドポイントを ip route get で再度確認する。 二回行う、二回目は重複した経路を追加するフックを捕まえるからだ。 そのあと再起動する、永続性は正しさとは別の性質だからだ。
更新と再起動を生き延びるトンネルには、所有者と機能する例外がある。 手動の再起動だけを生き延びるものにはどちらもなく、あなたが予定できない次のイベントで失敗する。