VPN トラフィックでポリシールーティングが変えるものと変えないもの
ルールはどのテーブルを参照するかを決めるため、メインテーブルのデフォルトルートだけでは何も説明できないことが多い。ルールを追加する前に、優先度・マーク・送信元をまとめて読む。
ポリシールーティングは、多くのトラブルシューティング手順が問うのとは別の問いに答える。メインテーブルは宛先がどこへ向かうかを示すが、ポリシールールはそもそもどのテーブルを参照するかを示し、送信元アドレス、パケットマーク、またはパケットが到着したインターフェースからそれを判断できる。トンネルの挙動が一貫しないとき、原因はルールセットであることが多く、ルーティングテーブルであることは少ない。
ルールがテーブルを選び、次にテーブルがルートを選ぶ
各ルールは優先度、一致条件、対象テーブルを持つ。カーネルは優先度順にルールをたどり、最初の一致で止まり、そのテーブルで通常の最長プレフィックス検索を行う。空のテーブルを指すルールは次のルールが選ぶものへ抜け落ちる。丁寧に書いたルールが何もしていないように見えるのは、このためだ。
メインテーブルを出力しても、動作している VPN クライアントを説明できないことが多いのはそのためだ。クライアントは通常、メインテーブルのデフォルトルールよりずっと前の低い優先度番号にルールを挿入するので、パケットはあなたが見つめていたルートには決して届かない。メインテーブルのメトリックを下げても、すでに迂回されたトラフィックには何も変わらない。
ルールは、意図的にプレフィックスをブラックホールや到達不能にすることもできる。一部のクライアントはそのようなルールをキルスイッチとして追加し、その場合のドロップは、設定されたトンネルではなく壊れたトンネルのように見える。
ルールセットは一覧ではなく順序として読む
ルールを優先度と参照先テーブルとともに出力し、次にデフォルトルートやトンネルルートを持つ各テーブルを出力する。重要なのは順序であり、スクリーンショットが通常省略するのもその部分だ。
ip rule show ip route show table all | sed -n '1,60p' ip route get 198.51.100.20 from 10.8.0.2 ip route get 198.51.100.20 from 10.8.0.2 mark 0x1
理論を観測に変えるのは、最後の二つのコマンドが、カーネルがその送信元とそのマークに対して何をするかを問い合わせるからだ。もしマークが変わると答えが変わるなら、マークに基づくルールが働いており、マークを省いたテストは別のパケットをテストしている。外側の接続には専用のルールが必要だ。すべてのトラフィックを自分経由でルーティングするトンネルは、接続先のエンドポイントアドレスを除外しなければならない。さもなければ、暗号化されたパケットはたった今離れたトンネルへ送り返される。ほとんどのクライアントはこの除外を自動で挿入するが、手で編集したルールセットこそ、それが抜け落ちる場所だ。
マークとソケット:クライアントがトラフィックを分ける二つの方法
一部のクライアントはファイアウォールでパケットにマークを付け、そのマークに一致するルールを追加する。別のクライアントはソケットレベルのルーティングを使い、接続する前にソケットへルートを設定する。前者は ip rule で確認できるが、後者は確認できず、一般的な検索にも現れない。
テスト用プログラムが、代表すべきアプリケーションと違う挙動をするなら、そのアプリケーションがマークを設定しているのか、デバイスにバインドしているのかを確認する。仕組みに名前が付いていれば、この違いは謎ではない。同じマシン上でシェルからの curl とブラウザのタブが別の経路を取れる理由も、これで説明できる。どちらの手法も広い意味でのポリシールーティングだ。宛先以外の何かで経路を選んでいる。どちらもトラフィックを許可するものではなく、どちらもピアが期待するファイアウォールルールや資格情報の代わりにはならない。
もう一つルールを足す前に所有権をたどる
ルールは何かがインストールする。VPN クライアント、ネットワークマネージャ、手書きのスクリプトはそれぞれ起動時にルールを追加でき、再接続ロジックは前のセットを残しうる。以前のプロファイルの古いルール二つは、プロファイルが削除されたずっと後までトラフィックを誘導し続ける。
優先度と形から、どのプロセスがそのルールを所有しているかを見つけ、その所有者が接続のたびにセットを書き直すかを確認する。書き直すなら、今日追加した手動ルールは明日には消える。修正はシェルの履歴ファイルではなく、クライアントの設定に入るべきものだ。テストのためにルールセット全体を消すのは魅力的な近道だが、代償は予測できる。クライアントが自分のトンネルを動かすために必要なルールも消えてしまう。一度に一つずつ削除するか、再起動できるマシンでテストする。
範囲は一つのフローではなく二つのフローで証明する
修正が確認できるのは、影響を受けるべきフローと受けるべきでないフローの両方によってだけだ。ポリシーがトンネルへ送る宛先と、外に残さなければならない宛先を選び、両方の検索とキャプチャを比較する。
ip route get 198.51.100.20 from 192.0.2.44 ip route get 198.51.100.21 from 192.0.2.44 tcpdump -ni any host 198.51.100.21 and port 443
二つの検索が異なるインターフェースを返せば、ルールは何かをしている。同じインターフェースを返せば、ルールは意図より広く一致しており、それが一つのアプリケーション向けのトンネルにサブネット全体を静かに送り込む障害だ。
チケットにルールの優先度と所有サービスを、二つのテストアドレスとともに記録する。そうすれば次の人は症状の説明ではなく再現可能な組を得られ、ポリシールーティングがまだ効いているかを一分で判断できる。