同じパケットに対して二つの独立した判断が行われ、どちらも要求を静かに終わらせることができる。ルート検索はインターフェースと次のホップを選び、その後パケットフィルタがその組み合わせを許可するか決める。タイムアウトは二つのうちどちらかが拒否したことだけを伝え、どちらかを教えない。段階を順に追えば、修理はたいてい推測ではなくなる。

二つの判断、一つのパケット、二人の所有者

ルート検索はまずポリシールールを参照し、次にそれらが指すテーブルを見て、宛先に一致する最も具体的なプレフィックスを選ぶ。トンネルルートをインストールしたクライアントがその判断を所有し、ファイアウォール規則でそれを代用することはできない。検索が予想外の場所を指すと、それ以降の各段階は間違ったパケットを扱う。

フィルタリングは別である。Linuxホストではnetfilterのフックがパケットの宛先によって通信を分ける。出力はマシンを離れ、入力はそこで終わり、転送はそれを通過する。VPNクライアントを受け入れてLANへルーティングするゲートウェイには転送経路が必要で、それは多くの既定設定が空のままにしているチェーンそのものである。

送信元の選択も同じ判断に属し、食い違いの多くはここに隠れている。カーネルはルートが指定しない限り出力インターフェースから送信元アドレスを選ぶので、LANサブネット向けに書かれたフィルタ規則がトンネルアドレスで出ていくパケットに一致することはない。

検索が実際に何を選んだかを読む

推測するのではなく判断を出力する。次のコマンドは、その宛先に対してカーネルが使うルートを、インターフェースと選ばれる送信元を含めて解決する。

ip route get 10.8.0.5
ip route get 10.8.0.5 from 192.0.2.44
ip rule show
ip route show table all | sed -n '1,40p'

VPNクライアントはメインテーブルより低い優先度にポリシールールをインストールすることが多く、きれいなメインテーブルはそれ自体では何も証明しない。ルールの優先度をそれらが選ぶテーブルと比べ、トンネルルートが一度手で追加されるのではなく再接続後も残るかを確認する。

ポリシーベースのIPsecはルーティングが扱わない三つ目の照合段階を追加する。strongSwanの転送に関する注記がトンネルとトランスポートの構成について説明しているとおりである。セキュリティポリシーはプレフィックスとプロトコルで通信を選び、ルートは保護されていないパケットがどこへ行くかだけを決める。ルーティングされていても一致するセレクタがないサブネットは、設定次第で保護されないままか破棄され、どちらの結果もファイアウォールの問題には見えない。ポリシーを出力し、そのセレクタをトンネルが運ぶと期待したプレフィックスと比較する。

フィルタリングはルートではなくフックで適用される

VPNリスナーを許可する規則は、ゲートウェイ自身宛ての通信についての規則である。そのゲートウェイの背後のホストに届くクライアントについては何も言わない。転送される通信は別のチェーンを通るからである。規則群を一つの平坦なリストとして読むことが、正しく見える規則が決して発火しない通常の理由である。

カウンタが問いをすぐに片付ける。パケット数がゼロの規則は一度も到達されておらず、間違ったチェーン、間違ったインターフェース、または以前の破棄を示す。破棄ポリシーの下でカウンタが増えている規則が探していた境界で、パケットは誤ってルーティングされるのではなく破棄されている。

クライアントが使う経路でプローブを送る

ゲートウェイ自身で実行するテストは、ゲートウェイ自身の送信元アドレスで出力と入力を通る。それはクライアントの転送要求とは別の経路なので、ローカルで成功したcurlは見た目より少ないことしか証明しない。失敗するマシンから試すか、インターフェースと送信元を明示的に固定する。

nc -vz -w 3 10.8.0.5 443
ping -c 3 -W 1 10.8.0.5
tcpdump -ni any host 10.8.0.5 and port 443
iptables -vnL FORWARD --line-numbers
nft list ruleset | sed -n '1,60p'

両端でのキャプチャが残りのケースを分ける。クライアントを出て決して届かないSYNは、ルーティング、暗号化、または上流のアクセスリストを意味する。届いて応答がないSYNはサービスまたはそのホストフィルタを意味し、トンネルが問題だったことはない。

戻り通信には独自の目が必要である。非対称ルーティングと逆経路フィルタリングは、間違ったインターフェースに届いた応答を破棄し、それはブロックされたポートではなく一方向の接続として現れる。ファイアウォールが起こしていない症状のせいにする前に、sysctlの値を確認する。

ログは最初の手段ではなく第二の意見として機能する。転送チェーン上の一時的なログ文は、そこに当たったインターフェースとアドレスを示し、後で簡単に外せる。恒久的に残せば、答えではなくログ量の問題を作ったことになる。

各変更を再接続後も残る場所に置く

ip route addで追加したルートはインターフェースが落ちるまで生きる。代わりに接続プロファイルに保存する。NetworkManagerは接続上の追加ルートを受け付け、netplanは起動をまたいで保持する。同じ規則はクライアント側のファイアウォール例外にも当てはまり、次の再読み込みで消える。

サーバー側の規則はサービスが起動時に読み込む設定ファイルに属し、閉じれば終わる対話セッションには属さない。規則を書き、再読み込みし、カウンタが動いたことを確認する。構文を拒否した再読み込みは古い規則群を静かに残すからである。

その後、元のアプリケーション要求を最初から最後まで繰り返し、どの層が変わったかを記録する。フィルタの変更も必要だったルート修正はそれでも失敗し、最初の問題が消えたと分かれば二度目の失敗はずっと読みやすい。結果の横に日付とクライアントのバージョンを記す。ルーティングとフィルタリングの既定値はどちらもリリース間で動くからである。そのメモをチケットに残し、次に担当する人が二段階の道のりを繰り返さず、止めた場所から始められるようにする。

関連記事