VPN接続でVagrant VMが消える:壊れたルートは誰のものか
1分前まで応答していたマシンが接続の瞬間に消える。何かを編集する前に、壊れたルートの持ち主を特定する。
一分前まで応答していたマシンが、VPNが接続した途端に同じアドレスでタイムアウトする。この症状を生む故障は三つあり、それぞれ別のマシンに住んでいる。ホストがプライベートネットワークへのルートを失う場合、ゲストのNAT範囲がトンネルが今広告する範囲と衝突する場合、あるいはフルトンネルがホスト上のすべてのルートの所有権を奪う場合だ。修正がそれぞれ別の場所にあるため、設定を変える前にどれが起きたのかを突き止めること。
ボックスではなくルートを見る
トンネルが上がっている間に、ゲストのアドレスに対するホストのルーティング判断を見る。ホストオンリーアダプタを指したままのルートは問題ではない。VPNアダプタを指すようになったルートが問題であり、それを変えたのはあなたではなくクライアントだ。アダプタがアドレスを保っていることはインターフェースが生き残ったという意味で、経路が生き残ったという事実とは別物だ。
接続の瞬間にちょうど切れるSSHセッションは想定内の挙動だ。クライアントはアダプタを循環させてルートを入れるので、接続は数秒死ぬ。故障は決して戻らない接続であり、一瞬点滅した接続ではない。
トンネルの前と後でテーブルを採取し、その二つの出力を差分する。差分が診断であり、同時にネットワークの所有者が求める証拠でもある。
ip -4 route get 192.168.56.10
ip -brief addr show
ip route show table main | head -20接続前と接続後でホストのテーブルを読む
Linuxでは重複するルート間の優先順位はプレフィックス長とメトリックで決まるので、より具体的なVPNルートは誤っていても勝つ。Windowsではインターフェースメトリックが同点を決め、トンネルのアダプタは通常、仮想アダプタより低いメトリックで現れる。どちらの場合も見える症状は同じで、パケットはトンネルのアダプタから出て消える。
ゲストのプレフィックスのルートの隣に、アダプタとそのメトリックを表示する。その二つの出力で所有権の問いに一目で答える。
Get-NetAdapter | Select-Object Name, InterfaceIndex, InterfaceMetric
Get-NetRoute -DestinationPrefix 192.168.56.0/24
route print -4 | Select-String '192.168.56'ルートが変わったのにアダプタのメトリックが変わっていなければ、クライアントが競合するルートを入れた。メトリックが変わっていれば、クライアントがアダプタの順序を変えた。どちらも修正でき、修正する場所は異なる。
ゲストのNAT範囲が衝突である場合
VirtualBox NATは既定で10.0.2.0/24を使い、同じ範囲を押し出すトンネルは、ゲストにその通信を実際の宛先ではなく自分のNATゲートウェイへ送らせる。パケットはホストを出ないので、反対側のファイアウォールログには決して現れない。Docker Machineにもホストオンリープランで同じ種類の衝突があり、そのプランを変えるにはマシンとその証明書を作り直す必要があり得る。
置き換え先は、トンネルが既に広告している範囲、次にオフィスネットワークが使っている範囲、次にこのホストのすべての仮想アダプタが主張した範囲を並べて選ぶ。ルーティングを壊すのは重複であり、似ているかどうかは関係ない。一見まったく似ていなくても、ある範囲が別の範囲の完全な内側に収まることがある。
新しい範囲はマシンの作成時に設定するか、変更して再読み込みし、そのうえで失敗する接続をゲストから再テストする。重要なのはゲスト自身のテーブルだ。
VBoxManage modifyvm devbox --natnet1 10.77.0.0/24
vagrant reload devbox --provision
vagrant ssh devbox -c 'ip route get 10.20.0.15'クライアントと戦わずに経路を戻す
どのプラットフォームにもホストオンリーのプレフィックスを再び前に出す方法がある。macOSではホストオンリーインターフェースへの静的ルートが次の接続まで効く。Windowsでは仮想アダプタのインターフェースメトリックを下げれば優先され続ける。Linuxでは置換操作が一つのプレフィックスを覆う。三つとも回避策で、ルートを再主張するクライアントはそれを取り消す。
起動時の盲目的な再接続ではなく、チェックをスクリプトにする。接続のたびにゲストのプレフィックスのルートを出力する小さなスクリプトが、謎をログの一行に変える。
プロファイルがフルトンネルなら、ネットワークの所有者に分割トンネリングか文書化された例外を求める。セキュリティポリシーを迂回するルートを黙って足すのは修正ではなく、後で監査人を連れてくる二つ目の問題だ。
修正を両側で確認する
変更後にホストからゲスト、ゲストから社内ホスト、ゲストからインターネットの三つの経路を検証する。片方を戻してもう片方を壊す修正は、修理の衣を着た設定変更にすぎない。比較が同一条件になるよう、変更前に集めたのと同じ出力を採取する。
次の発生が再構築ではなく検索になるよう、変わったインターフェース、メトリック、ルートを時刻とともに記録する。そのメモは長いチケットのやり取りより価値がある。
ip -4 route get 192.168.56.10
traceroute -n -m 4 10.20.0.15
curl -sS -o /dev/null -w '%{http_code}\n' https://example.comホストが再びゲストに届き、ゲストがLANに届けば、始めたときの経路を取り戻したことになる。片方しか動かないなら、残る故障はもう一方の所有者の領域にあり、差分がどの領域かを教えてくれる。