1台のデスクトップでVPNクライアントを2つ動かす:何が衝突し、何が機能するか
2つのクライアントがデフォルトルート、リゾルバ、フィルタドライバを奪い合います。誰が出口を所有しているかを記録し、2つ目のトンネルをVMかnetnsで分離します。
二つ目のクライアントが接続すると、一つ目のリソースが名前解決できなくなり、チケットには業務用VPNが個人用を壊したと書かれています。障害という意味では何も壊れていません。両方のクライアントは設計どおりに動き、マシンのルーティングテーブルは一つだけです。衝突は、各クライアントが自分のものとみなす四つのリソースをめぐるものです。順番に片付けていけば、修正はたいてい修理ではなく設計上の選択になります。
ステップ 1:どちらのクライアントが出口を所有しているか調べる
何かを変更する前に、現在の出口の決定を読み取ります。公開アドレスへのルート検索は、パケットが今どのインターフェースと次のホップを使うかを示し、それがどちらが勝ったかの答えです。クライアントが作成したインターフェース名と比較します。名前には通常、製品名やプロトコル名が含まれます。検索が予想していなかったトンネルを指しているなら、すでに衝突を見つけています。
ip route get 1.1.1.1
ip route show default
route print
中にはデフォルトルートをまったく置き換えず、アドレス空間の下半分と上半分にそれぞれ半分ずつ追加し、合わせて全体を覆うクライアントもあります。これでは元のデフォルトルートが見えたままになり、手作業の修理が正しく見える一方で、通信は依然としてトンネルから出ていきます。デフォルトエントリの有無だけでなく、メトリックとプレフィックス長を読み取ります。
両方のクライアントが同じメトリックで同じプレフィックスを主張しているなら、そこで止まります。カーネルは片方を選び、もう片方は何も運ばないまま接続済みに見えます。
ステップ 2:リゾルバと重複するプレフィックスを確認する
DNSは二つ目の衝突で、特徴的な症状を生みます。アドレスは機能するのに名前が失敗するのです。各クライアントが自分のリゾルバを押し込み、後続のクエリでは最後に書き込んだ側が勝ちます。クライアントの設定画面を読むのではなく、リゾルバサービスにリンクごとに何を使っているか尋ねます。
resolvectl status
Get-DnsClientServerAddress
dig +short intranet.corp.example
次に、二つのネットワークが使うプライベートプレフィックスを比較します。両側が同じ範囲から割り当てている場合、クライアント側の工夫では直りません。マシンはどの10.0.0.0/8の宛先がどのトンネルに属するかを判別できないからです。片側を採番し直すか変換する必要があり、それはネットワークの所有者との会話であって、設定変更ではありません。重複は、正直な答えが「設計を変えるしかない」となる唯一の衝突です。
プレフィックスが重複しているならここで止まります。このチェックリストの以降はすべて、重複していないことを前提にしています。
ステップ 3:持続する分離パターンを選ぶ
信頼できるパターンは、同じルーティングテーブルに対して二つのクライアントを動かすことを避けます。一つのクライアントで両方のプライベートネットワークに届くスプリットトンネルポリシーを使うのが最も簡単で、宛先が重複せず、ポリシーの所有者が同意する場合に限ります。仮想マシンかネットワーク名前空間はその次の段階で、それぞれが独自のテーブルとリゾルバを持ちます。
sudo ip netns add vpn2
sudo ip netns exec vpn2 ip link show
sudo ip netns exec vpn2 curl -sI https://intranet.corp.example/
名前空間は二つ目のOSなしで仮想マシンと同じ分離を与えますが、粗い縁があります。トンネルデバイスをその中へ移す必要があり、アプリケーションはその内部で起動しなければなりません。管理された業務クライアントと並べて個人用VPNを使うなら、別の物理デバイスがしばしば最も驚きの少ない選択肢です。トンネルの中にトンネルを重ねるのは分離パターンではありません。内側のエンドポイントは外側のトンネル経由で到達可能なままでなければならず、この構成はさらにMTUと遅延の問題を追加します。
一つのパターンを選び、その理由を書き留めます。一つのアプリケーションに名前空間を使い、残りにスプリットトンネルを使うと、元の衝突がデバッグしにくい形で再現されます。
ステップ 4:同じセッションから両方のネットワークを検証する
各プライベートネットワークのリソースを一つずつ、アプリケーションが実際に動く環境からテストします。アプリが名前空間の中で動くなら、自分のシェルからではありません。出口インターフェース、解決されたアドレス、応答コードを同時に確認します。三つのうち一つの成功が、他の失敗を隠すことがあるからです。再起動後にも繰り返します。クライアントが起動する順序がどちらが勝つかを決めるからです。その順序こそ、人々が記録し忘れる部分です。
curl -sI https://intranet.corp.example/
curl -sI https://files.personal.example/
ip route get 10.20.30.40
各ネットワークについて、クライアントのバージョン、インターフェース、リゾルバの状態、プレフィックスを記録します。クライアントが更新されてルートの挙動が変わったとき、その記録が五分の修正と作り直しの差になります。次に担当する人は、どのトンネルが先に上がったかというあなたの記憶を共有しません。
デフォルトルートを所有するインターフェース、各名前が使うリゾルバ、二つ目のトンネルを分離するパターン、再起動後にネットワークごとに一度のリクエストの結果を挙げられるなら、チェックリストは完了です。それ未満は、今日たまたま動いている設定にすぎません。