マルチサブネットの IPsec で戻り通信が落ちる? reqid を数える
マルチサブネットのトンネルで片方向だけ通らないのは、暗号化やルーティングではなくポリシーと reqid の不一致が原因であることが多い。xfrm データベースを順に読む。
通信はある拠点を出たまま戻らず、両方のゲートウェイはネゴシエーション完了を報告し、手がかりは応答のない外向きパケットの山だけである。Linux のエンドポイントでは、通常の原因は暗号強度でも MTU でもルーティングテーブルでもない。ポリシーエントリの粒度と、各ポリシーをセキュリティアソシエーションに結び付ける番号である。以下の手順は、他の何かに触れる前にこの二つのデータベースを読む。
何かを変える前に症状を切り分ける
ネゴシエーション完了で片方向だけ失敗するなら、問題はデータ経路に絞られる。外向きポリシーが一致して応答が捨てられたか、相手側に送る手立てがなく応答が届かなかったかのどちらかである。アプリケーションから見ると両者は同じに見え、xfrm データベースが区別する。
MTU から始めない。誤った MTU は停止やフラグメンテーションの症状を生むが、外向きカウンタが増え続けるきれいな方向分断にはならない。
ポリシーデータベースと状態データベースを読む
Linux ではポリシーエントリが暗号化を決めるため、パケットをトンネルに入れるのは一致するポリシーであり、ルートではない。ip xfrm policy を実行して各エントリのセレクタ、方向、優先度、テンプレートを確認し、ip xfrm state で確立済みのアソシエーションとその reqid を確認する。ポリシーとアソシエーションはその reqid で結び付く。
三つの方向をすべて見る。外向きと内向きはこのホストとの間の通信を覆い、ホストが他者のために転送する場合はフォワード方向が重要になる。どれか一方向でエントリが欠けていたり食い違っていれば、暗号上の不具合なしに片方向の結果を説明できる。
古典的な非対称:複数サブネットに一つの reqid
よくある失敗は、ネゴシエーションしたすべてのサブネットのポリシーを一つの reqid の下に導入するピアで起きる。racoon の generate_policy require がそうなる。すると通信は最後に確立されたアソシエーションから出て行く一方、相手側はサブネットごとに別のアソシエーションを保つ。応答は、本来受け取るべきポリシーを reqid が指さないアソシエーションに届き、カーネルは復号後にそれを破棄する。
修正は設定変更であり、ファイアウォール規則ではない。generate_policy unique; は各ポリシーに固有の reqid を与え、ピアのポリシー単位のアソシエーションに対応する相手ができる。適用して再ネゴシエーションし、成功を宣言する前に想定サブネットの異なる reqid を数える。
二つのサブネットが依然として一つの reqid を共有し、相手側が二つを期待しているなら、非対称を見つけたことになる。対応表を記録する。次の変更がそれを直したのか保ったのかを示す証拠になる。
セレクタはネゴシエーションから決まり、設定からではない
保護される範囲は両端が合意したものであり、片側が要求したものではない。ホストペアを広い遠隔範囲に対して提示するクライアントは、ゲートウェイが狭めた版を受け取り、クライアント側で広げることはできない。手元のファイルではなく、導入済みのセレクタを読む。
目的が逆で、ある宛先をトンネルの外に置きたい場合は、優先度番号の小さいバイパスポリシーを追加して自動導入されたエントリに勝たせる。テンプレートのないポリシーは平文を許すので、これは調査手順ではなく変更記録のための意図的な例外になる。
この順で検証し、戻し方も知っておく
両方向についてサブネットごとにポリシーを並べ、ホストが転送するならフォワード方向も含める。異なる reqid を数え、期待する側でポリシーごとに一つであることを確認する。導入済みのセレクタと合意したセレクタを比べる。鍵更新の後にアソシエーションごとのカウンタを読み直す。確認したアソシエーションがすでに消えていることがあるためだ。ルートは最後に確認する。遠隔サブネットへのルート欠落は、ポリシーカウンタがきれいなまま同様の片方向症状を生む。
ピアを変える前に、二つの xfrm コマンドの現在の出力を保存する。新しい設定で戻り方向が回復しないなら、その出力を戻すほうが記憶からトンネルを作り直すより速い切り戻しであり、比較も正直に保てる。