スプリットトンネルのルートが重複するとき:どのプレフィックスが優先されるか
最長プレフィックス一致、メトリック、ポリシールールが、重複する宛先をどのトンネルが処理するかを決めます。まず送信元アドレスと解決済みの名前を確認してください。
スプリットトンネルのプロファイルが二つ、プライベートプレフィックスが二つ、そして両方が主張するホストが一台ある。症状はきれいな失敗になることはまれで、あるサービスは月曜日には動き、二台目のクライアントが再接続した後にタイムアウトし、再起動するとまた動く。クライアントを接続した順序は結果を決めないし、クライアントの画面の行の順序も決めない。これらの確認を順番に行い、当てはまらない最初の確認で止めること、後の確認は前の確認が正しいときにだけ意味を持つからだ。
1. 宛先と送信元を書き出す
失敗するリクエストが向かう正確なアドレスから始め、ホスト名やアプリケーション名から始めてはいけない。名前を一度解決してすべての応答を記録し、失敗するフローが実際に使うものを選ぶ。次に同じフローのローカルアドレスを記録するのは、送信元アドレスによってどのポリシールールに一致するか、したがってどのテーブルを参照するかが変わるからだ。
複数の A レコードの一つへ向かうリクエストは、兄弟アドレスが成功するのに失敗することがあり、これは不安定なトンネルに見えて実際には二つの別経路だ。宛先が複数の応答を持つ名前なら、何かを変える前に各応答を個別に試すこと。
2. カーネルにどのルートを選んだか尋ねる
ルートテーブルを読んで答えを推測してはいけない。スタックが尋ねるのと同じ質問を同じ送信元アドレスで尋ねること、Linux なら ip route get 10.20.4.10 from 10.8.0.2、PowerShell なら Find-NetRoute -RemoteIPAddress 10.20.4.10 だ。出力は実際に使われるルートを示し、テーブルを読んで予想したものとしばしば違う。
一致するルートの中では通常より具体的なプレフィックスが勝ち、両方に含まれるアドレスなら /24 が /16 に勝つ。同じ長さの一致どうしではメトリックの低い方が勝ち、ダウンしているリンクにインストールされたルートは飛ばされる。同じ /24 を同じメトリックで押し込む二つのトンネルは別のケースで、カーネルは両方のルートを保持してその間で選ぶため、クライアントの接続順に従うのではなく結果が入れ替わりうる。月曜日は動き火曜日は失敗するというパターンを生むのはまさにこの状況で、別の順序で再接続しても変わらない。
3. ポリシールールが参照先を変えていないか確認する
ルートテーブルが参照される前に、カーネルはポリシールールをたどる。ルールは、特定の送信元、ユーザー、ファイアウォールマークからの通信をまったく別のテーブルへ送ることがあるので、メインテーブルの勝ちプレフィックスがそのフローでは一度も参照されないことがある。ip rule show はそれらを評価順に一覧し、ip route show table 100 は選ばれたテーブルが実際に何を含むかを示す。
ここには二つの罠があり、空のテーブルを指すルールは次のルールへ抜ける参照を生むので、何もしていないように見える。もう一つは優先度の番号そのもので、ルールは昇順に読まれ、組み込みの値は 0 local、32766 main、32767 default である。32767 より小さい番号のルールは、すべてを受け止める既定ルールより前に参照される。32767 より大きい番号のルールはその後ろに位置し、それ以前のどのテーブルも応答しないときだけ到達するが、main の通常の既定ルートがそれを妨げるので、実際には決して到達せず、インストールされているように見えながら黙って何もしない。クライアントがルールとルートを書いたなら、両方を確認し、再接続後にもう一度確認すること。書き直されたプロファイルは別の優先度の二番目のルールを追加することがあるからだ。
4. ルーティングの引き分けと重複したアドレス計画を切り分ける
プレフィックスがまったく問題でないこともある。二つの拠点がどちらも 192.168.1.0/24 を使っているなら、同じアドレスが二つの異なるホストを指しており、どのルートもそれらを区別できない。二つの応答の一方へのホストルートは、もう一方の拠点が同じ名前に対して応答するまでしか機能せず、そのとき例外は静かに不具合そのものになる。
手がかりは、宛先アドレスが両方の経路で同一で、意図した所有者だけが違うことだ。これはアドレス計画の決定でありルーティングの調整ではないので、片側を再採番するか、片側を変換するゲートウェイの背後に置くか、自分の名前を解決するプロキシ経由で二つ目の拠点に到達すること。既定ルートを下げたりホスト例外を積み上げたりしても、衝突の場所が移るだけだ。
5. リゾルバーがルートと一致していることを確認する
誤ったプライベートアドレスに解決される名前は、ルーティング競合の症状をすべて生み、その原因は一つも生まない。ホストが受け取る応答と、宛先が実際に使うアドレスを比較し、どのリゾルバーが答えたかを確認すること。トンネルがリゾルバーを押し込むならクライアントはトンネルを使うフローに対してそれをインストールすべきで、押し込まないならホストはローカルのリゾルバーに問い続け、それが検索ドメインやキャッシュされたレコードから答えることがある。
リゾルバーに直接問い合わせ、応答したサーバーを記録すること。短い TTL のキャッシュ応答は、再接続後の最初のリクエストが五回目と違う振る舞いをする理由も説明してくれる。
6. 再接続し、適用された状態を確認してから、両方のフローを試す
修正したら再接続し、プロファイルエディターを信じるのではなく、クライアントが実際に何をインストールしたかを確認すること。ルール、テーブル、そしてそこから得られる ip route get の応答をもう一度読む。二台目のクライアントは接続時に 自分のルートを再インストール して競合を作り直すことがあるので、状態の確認は最後のクライアントが接続した後に行う必要がある。
試すのは一つではなく二つのフローで、以前失敗していたリクエストと、もう一方のトンネルを使うはずのリソースだ。すべてのプライベート通信を一つの接続に寄せると、最初のテストは通り二つ目が壊れる。これを見つけられるのは対にしたテストだけなので、残す例外はすべて宛先と理由を添えて記録すること。