ブリッジと NAT は、同じゲストを VPN に接続する二つの方法ではありません。両者はトンネルが関与する前にゲストのパケットが誰のものかを決めます。NAT モードでは、ハイパーバイザーがゲストの通信を書き換え、ホスト側のコードから送出します。そのためゲストは、ホストがそのコードに与えたルートに従います。ブリッジモードでは、ゲストは物理セグメント上で自分自身のリンク層の識別子を持ち、自分のデフォルトゲートウェイを選びます。そのためホストのトンネルは、LAN ルーターがトンネルを張っている場合を除いて、ゲストには無関係です。私は VM を「VPN 上にある」とみなすのをやめ、「そのゲストのデフォルトルートがどこを指すか」という問いとして扱うようにしました。以下のテストはモードごとに数分で終わり、推測なしで決着します。

NAT はゲストをハイパーバイザーのコードの背後に置き、ホストのルートが適用される

VirtualBox では、NAT のゲストは 10.0.2.0/24 上にいて、仮想ゲートウェイが 10.0.2.2、DNS プロキシが 10.0.2.3 にあり、物理ネットワークへの独自ルートはありません。外向きのパケットは NAT エンジンが引き取り、送信元がホストになるよう書き換えて、ホストの IP スタックに渡します。そこから先、ゲストの通信はホストのフローであり、ルート検索は宛先で行われます。0.0.0.0/1 と 128.0.0.0/1 をホストに設定するフルトンネルのクライアントは、VM の存在すら知らないままその通信を捕まえます。Oracle の VirtualBox ネットワークの章には、この既定値が載っています。自分の環境でアドレスを確認したいときに使えます。

libvirt の既定ネットワークも 192.168.122.0/24 から同じ場所に到達します。dnsmasq が lease を配り、ホストがサブネットをマスカレードするので、ゲストのパケットは再びホストのルーティング判断に届きます。例外は、ルートではなくプロセスで通信を選ぶクライアントです。スプリットトンネルの一覧がブラウザーだけを含み、他に何も含まないなら、NAT エンジンはその一覧にいません。ゲストはトンネルなしでマシンを出ていき、ホストのブラウザーだけが保護されているように見えます。同じサブネット、正反対の結果です。

ブリッジは物理 LAN 上にゲスト自身の居場所を与える

ブリッジのゲストには、実アダプターにつながる仮想 NIC が与えられ、独自の MAC アドレスを持ち、物理ネットワークから DHCP の lease を取ります。デフォルトゲートウェイはハイパーバイザーではなく LAN ルーターで、フレームはそのアダプターからケーブル上に出ていきます。ホストのトンネルのルートはホストの表にあり、決して参照されません。ゲストのフレームはホストの IP スタックに入らないからです。

これは両方向に効きます。mDNS と SMB の閲覧が機能し始めるのは、ゲストが LAN のブロードキャスト通信を見るからであり、ゲストは間にホストのファイアウォールを挟まず、同じセグメントの他のマシンから到達できるようになります。ブリッジは、既存のトンネルにゲストを通す手段でもありません。VM をホストの WireGuard や OpenVPN のインターフェースにつなぐのは、VirtualBox や libvirt が代わりにやってくれることではありません。ブリッジのゲストをトンネルに通す必要があるなら、トンネルはその LAN のどこかで終端しなければなりません。

議論を終わらせるテスト

両方のモードで同じ確認を実行し、答えを書き留めます。

  • ホスト側では、curl -s https://ifconfig.me が公開 v4 アドレスを返します。
  • ゲスト側では同じコマンドに加え、デフォルトゲートウェイのために Linux なら ip route、Windows なら Get-NetRoute -DestinationPrefix 0.0.0.0/0 を実行します。
  • リゾルバーの識別:ゲストで resolvectl status または cat /etc/resolv.conf を実行し、10.0.2.3 を指すのか LAN のサーバーを指すのかを見ます。
  • アドレスファミリー:ip -6 addr show scope global と v6 のリクエストを一つ。v4 のトンネルは、ゲストが持つかもしれないグローバル v6 アドレスについて何も語らないからです。

公開アドレスが一致していれば、ゲストはホストの経路に載っています。ゲストのアドレスが LAN の通常の出口と一致していれば、載っていません。多くの人が飛ばすのは対照実験です。ホストのトンネルを落として、ゲストのリクエストを繰り返します。それでもゲストが閲覧を続けるなら、モード名が何を示唆していても、そのゲストはホストのトンネルに依存していませんでした。NAT モードなら、ホストのトンネルを落とした時点でゲストはインターネットを失うはずです。ただしクライアントがトンネル外の通信を許可する設定になっている場合は別で、それ自体を知っておく価値があります。

二つのシグナルは嘘をつきます。ping の成功は到達性を示すだけで、出口の経路を示しません。そして DNS はホストのリゾルバー経由で 10.0.2.3 のプロキシが答えているのに、TCP は別のルートを通ることがあります。ページは読み込まれるのにログインが完了しない、というのはそういうことです。

どのモードが作業に合うか

モードはルーティングの判断なので、習慣ではなく要件から選びます。

RequirementMode that fits
Every guest flow must exit through the host tunnelNAT, with a host client that tunnels by route, verified from inside the guest
The guest needs its own VPN account or profileBridged, or NAT with a client running inside the guest, not both
The guest must serve SSH, SMB, or a dev server to the LANBridged; NAT needs a port forward, which does not change the outbound path
The guest must stay invisible to the LANNAT; a bridged guest is another host on the segment
The guest needs a real public IPv6 addressBridged; VirtualBox NAT mode has no IPv6 forwarding
Isolation from the LAN with access to the hostHost-only adapter, not NAT

一行目が人が引っかかる場所です。NAT とホストのフルトンネルクライアントの組み合わせは、確かにゲストを覆いますが、クライアントがルートでトンネルし、ホストの上流がそのトンネルである間だけです。クライアントをブラウザーだけの許可リストに移すと、どこにもエラーが出ないまま覆いは消えます。四行目は逆の誤りです。便宜のためにブリッジしたゲストが、社内 LAN で静かに SMB や SSH に応答し始めます。

VPN のせいにされる障害

Windows では NAT の変換は VirtualBox の VM プロセスの中で動くので、アプリごとのクライアントは仮想マシン向けの包括的な規則ではなく、まさにそのイメージを一覧に入れる必要があります。クライアントの更新がプロセスの許可リストを作り直すと、NAT のゲストが最初に覆いを失い、報告は「ホストは正常なのに、VM は LAN には届くがインターネットには届かない」という形で上がってきます。

Wi-Fi へのブリッジも定番です。アクセスポイントは外部の送信元 MAC を持つフレームをめったに転送しないので、wlan0 へのブリッジは完全に失敗するか、AP のクライアント分離が落とし始めるまで動きます。VirtualBox はそれでも一覧に無線アダプターを出します。ホストが Wi-Fi にいてゲストをブリッジする必要があるなら、想定せずにテストを計画してください。

三つ目は MTU です。ブリッジのゲストは LAN の 1500 バイト MTU を保ちます。そのゲストが自前の WireGuard クライアントを 1420 で動かすと、小さなリクエストは通るのに大きな TLS ハンドシェイクが止まります。NAT の下ではホストのトンネルの MTU はホストの問題ですが、ゲストは依然として 1500 を信じており、don't-fragment ビットを立てた UDP は同じように消えます。

モードを記録し、アダプターを変えたら再確認する

モード、ブリッジが使うホストのインターフェース、ゲストのデフォルトゲートウェイ、リゾルバー、v4 と v6 の出口アドレスを記録します。その記録が次の障害を安くします。ノート PC がドックから Wi-Fi に移ると、ブリッジのゲストはブリッジを伝って別の物理アダプターに移り、別のサブネットで lease を取り直すことがあります。一方 NAT のゲストは 10.0.2.x のアドレスを保ち、黙って別の上流を引き継ぎます。

チケットを閉じる前に、次の各項目を確認してください。

  • ゲストの出口アドレスがホストの出口アドレスと異なるので、ホストのトンネル上にありません。
  • リゾルバーが 10.0.2.3 のプロキシか LAN のサーバーで、どちらが答えたかを把握しています。
  • トンネルの設計が v4 のみなら、ゲストにグローバル v6 アドレスは存在しません。
  • ホストのトンネルを落とすとゲストは閲覧をやめるか、依存していなかったことを今は知っています。
  • ゲストは関係のない LAN のブロードキャスト通信を見ていません。

関連記事