クライアントプールが二つ、ゲートウェイが一台で計画は取るに足らないように見えますが、一つのルールが最初のプールを速いアップリンクへ出し、もう一つが第二のプールをパートナートンネル経由で送ります。ところがルールを設定しても、そのプールはデフォルトルートから出ていきます。ルールは壊れていません。パケットの送信元は、参照の瞬間に作者が想定したものではなく、変換と参照は同じパケットの旅の別の地点で起こり、その順序は多くの人が描く頭の中の図とは逆になっています。

参照は送信元が書き換わる前に行われる

VPNクライアントから転送されるパケットに対し、カーネルは決まった順序を実行します。トンネルインターフェースに到着し、conntrackとDNATが存在する prerouting を通り、次にルーティング判定、次に転送、次に postrouting で最後にSNATが適用されます。from という形のルールはそのルーティング判定の際に参照されるため、クライアントの元のアドレスを見ており、変換後のアドレスではありません。

つまり masquerade ルールを追加しても、外向きフローにどのポリシーが一致するかは変わりません。変わるのは遠端が見る内容、ひいてはどの戻り経路が存在するかです。これは二つの別の結果であり、変更レビューはしばしばこれを混同します。切り分ければ、設計はたいてい一分で明らかになります。

変換後のアドレスがルールに現れるのは応答方向です。ゲートウェイに戻るパケットは変換後のアドレス宛であり、宛先や受信インターフェースを条件にしたポリシールールがあれば、照合するのはその値です。同じ接続でも、方向ごとに真実の源が異なります。

StageSource the kernel seesWhat it means for your rule
PreroutingClient address, 172.31.7.42Where marks and DNAT are applied
Routing decisionStill 172.31.7.42This is where from rules match
PostroutingBecomes 198.51.100.9What the far end and its return route see

したがって送信元の異なる二つのプールには別々のテーブルが必要で、設計は妥当です。上の表が排除するのは、遠隔サイトが受け取ったものを見てルールを推測するという近道です。

ゲートウェイからのテストはプールのテストではない

ゲートウェイ自身が生成するトラフィックは、インターフェースに到着していないため prerouting を通りません。出力経路でルーティングされ、送信元はゲートウェイ自身のアドレスになり、クライアント範囲を条件にした from ルールは一致しません。この分野の「箱からは動くがクライアントからは動かない」というチケットはすべて、この事実の言い換えです。

クライアントを近似するのではなく模擬してください——ルーティング参照は、送信元と入力インターフェースを与えれば直接問い合わせられます。

ip route get 198.51.100.9 from 172.31.7.42 iif tun0
ip route get 198.51.100.9 from 172.31.8.42 iif tun0
ip route show table 201

プールごとに一度ずつ実行します。二つのコマンドが同じインターフェースを返すなら、ルールはプールを分離しておらず、原因は欠けているルールか、両方に一致する優先度の高いルールです。異なるインターフェースを返すのにクライアントが失敗するなら、障害は参照より後ろにあり、ルールを追うのはやめられます。

優先度であり、ファイル内の位置ではない

ルールは優先度の昇順で評価され、重要なのは番号であって、入力した順序ではありません。local テーブルは優先度0、main テーブルは32766、デフォルトルールは32767にあり、既定の優先度で追加したルールはリストの末尾近くに落ちて、ほとんどすべてに負けます。

ip rule show
ip rule add from 172.31.8.0/24 lookup 201 priority 1000
ip -4 route show table 201

優先度を明示すると、意図した順序がファイル上でもレビューでも見えるようになります。また、後からの追加が既存ルールを黙って追い越すことを防ぎ、これが無関係な変更の後に動いていたポリシーが動かなくなる最も多い原因です。

一致したルールが不完全なテーブルを指しているのがもう一つの罠です。テーブル201にデフォルトルートはあるが宛先へのルートがない場合、パケットは破棄されるか誤った場所へ送られ、ルールだけを見ると完全に正しく見えます。ルールではなくテーブルを読んでください。ルールはポインタであり、空のテーブルは何も指していないポインタです。

戻り経路は依然として必要

送信元ポリシーは出口を選びます。戻り経路を作るわけではありません。第二のプールがパートナートンネルから出るなら、パートナーは 172.31.8.0/24 に到達する方法を知っている必要があり、ゲートウェイへの戻りルートか、既に知っている変換後のアドレスを受け取るかのどちらかです。

どちらを選ぶかは、目に見える結果を伴う設計判断です。クライアント範囲を戻しでルーティングすれば、パートナー側でクライアントごとの識別が保たれ、あなたのプレフィックスを受け入れてもらう必要があります。変換はプールを一つのアドレスの背後に隠し、パートナーにはそのアドレスだけを受け入れてもらう代わりに、誰が接続したかについて双方のログが一致しなくなります。

どちらを選んでも、プールの定義の隣に書き留めてください。誰かの記憶にしか存在しない戻りルートは、パートナーがファイアウォールを変えるまで生き残り、その後に再構築で一日かかる類のものです。

ポリシーでゲートウェイ自身のトンネルを捕まえない

クライアント向けに書いたルールは、除外しない限りゲートウェイが生成するトラフィックにも適用されます。マークや出力インターフェースを条件にした広いルールは、ゲートウェイ自身のパートナーへの接続を捕まえ、その結果 ポリシーを運ぶトンネルがポリシーでルーティングされます。これはプロバイダ障害に見えるループや切断を生みます。

各ルールは、送信元プレフィックス、入力インターフェース、対応していればクライアントのパケットだけが持つマークまで、設計が許す範囲で狭くしてください。ルール変更のたびにゲートウェイ自身の接続をテストするのは、障害が自己参照的でクライアント側のテストには現れないからです。

ip-rule のマニュアルページは、セレクタと優先度の意味を記述しています。プールごとの参照テストと組み合わせれば設計は検査可能になり、それが一年持つポリシールーティングと、誰も触りたがらないポリシールーティングの違いです。

関連記事