トラフィックは本当に VPN を通っているのか? 確認する方法
経路の照会、最初のホップ、物理アダプターでのキャプチャ、外部からのアドレス確認は、それぞれ問いの別の部分に答えます。
トレイのアイコンから見ると、トンネルに入るトラフィックと静かにそれを迂回するトラフィックという二つの障害は同じに見えます。どちらの場合もクライアントは Connected と表示しますが、Connected はトンネルのインターフェースが存在し、クライアントが望んだ経路をインストールしたという意味にすぎないからです。一つのアプリケーションの一つのパケットがその経路を使ったかどうかは別の問いで、スタックの別の場所で答えます。四つの測定でその大半が決まります — 経路の照会、最初のホップ、物理アダプターでのキャプチャ、外部からの観察 — そしてサーバー側のセッション表示が残りを覆います。
パケットが進む経路から始めます
経路表が決定そのものなので、全体を読んで推測するのではなく、一つの宛先について尋ねます。Linux では ip route get がカーネルの選んだインターフェースと送信元アドレスを示します:
ip route get 203.0.113.10
ip route get 10.20.5.7Windows では Find-NetRoute -RemoteIPAddress 203.0.113.10 が route print -4 より役に立つ理由も同じです。勝った経路を報告し、存在するすべての経路ではありません。それでも 0.0.0.0 行のために一度は表を読んでください。そこに /1 の組があれば、フルトンネルのクライアントが既定経路を書き換えており、OpenVPN の redirect-gateway def1 が 0.0.0.0/1 と 128.0.0.0/1 をトンネル経由でインストールして、物理的な既定経路を削除せずに最長プレフィックス一致で既存の 0.0.0.0/0 に勝つため、二つの既定経路が共存しながらすべてがトンネルに入ります。
表を嘘に変える二つの細部があります。第一に、既定経路の数ではなく一致したプレフィックスを見てください — インターフェースのメトリックか /1 の組が勝者を決めるからです。第二に、すでに存在する接続は確立した経路を保ちます — トンネルが上がった後も、開いたセッションはリセットされるまで古い経路を使い続けることがあり、だから再接続が経路の問題を直したように見えるのです。動いているクライアント — ps ax | grep openvpn — はプロセスが起動したことしか証明しません。
内部の名前と公開の名前を一つずつ追跡します
経路の照会は意図を示し、経路は配送を示します。接続した状態で、内部であるべき名前とそうでない名前を追跡し、最初のホップを比較します:
traceroute intranet.corp.example
traceroute 1.1.1.1両方が同じ最初のホップなら、内部の名前はトンネルに入っておらず、障害はその上にあり、多くは公開アドレスに解決される名前か、インストールされなかった経路です。内部のトラフィックが 10.8.0.1 から出て、公開のトラフィックが 192.168.1.1 から出るなら、スプリットトンネリングは設定どおりに動いています。VPN ゲートウェイまで届いてタイムアウトだけを返すトレースは、通常は戻り経路かサーバーのファイアウォールの問題で、転送経路の欠落ではありません。
フィルターされた ICMP はこの確認を嘘にし、両方のトレースで星印が並ぶと死んだトンネルに見えますが、通常はファイアウォールです。可能な場所で TCP ポートを試し — Linux では traceroute -T -p 443 — トレースはどのリゾルバーが答えたかを語らないことを忘れないでください: 名前はローカルで解決しつつ、トンネル経由でも到達できる場合があります。
トンネルではなく物理アダプターでキャプチャします
ネットワークが実際に何を見るかを示すのは物理リンクだけです。トンネルが上がった状態で、社内へのセッションは VPN サーバー宛ての暗号化ペイロードとして現れるはずで、10.20.5.7 への接続としては現れません:
sudo tcpdump -ni eth0 udp port 53
sudo tcpdump -ni eth0 host 10.20.0.5最初のフィルターはローカルに出て行く名前解決を捕まえます — これが最も多く最も静かな漏れで、ページは読み込まれ、リゾルバーがクエリを見ただけです。二つ目はトンネル内にしか存在すべきでない内部アドレスへの平文トラフィックを捕まえます。Windows では pktmon がドライバーなしで同じ仕事をします: pktmon filter add -p 53、次に pktmon start --capture --pkt-size 128、次に pktmon stop と pktmon format pktmon.etl -o capture.txt です。これらのフラグは Windows のビルドによって少し異なるので、構文を信じる前に pktmon filter add /? を確認してください。
漏れを見つけるには物理インターフェースでキャプチャします — トンネルでのキャプチャは、すでにそこにあると信じているパケットを含み、サーバーでは送信元がゲートウェイである読めない外側のパケットを含みます。どのインターフェースのバイトカウンターもパケットを説明し、プログラムを説明しません — トラフィックをプロセスに帰属させるにはソケットをプロセスに対応づけるモニターが必要です。
外部のサービスに尋ね、次にアプリケーションごとに尋ね直します
出口を証明する唯一の確認は外部からの応答、つまり見えた送信元アドレスを返すサービスです。インターフェースを選べるシェルから実行し、二回実行します:
sudo curl --interface tun0 https://example.net/ip
sudo curl --interface eth0 https://example.net/ip異なる応答は両方の経路の証拠と、特定のアプリケーションを試す方法を与えます — アプリケーションを束縛するか、一つの経路だけを持つネットワーク名前空間で実行し、遠端がどのアドレスを記録するかを見てください。同じ応答は興味深い障害で、束縛が効かなかったか、ホストと遠端の間の何かが届く前に送信元アドレスを書き換えています。Windows では curl --interface はアダプターの名前ではなくアドレスを求めます。
VPN アドレスを報告するブラウザーはそのブラウザーを証明します。メールクライアント、パッケージマネージャー、バックアップエージェント、二つ目のブラウザープロファイルはそれぞれ別の経路を取り得ます — 特にプロキシ設定やスプリットトンネルの経路がどれかを覆っている場合です。アドレスの変化自体は漏れの証明ではありません — ロードバランサーは見た出口によって違う応答を返すことがあるので、ページではなく記録された送信元アドレスを比較してください。
サーバー側の表示でピアを確認します
サーバーは別の問いに答えます — ピアが接続しているか、どれだけ運んだか、セッションが再起動したかです。サーバー側でピアが生きているのにクライアントのカウンターがほとんど動かないなら、クライアントの表が何と言おうと、アプリケーションのトラフィックはトンネルに入っていません。何も動かないと報告する利用者のために大量のデータを運ぶピアは、別の調査です。
ここには二つの罠があります。マスカレードされたトンネルはすべてのフローをゲートウェイ発に見せるので、ログやクライアント別の集計は一つのアドレスに潰れます。そしてクライアントはローカルホストとして扱われるので、誰かが VPN 経由でファイルをコピーしているかという問いには、サーバー上のファイル共有トラフィックかサーバー上のホスト監査が答えます — トンネルを見張ると端点と量は分かっても、ファイル名は分かりません。
設計上の判断と漏れを区別します
トンネルの外にあるものがすべて漏れではありません。リンクローカルとブロードキャストのトラフィックは設計どおりローカルに留まり、マルチキャストで見つかったプリンターは LAN で告知を続け、DHCP はローカルに出る必要があります。特定のインターフェースに束縛されたアプリケーションは意図的に経路表を迂回し、それを変えるのはファイアウォール規則、名前空間、ポリシー経路だけです。
IPv6 はチェックリストで独自の行に値します。IPv4 しか運ばないトンネルはデュアルスタックのホストに第二の使える経路を残し、デュアルスタックの宛先はそちらを好みます — リゾルバーが IPv6 で到達可能なら DNS も含みます。IPv4 の結果を完全とみなす前に、アダプターで IPv6 を無効にするか、トンネルがそれを運ぶことを確認してください。
確認が食い違うとき、その食い違いが通常は障害を名指しします:
| What you see | What it means | Next step |
|---|---|---|
| The route picks tun0 but the capture shows cleartext to 10.20.5.7 | Something bypassed the table: a bound app, a policy route or a session older than the tunnel | Reset the flow, check the app bind, check the ip rule list |
| The route picks eth0 for an internal name | The name resolves to a public address, or the route was never installed | Compare the resolved address with the routes the server pushes |
| The capture shows DNS to the LAN resolver | Resolver leak: data is tunneled, lookups are not | Point the resolver inside, or push it from the server |
| All four checks agree and one app still fails | Path selection is fine; suspect MTU, a per-app proxy or the far end | Test the same destination from a known-good client |
うまくいく順序はこうです — 接続の前後で経路表を保存し、内部の名前と公開の名前を一つずつ追跡し、物理アダプターで DNS をキャプチャし、特定のアプリケーションについてシェルから出口アドレスを返し、最後に量のためにサーバーを読みます。最初の四つが一致すれば、トンネルは思っているものを運んでおり、残る問題はその上にあります。二つが食い違うなら、食い違う組が障害であって、アイコンではありません。