VPN の外に出すのはローカル Web サービス一つだけ、ポートで振り分け
送信元ポートのルールでホストのサービスを一つだけ WAN に出し、残りは VPN を使い続けられるかを、そのコストとともに判断します。
ホスト上の一つのサービスだけが物理アップリンク経由でインターネットに応答し、その他の通信はトンネルを使い続ける必要があります。ポリシーベースルーティングがその負荷に耐えられるかは三つの条件で決まり、どれもルールを書く前に安く確認できます。サービスは DNAT やポート転送の背後ではなくこのホスト上で終端していること、VPN 自身のルールが例外を許可していること、そして要求ではなく応答を一致させることです。三つのうちどれかが欠けると、下のコマンドはきれいに読み込まれるのに何の役にも立ちません。
ルールを書く前に三つの条件を確認する
DNAT でポートを公開しているコンテナや、ポート転送の背後にあるサーバーが作るパケットは、このホストを起点としません。そのパケットは転送されるため、 ホストローカルの入力を条件にしたルールはそれらを決して見ません すると通信は既定ルートを取り続けます。先に進む前に、最も間違えやすい条件だからこそ、サービスが実際どこで動いているかを確認してください。
二つ目の条件は仕組みではなくポリシーです。トンネルを迂回する経路はトンネルの目的に対する例外であり、管理されたホストではその判断はポリシーの所有者に属し、タイムアウトを調べている人ではありません。
応答を一致させる。クライアントの宛先ポートではない
TCP 443 で待ち受けるサーバーの応答は、送信元ポート 443 でホストを出ます。同じホストのブラウザーが遠隔の HTTPS サイトに接続するときは、一時的な送信元ポートと宛先ポート 443 を送ります。どちらもポート 443 の通信で、WAN テーブルを使うべきは片方だけですから、宛先ポートで一致させると誤った半分をつかみます。
区別できるのは応答の向きです。送信元ポートで一致させ、ルールをローカルで生成されたパケットに限定すれば、ブラウザーの要求に触れずにサービス自身の応答をカバーできます。
ルールが指す前に完全な戻りテーブルを作る
空のテーブルは経路なしを意味し、壊れたポリシーではなく壊れたサービスのように見えます。まず、ホスト上で他の何も使っていないテーブル番号と優先度を使って埋めてください:
ip -4 route add table 100 192.0.2.0/24 dev eth0
ip -4 route add table 100 default via 192.0.2.1 dev eth0
ip -4 rule add priority 1000 iif lo ipproto tcp sport 443 lookup 100
番号はコピーせず、稼働中のホストから読み取ってください。ip -4 rule show はどの優先度が使われているかを示し、既にある優先度にルールを追加すると、単体では正しく見える二つのルールの順序が黙って変わります。
ここで実際に働くのは二つのセレクターです。iif lo はホスト自身が生成したパケットをカーネルが報告する方法なので、ルールが外部から届く転送通信を誤ってとらえることはありません。ipproto tcp sport 443 は一つのトランスポートと一つのポートに絞り、要件が許す限り狭くします。プロトコルのセレクターを外すと、ルールは UDP 443 もとらえますが、これは別の挙動を持つ別のサービスです。
プライベート側の応答はトンネル内に留める
同じリスナーがプライベート側のクライアントにも応答する場合、テーブル 100 のすべてをとらえる WAN 既定ルートが、その応答をアップリンク経由で返そうとします。WAN 既定に従ってはならないプライベート接頭辞を追加するか、次のポリシールールに落としてください:
ip -4 route add table 100 throw 10.90.0.0/24
throw ルートはこのテーブルでの検索を終え、パケットをルール一覧に戻すので、続く VPN ポリシーに機会が回ります。それ自体はトンネルへ何もルーティングせず、後続のルールに一致する経路がなければパケットはやはり失敗しますから、throw を修正と決めつけず、次のポリシーを検証してください。
リバースパスフィルタリングとホストのファイアウォールルールは、到着した要求に依然として適用されるので、検証を緩める前に実際の判定を確認してください。ルーティングの例外は、rp_filter が不可能と見なす戻り経路を受け入れるようにはしません。
TCP、次に QUIC、次に再起動を試す
許可された外部クライアントから一本、プライベート側から一本接続を開き、実際のアドレスとポートで応答の検索を確認します。外部の応答がテーブル 100 を使い、プライベートの応答が使わなければ、ポリシーは要求どおりに動いています。
HTTP/3 は UDP 上で提供され、TCP のルールでは一致しません。そのため QUIC のリスナーには専用のセレクターが必要で、なければ HTTPS が動いている間もトンネルを使い続けます。採用するルールはインターフェースを所有するコンポーネントに保存して再接続や DHCP 更新の後に確認し、再起動後に競合するマネージャーが実行時ルートを削除するのは、発生源で直すべき所有権の問題であり、より広い NAT ルールを上に足す理由ではありません。