V2RayのDNSリーク検出方法とdnsモジュールによる漏洩防止設定

DNSリークが起きる原因を解説し、再現可能な検出手順と、dnsアウトバウンドやdomainStrategyを使った実用的な設定例でDNSクエリをプロキシ経由にする方法を紹介します。

この記事の概要

この記事は、v2rayNまたはXrayで正常に接続できるものの、検出ページに日本国内の通信事業者DNSが表示されるユーザー向けです。通信経路、基準値の確認、Xray設定、トラブルシューティングの順に解説します。読み終えると、システムDNS、ブラウザーの暗号化DNS、プロキシコアによる名前解決を区別し、ポート53のクエリが実際にプロキシのアウトバウンドへ入っているか確認できます。

DNSリークはどこで起きるのか

ドメインへアクセスすると、アプリは通常まずドメインをシステムリゾルバーへ渡し、解決されたIPへ接続します。システムプロキシが制御できるのはプロキシ設定に対応したHTTPまたはSOCKS接続だけで、OSがUDP 53やTCP 53へ送るDNSクエリを自動的に書き換えることはありません。そのため、WebトラフィックがVMessまたはVLESSノード経由でも、ドメイン検索だけはネットワークアダプターに設定された通信事業者のリゾルバーへ直接送られる場合があります。

リークはノードの停止を意味しません。より正確には、サービスへの接続はプロキシを通る一方、名前解決は想定外の別経路を通っている状態です。検出ページに日本国内のネットワーク事業者、ルーターのアドレス、企業内ネットワークのリゾルバーが表示された場合は、システム設定と照らして判断します。パブリックDNSの名前が表示されても、それだけでプロキシ経由とは証明できません。同じパブリックリゾルバーへは、直接接続でもリモートノード経由でもアクセスできるためです。

アプリがドメインを検索システムリゾルバーローカルポート53DNSアウトバウンドプロキシノードが転送リモートリゾルバー

Xray設定のトップレベルにあるdnsモジュールは、主にコア自身の名前解決やマッチングに必要な処理を担当します。たとえばノードサーバーのドメインを解決したり、ルーティングルール用に宛先IPを取得したりします。設定ファイルに存在するだけで、OSが行うすべてのDNSクエリを引き受けるわけではありません。アプリがシステムへ送るDNSを処理するには、受け付ける入口、システムDNSの向き先、対応するアウトバウンドの3つがそろっている必要があります。

ブラウザー内蔵の暗号化DNSは別の経路です。通常はHTTPSでDNSサービスへ接続するため、ローカルのポート53にはアクセスしません。ブラウザーの通信がシステムプロキシの制御下にあれば、この接続もプロキシを通る可能性があります。一方、アプリがシステムプロキシを迂回すれば直接外へ出ることもあります。トラブルシューティングでは、まずブラウザーのセキュアDNSを一時的に無効にしてシステムDNSの経路を検証し、最後に設定を戻してブラウザー側を個別に確認してください。

結論:まず名前解決の経路を分けてから設定を変更する

見慣れないDNSアドレスが表示されても、すぐにノードを変更しないでください。クエリがシステムのポート53、ブラウザーの暗号化DNS、Xrayコアのどこから発生したのかを確認します。3つの経路では修正箇所が異なるため、混ぜて検証すると結果が食い違います。

再現可能なDNSリーク検出の基準値を作る

1回の検出結果は、キャッシュ、ブラウザーの先読み、リゾルバーのエニーキャスト拠点の影響を受けやすいものです。より確実にするには、同じネットワーク、同じノード、同じブラウザー設定で2回テストします。1回目はDNSを制御していない状態の結果を記録し、2回目は設定適用後にキャッシュを削除して再検証します。各回でランダムなドメインを少なくとも3回検索し、古いキャッシュによって実際の名前解決が省略されるのを防ぎます。

  1. ネットワークアダプターのDNSを記録する

    PowerShellを開き、Get-DnsClientServerAddress -AddressFamily IPv4を実行します。使用中のネットワークアダプター名とServerAddressesを記録してください。家庭内ネットワークではルーターのアドレスが表示されることが多く、パブリックネットワークでは2つのリゾルバーアドレスが直接配布される場合もあります。

  2. 検証への干渉要因を無効にする

    ブラウザーのセキュアDNSを一時的に無効にし、ネットワークスタックを変更する他のプログラムを終了します。その後、ipconfig /flushdnsを実行してWindowsのDNSキャッシュを消去し、開いている検出ページを閉じます。

  3. 直接接続時の結果を記録する

    v2rayNのシステムプロキシを切断し、DNS検出ページを開いて2回連続でテストします。リゾルバー数、ネットワークの所属先、地域を記録してください。このデータがローカル経路の基準値になります。ページに表示された国名や地域名だけを保存しないようにしましょう。

  4. 接続後に再検証する

    対象ノードへ接続し、v2rayNのローカルSOCKSポート10808とHTTPポート10809が待ち受け中であることを確認します。もう一度キャッシュを消去して検証してください。結果が直接接続時の基準値と完全に同じなら、システムDNSが制御されていない可能性が高いです。

  5. 指定した入口を検証する

    ローカルDNS入口を設定した後、nslookup example.com 127.0.0.1を実行します。アドレスが返され、Xrayのログにdns-indns-outが現れて初めて、クエリが想定した経路へ入ったと判断できます。

53
システムDNSの標準ポート
10808
サンプルSOCKSポート
10809
サンプルHTTPポート
3回
推奨する検証回数

サンプル環境はWindows 11 24H2、v2rayN 7.12.5、Xray-core 25.6.8です。最初の直接接続テストでは、ローカルネットワークのリゾルバーエンドポイントが3つ表示され、平均検索時間は約18ミリ秒でした。リモートノード経由で指定したリゾルバーへ接続すると、選択したパブリックDNSサービスだけが表示され、連続検索の平均は約136ミリ秒になりました。遅延の増加はノード間転送に伴う通常のコストで、実際の値は経路の距離によって変わります。136ミリ秒を固定の基準値と考えないでください。

dnsの入口とアウトバウンドでプロキシ経路へ取り込む

以下の設定例では、ローカルの127.0.0.1:53をDNS入口として使い、TCPとUDPのクエリをdns-outというタグのアウトバウンドへ渡し、既存のproxyアウトバウンドで転送します。適用前に、現在有効な設定で選択中ノードのアウトバウンドタグを確認してください。実際のタグがproxyでない場合は、proxySettings.tagを既存のタグへ変更します。

ポート53は、システムサービス、仮想ネットワークアダプターのプログラム、ローカルDNSソフトウェアによってすでに使用されている可能性があります。また、低いポート番号の待ち受けには通常、管理者権限が必要です。まず入口ポートを1053に変更してXray設定が起動できるか確認できますが、WindowsのネットワークアダプターのDNS設定には非標準ポートを直接指定できません。システムのクエリを正式に引き受けるには、ポート53を解放し、アクティブなネットワークアダプターのIPv4 DNSを127.0.0.1へ向ける必要があります。

{
  "dns": {
    "servers": [
      {
        "address": "1.1.1.1",
        "domains": [
          "geosite:geolocation-!cn"
        ]
      },
      {
        "address": "223.5.5.5",
        "domains": [
          "geosite:cn"
        ]
      }
    ],
    "queryStrategy": "UseIPv4",
    "disableCache": false
  },
  "inbounds": [
    {
      "tag": "dns-in",
      "listen": "127.0.0.1",
      "port": 53,
      "protocol": "dokodemo-door",
      "settings": {
        "address": "1.1.1.1",
        "port": 53,
        "network": "tcp,udp"
      }
    }
  ],
  "outbounds": [
    {
      "tag": "dns-out",
      "protocol": "dns",
      "settings": {
        "address": "1.1.1.1",
        "port": 53,
        "network": "tcp",
        "nonIPQuery": "drop"
      },
      "proxySettings": {
        "tag": "proxy"
      }
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "inboundTag": [
          "dns-in"
        ],
        "outboundTag": "dns-out"
      }
    ]
  }
}

queryStrategy: UseIPv4は内蔵DNSがIPv4の結果を優先して返すようにします。現在のノードやローカルネットワークでIPv6のアウトバウンドが安定しない場合に適しています。経路がIPv6に完全対応しているなら、実際の宛先に応じてUseIPへ変更できます。ただし、プロキシノード、システムルート、リモートリゾルバーも同時に確認し、AAAAレコードだけ取得して利用可能なIPv6アウトバウンドがない状態を避けてください。

nonIPQuery: dropは、DNSアウトバウンドでAおよびAAAA以外のクエリを破棄します。一般的なWebサイトの名前解決だけが必要な軽量構成には適していますが、TXTやSRVなどのレコードに依存する企業サービスへ影響する可能性があります。メール認証、サービスディスカバリー、社内アプリの名前解決に異常が出た場合は、この項目を削除して再検証してください。問題をVMessやVLESSのプロトコルのせいにしてはいけません。

結論:入口、ルーティング、システムの向き先をすべてそろえる

トップレベルのdns設定だけでは、システムのクエリが直接接続される可能性があります。ローカル入口だけ用意しても、ネットワークアダプターのDNSを127.0.0.1へ向けなければ実際のリクエストは届きません。制御が完了したかどうかは、ポートの待ち受け、ログへの記録、再検証の結果の3項目がすべて成立することを基準に判断します。

domainStrategyはDNSリーク防止スイッチではない

routing.domainStrategyは、ルーティングモジュールがルールにマッチさせる際、対象ドメインをIPへ解決するかどうかを決めます。これは「ルーティングルールのために追加の名前解決を行うか」を制御するもので、「OSのDNSをどこから送るか」を決めるものではありません。AsIsからIPIfNonMatchへ変更すると、IPルールがマッチする機会を得られる場合がありますが、ネットワークアダプターから送信されるUDP 53のリクエストを自動的に遮断することはありません。

名前解決の動作 適用の目安
AsIs 元のドメイン名のままドメインルールを実行し、IPルールのために自動解決しない ルールの中心がdomainやgeositeで、追加の名前解決を減らしたい場合
IPIfNonMatch ドメインルールにマッチしない場合に対象を解決し、その後IP系ルールを試す geositeとgeoipを併用し、マッチ範囲とクエリ数のバランスを取る場合
IPOnDemand 対象IPが必要になる可能性のあるルールに遭遇した時点で先に解決する IPルールを優先し、早い段階での名前解決が必要な構成

よく使われる設定はIPIfNonMatchです。まずドメインルールを適用し、マッチしなければgeoipや明示的なIPルールのために解決します。これにより、すべてのリクエストで事前に名前解決を発生させず、IPによる振り分けも維持できます。ルーティングリストの先頭近くにIPルールを置いている場合、IPOnDemandはコアによるDNSクエリ数を大幅に増やす可能性があります。名前だけで選ばず、ログを確認しながら使ってください。

トップレベルのdns.serversによるドメイン振り分けとrouting.rulesは別のロジックです。前者は特定のドメインをどのリゾルバーへ渡すかを決め、後者は接続をdirect、proxy、blockのどれへ送るかを決めます。geosite:cnを近隣のリゾルバーで解決しつつ、すべてのDNSクエリをリモートノード経由にしたい場合は、この2つの目的が衝突しないか確認してください。リゾルバーのアドレスと転送経路は分けて設計する必要があります。

v2rayNで設定を適用し、上書きを防ぐ

v2rayNの通常のサブスクリプションノードでは、クライアントが実行用設定を生成します。一時JSONファイルを直接編集しても、サーバーの切り替え、サブスクリプション更新、コア再起動の後に上書きされる可能性があります。DNSのインバウンドとアウトバウンドを完全に制御するには、カスタム設定サーバーを使い、既存ノードのパラメーター、ルーティングルール、上記のDNS構成を有効な設定ファイルへ統合します。

  1. コアの種類を確認する

    「設定」→「パラメーター設定」→「Core タイプ」を開き、現在のサーバーがXrayコアを使用していることを確認します。保存後にコアを再起動し、別のコアで設定構文が解釈されるのを防ぎます。

  2. アウトバウンドタグを確認する

    現在の実行設定を開き、選択したノードに対応するoutbounds.tagを探します。この記事の例ではproxyを使っています。実際のファイルで別の名前になっている場合は、DNSアウトバウンドのプロキシタグも同じ名前にします。

  3. カスタム設定を追加する

    「サーバー」→「カスタム設定サーバーを追加」から、用意したJSONファイルを選択します。まずローカルDNS入口のポート1053を残したまま起動テストを行い、構文とルーティングログに問題がないことを確認します。

  4. ポート53を解放する

    Get-NetUDPEndpoint -LocalPort 53Get-NetTCPConnection -LocalPort 53を実行して使用状況を確認します。競合を解消したら設定のポートを53へ戻し、管理者権限でv2rayNを再起動します。

  5. アクティブなネットワークアダプターを変更する

    現在アクティブなネットワークアダプターのIPv4 DNSサーバーを127.0.0.1に設定します。ローカルの通信事業者DNSを予備として同時に残さないでください。ローカルサービスが一時的に応答しないと、システムが予備のリゾルバーへ自動的に切り替える可能性があります。

  6. キャッシュを消去して再検証する

    ipconfig /flushdnsを実行し、nslookup example.com 127.0.0.1で入口を検証してから、3回の検出を行います。完了後、ログでdns-indns-outに到達していることを確認してください。

システムプロキシだけを使い、TUNを使用していない場合、システムプロキシ設定に従わないアプリの接続は直接通信する可能性があります。DNSの制御で解決できるのは名前解決の経路だけで、全トラフィックの制御を代替するものではありません。TUNを使う場合も、DNSハイジャックとルーティングルールを確認してください。従来のUDP、TCP 53は捕捉できますが、アプリが独自に確立するHTTPS名前解決は通常の443トラフィックとして扱われ、行き先は該当アプリの通信ルールで決まります。

よくあるエラーと確認の順番

トラブルシューティングでは、まずコアが起動しているか、次にポートが待ち受けているか、最後に検出ページを確認します。検出ページは経路の末端にあるため、前の2項目が失敗している状態で何度更新しても情報は増えません。ログレベルは一時的にinfoへ設定し、原因を特定したら通常の設定へ戻してください。大量のアクセス記録が長期間生成されるのを防げます。

エラー:failed to listen TCP on 127.0.0.1:53

原因と対処:ポート53が別のプロセスに使用されているか、現在のプロセスに十分な権限がありません。まずPowerShellでTCPとUDPのエンドポイントを調べ、競合するサービスを停止してから、管理者権限でコアを再起動します。

エラー:failed to find an available destination

原因と対処:ノードサーバーのドメインまたはDNSの宛先をブートストラップ解決できません。サーバーアドレスの入力ミスを確認し、一時的に直接到達できるブートストラップリゾルバーを用意します。ノード確立後に、目的の経路へ戻してください。

エラー:outbound proxy not found

原因と対処:proxySettings.tagが存在しないアウトバウンドタグを参照しています。実際の実行設定を開き、選択中ノードの正確なtagをコピーして、DNSアウトバウンドの参照先も同じように変更します。

現象:nslookupはタイムアウトするがコアにエラーがない

原因と対処:ネットワークアダプターが127.0.0.1を参照していないか、ファイアウォールがローカルUDP 53を遮断している可能性があります。まずnslookup example.com 127.0.0.1を明示的に実行し、その後ネットワークアダプターの設定とローカルルールを個別に確認します。

現象:検出結果にリゾルバーが2つ表示され続ける

原因と対処:ブラウザーのセキュアDNS、IPv6 DNS、または予備のネットワークアダプターが独自に名前解決している可能性があります。ブラウザーの暗号化DNSを無効にし、IPv6 DNSアドレスを確認し、使用していない仮想ネットワークアダプターを無効にしてから再検証します。

ログにリクエストがdns-inへ到達しているのにdns-outへ進んでいない場合は、ルーティングルールの順序を確認します。Xrayのルーティングは上から順にマッチするため、先にある汎用的なインバウンドルールがリクエストをdirectへ送っている可能性があります。dns-in向けのルールを汎用ルールより前に置き、重複するtagがないことも確認してください。

Xrayのログが正常でシステムのクエリも問題ないのに、ブラウザーの検出結果だけが異なる場合は、ブラウザーが独立した名前解決経路を使っていることが多いです。セキュアDNSを戻した後は、通常のHTTPSトラフィックとして検証します。ポート53の設定を変更し続けるのではなく、ブラウザーのプロセスがシステムプロキシまたはTUNを通っているか確認してください。

0.0.0.0:53
意図せずLANへ公開しない
127.0.0.1:53
推奨するローカル待ち受けアドレス
1053
起動テスト用ポート

待ち受けアドレスは127.0.0.1のままにし、手軽だからという理由で0.0.0.0へ変更しないでください。後者ではすべてのネットワークアダプターで待ち受けるため、LAN内の端末からそのポートへアクセスできる可能性があり、ファイアウォール設定の対象も広がります。他の端末へDNSサービスを提供する明確な目的がある場合に限り、LANアドレスへバインドし、アクセス制御を設定してください。

最終判断:4項目で一連の動作を確認する

ネットワークアダプターのDNSが127.0.0.1を指し、ローカルポート53が正常に待ち受け、ログにdns-inからdns-outへの流れが記録され、検出結果に直接接続時の基準リゾルバーが表示されない。この4項目が同時に成立して初めて、システムDNSが想定したプロキシ経路へ入ったと確認できます。

v2rayN をダウンロード