IPsec ホストで通信をキャプチャし、ESP パケットが出ていくのを見て、何も戻ってこないのを確認し、遠端が壊れていると結論づけました。そのキャプチャはこの結論を支えません。ESP は会話の一方向だけを守り、IP 層では何も確認応答しません。したがって戻りの ESP がないことは、トンネルが死んでいるのと同じくらい容易に、アプリケーションに言うことがなかっただけの可能性もあります。どちらの端を責める前にも、内側のやり取りと受信側の状態を読んでください。

誤解:保護されたパケットには必ず応答が返る

ESP は要求と応答のプロトコルではありません。ポリシーが選んだものを暗号化して認証し、受信側は自分のパケットを生成せずに、その内側パケットを検証して復号し、配信します。宛先が無視する UDP 問い合わせや、受信ポリシーが破棄する ICMP エコーは、正しい結果として両方向に沈黙を生みます。その沈黙を転送障害とみなすと、決して存在しなかったネットワーク障害を探しに行くことになります。

一方向のキャプチャが実際に証明するのは、送信側のスタックがその観測点で何かを暗号化したということだけです。到着についても、応答する意図についても何も分かりません。有用な問いは「なぜ応答がないのか」ではなく「内側の会話が何を生むべきだったのか」です。

二つの SA、二つの SPI、一つの会話

IPsec のセキュリティアソシエーションは一方向なので、通常の保護された交換は、別々の識別子と独立した状態を持つ受信側アソシエーションと送信側アソシエーションを伴います。送信パケットの SPI で戻り通信を探すのはカテゴリー錯誤です。応答はどれも相手自身の送信側 SA の下を、相手自身の SPI で流れるからです。代わりにトラフィックセレクターと相手のアドレスで組を照合してください。

鍵の再生成は、古い状態と置き換え後の状態が重なりうるため、数秒間だけ全体像を複雑にします。症状が鍵の再生成の前後で始まったなら、接続名だけでなく、アソシエーション識別子とタイムスタンプをまとめて集めてください。

何かが応答する前に受信側がすべきこと

StageWhat to look atWrong conclusion if skipped
Sender encryptsoutbound SA packet counter"the tunnel is up"
Peer receivesinbound SA counter and replay window"the peer is down"
Inner deliverytarget host or service logs"routing is broken"
Application repliesthe app's own trace"the reply was dropped"
Protected returnthe peer's outbound SA"ESP only works one way"

どの行も独立に失敗し、失敗ごとに担当が異なるため、単一のキャプチャではそれらを区別できません。受信カウンターが到着の唯一の直接的な証拠です。認証やリプレイ検査に失敗したパケットは、応答なしで破棄されるからです。受信カウンターが動いていない相手は、したがって自分のポリシーについて何の情報も送っていません。

配信は復号とは別の段階です。状態が有効でも、内側の宛先を含まない受信ポリシーや経路によってパケットが後から破棄されることがあるため、きれいなカウンターが目的の場所に届いた証拠だと決めつけず、対象ホストが平文を見たかどうかを確認してください。

ネイティブ ESP は UDP ではない

ネイティブ ESP は IP プロトコル 50 であり、TCP でも UDP でもなく、ポートも一切ありません。したがって UDP 500 の IKE を許可するファイアウォール規則はデータ経路について何も語らず、ポートを前提に書かれたフィルターはトンネルのネゴシエーションを通したうえで内部で運ばれるすべてを破棄しかねません。データ経路は、実際に観測したモードで単独に検証してください。

NAT の背後では形が変わります。保護されたペイロードは UDP の中を、通常はポート 4500 で流れ、これは RFC 3948 が定めるとおりです。規則を書く前に有効なモードを記録し、経路上の機器がネイティブ ESP と UDP カプセル化 ESP をまったく別に扱うこと、一部の中間装置が片方を通してもう片方を破棄することを踏まえてください。

このインシデントに属するカウンターを読む

strongSwan ホストでは swanctl --list-sas がアソシエーションごとのパケット数とバイト数を両方向で報告し、「一度も届かなかった」と「届いたが応答されなかった」を切り分けるのに足ります。Linux では /proc/net/xfrm_stat が状態の欠落、ポリシーの欠落、プロトコルエラーといった集計的な失敗を数えます。これらの合計は起動時から蓄積され、一つのネットワーク名前空間に属するため、大きな数字はそのまま帰属にはなりません。

正しい名前空間でインシデントの時間帯の前後に二回読み取り、差分を比較してください。そうしないと先週のエラーを今日の午後のチケットに貼り付けることになります。名前空間と二つのタイムスタンプをチケットに書き、次の読み手が合計を信じるのではなく比較を再現できるようにしてください。

容疑者ではなく段階を名指しする

有用な結論はパケットがどこで止まったかを述べます。一度も受信していない、受信して破棄された、配信されたが応答されない、応答されたが戻り道で失われた、のいずれかです。それぞれが別の担当と別の次のコマンドを指します。「VPN サーバーから応答がない」は四つの異なる障害を一つの文に押し込みますが、その文をキャプチャは決して正当化していません。

キャプチャは狭く保ち、生のカーネル状態はチケットの外に置いてください。ホストの外に出すべきでない鍵素材を含むことがあるからです。カウンターの差分とタイムスタンプこそ、次の人に渡す価値のある部分です。

関連記事