クライアントは接続して認証し、その後トラフィックは誤ったアップリンクから出てしまいます。マシン上の唯一の既定ルートがゲートウェイ自身のものだからです。その既定ルートを置き換えると、マシン自身の更新と管理アクセスが壊れるため、選択は「すべての通信」より狭くする必要があります。実用的な形は、クライアントプールの内部送信元アドレスを鍵とするポリシールールで、代替 WAN を持つ二番目のルーティングテーブルを指します。そこから先のチェックリストは、ルール自体ではなく完全性と障害時の挙動についてです。

送信元アドレスがルーティング判断まで残ることを確認する

送信元範囲に一致するポリシールールは、参照時点でパケットがまだその送信元を運んでいるときだけ発動します。転送されたクライアント通信は、ルーティング前に上流で書き換えられていなければ、その条件を満たします。ゲートウェイ自身が生成する通信は満たさず、まさにそのためにゲートウェイ自身の既定ルートはその場に残せます。

ここでローカルテストは誤解を生みます。ゲートウェイ上で実行した curl はゲートウェイのアドレスを持つローカル生成のフローなので、メインテーブルを使い、クライアントの経路については何も証明しません。接続済みのクライアントから試すか、プールに本当に属する送信元で通信を生成してください。

まず実際の値を書き出します。プールのプレフィックス、それを運ぶトンネルインターフェース、二番目の WAN のアドレスとネクストホップ、使う予定のテーブル番号を控えたうえで、新しいルールを追加する前に過去の試行の古いルールを消してください。優先度の異なる重複ルールはランダムに見える障害を生みます。

完全な選択テーブルを組む

テーブルは友達付きの既定ルートではありません。 すべての参照がその内部で解決するだけのルートが必要で、ネクストホップに到達できるよう WAN サブネットの接続ルートも含みます。tun1 上の 10.77.0.0/24 のプール、ネクストホップ 203.0.113.1 を持つ WAN アドレス 203.0.113.20/24、テーブル 600 の場合:

ip -4 route replace 203.0.113.0/24 dev usb0 src 203.0.113.20 table 600
ip -4 route replace 10.77.0.0/24 dev tun1 table 600
ip -4 route replace default via 203.0.113.1 dev usb0 table 600
ip -4 rule add priority 1500 from 10.77.0.0/24 lookup 600

ルールは既存のキャッチオールルールより低い優先度に置かれるため、一致したクライアントは先にテーブル 600 に当たり、それ以外はすべてメインテーブルに落ちます。ip-rule のリファレンスが順序付き参照モデルとセレクター構文を詳しく説明しています。

次にテーブルに含まれないものを考えます。メインテーブルにしかルートがない宛先、たとえば eth0 経由で届く管理サブネットは、テーブル 600 では見つからず、そこに既定ルートがあるとメインへも戻りません。その経路が重要なら、選択テーブルへ明示的に追加してください。VPN 出口テーブルでは通常それが正解です。

リスナー自身の通信をポリシーの外に保つ

OpenVPN リスナーには独自の外部接続があり、クライアントが到達したアップリンクで運ばれます。その通信は到着時の戻り経路を保つ必要があり、サーバーの公開アドレスやトンネルインターフェース全体を覆う広いルールは、それを代替テーブルへ引き込みかねません。ルールは内部プールだけに限定してください。

同じ理由で逆経路フィルタも確認に値します。クライアントへの応答が usb0 から出る一方、要求が別のリンクで到着した場合、厳格な rp_filter 設定はルーティングポリシーが有効と見なすパケットを落とすことがあります。ルールが失敗したと結論する前に、両インターフェースの有効な sysctl 値を確認してください。

順序はマシン上の他のすべてとの関係でも重要です。Docker ブリッジ、二つ目の VPN、プロバイダーイメージ由来の既存ルールはいずれも優先度を追加するので、優先度 100 が単独だと決めつけず、ルール一覧全体を読んでください。

転送と変換をルートに一致させる

ルーティングはアップリンクを選ぶだけで、転送を許可しません。カーネルで IPv4 転送を有効にし、ファイアウォールでクライアントから WAN 方向と戻りの通信を受け入れる必要があります。フローを落とす FORWARD チェーンを伴う正しいテーブルは、ルート欠落と同じ症状を出すため、両方を同じパスで確認します。

二番目の WAN がプライベートプールをこちらへ戻さないなら、その出口で送信元を変換します。動的アドレスのインターフェースでは、プールとインターフェースに限定した狭い masquerade ルールが一般的な選択です:

iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -o usb0 -j MASQUERADE

ここでは対象より範囲が重要です。任意の外向きインターフェースに一致する masquerade ルールは、eth0 から正しく出る通信も書き換えてしまい、ルーティングの誤りを直すのではなく隠します。変換はルーティング判断の後に走るので、誤ったアップリンクへ送られたパケットを修復することは決してできません。

経路が異なればトンネルのオーバーヘッドにも注意が必要です。クライアントが大きな TCP MSS を交渉し、代替 WAN の MTU が低いか内部にトンネルがあると、大きなセグメントは止まり小さなものは通ります。転送経路で MSS をクランプすれば、断続的な停止ではなく予測可能な挙動になります。

usb0 が消えたときに何が起きるかを決める

空のテーブルは障害時に閉じる状態ではありません。一致するルートが消えると、参照は次のルールへ続き、メインテーブルに達して eth0 の既定ルートを取ります。二番目の WAN から出るはずだった通信は静かに一番目から出てしまい、ポリシールーティングの構成では通常これが最も避けたい結果です。

そのフォールバックが許容できない場合は、テーブル 600 に明示的な終端ルート、たとえば blackhole の既定ルートを追加するか、インターフェースが落ちている間はファイアウォールでプールを落としてください。どちらも書き留められる判断です。沈黙はそうではありません。

永続性が最後の項目です。両方のリンクを持つ主体が、ネットワークマネージャーであれディスパッチャースクリプトであれ接続のライフサイクルであれ、再接続のたびに重複を追加せずルートとルールを再作成する必要があります。実クライアントからの要求とゲートウェイからの別の要求で検証し、両方で観測した出口を確認し、その後二番目の WAN を抜いて、設計した二つの結果のどちらが実際に起きるかを見てください。IPv6 には独自のテーブル、ルール、変換が必要です。上の IPv4 ルールはそれについて何も述べていません。

関連記事