V2RayのDNS振り分け設定|国内・海外ドメインの名前解決とDNS汚染対策

V2Ray内蔵DNSの問い合わせ順序、ドメイン別のDNSサーバー指定方法、FakeDNSとドメイン戦略の連携を解説します。

この記事の概要

DNSを振り分けるには、「どのサーバーで名前解決するか」と「問い合わせをどの出口に通すか」の両方を設定する必要があります。ノードに正常に接続でき、国内外のドメインルールを細かく設定したい方向けに、システムDNSとコアDNSの違いから、サーバー選択、ルーティング戦略、設定例、ログによる確認方法まで解説します。通常のシステムプロキシ環境では、最初からFakeDNSを有効にする必要はありません。まず再現性のある基本設定を作ると、問題を切り分けやすくなります。

1. DNS振り分けの前提:問い合わせをコアに通す

V2RayにDNSサーバーを設定しても、PC上のすべてのアプリがそのサーバーを使うわけではありません。内蔵DNSが処理するのは、ルーティングで宛先IPを判定する場合や、一部のアウトバウンドでドメインを解決する場合、DNSインバウンド転送を設定した場合など、コアによる名前解決が必要な問い合わせです。アプリ自身が送信するDNS問い合わせは、適切な横取りまたは転送経路を通った場合に限り、このルールで処理されます。

アプリがドメインにアクセス プロキシが宛先を受信 ルーティングで名前解決 DNSサーバーを選択 アウトバウンドルールに一致

この流れは、「アプリがドメインをプロキシに渡し、ルーティングで名前解決が必要になる」場合の一例です。ドメインルールによってプロキシへの接続が決まっていると、コアはローカルで宛先IPを調べず、ドメインをそのままリモートへ渡すことがあります。アプリが先に名前解決してIPアドレスをプロキシに渡した場合、コアが受け取るのはドメインではなくIPアドレスです。

接続方式一般的なDNS動作確認ポイント
ブラウザーでHTTPプロキシを使用プロキシリクエストには通常ドメインが含まれるが、ブラウザー独自の名前解決やプリフェッチが行われる場合もあるセキュアDNS、プロキシの除外リスト
アプリでSOCKS5を使用アプリはドメインを渡す場合と、端末で先に名前解決する場合があるリモートでのドメイン解決が有効か
デスクトップのTUNモード仮想ネットワークアダプターのルーティングとDNSの横取り設定によるDNSが実際に横取り経路を通っているか
AndroidのVPNモードクライアントが通信を横取りできるが、除外したアプリは元のネットワークを使う場合があるアプリごとの設定、プライベートDNSの設定

v2rayNはデスクトップクライアントです。v2rayNGはXrayコア、v2flyNGはV2Flyコアを使用します。画面に「DNS」と表示されているからといって、設定をそのまま相互に流用できるわけではありません。この記事のコード例は、V2Ray/V2Flyで一般的な従来形式のJSON構造です。実際に読み込めるかどうかは、使用中のコアのバージョンとクライアントが生成する設定で確認してください。

2. 内蔵DNSがDNSサーバーを選ぶ仕組み

dns.serversには文字列形式のアドレスのほか、domainsを含むサーバーオブジェクトも指定できます。ドメインがオブジェクトのルールに一致すると、そのサーバーが優先的な問い合わせ先になります。複数のオブジェクトに一致する場合は、リスト内の順序も影響します。配列全体を「常に1番目がメイン、2番目が予備」と単純に解釈しないでください。

  1. 静的マッピングとキャッシュを確認します。 設定内のdns.hostsや既存のキャッシュが結果に影響することがあります。そのため、DNSサーバーを変更しても、新しいネットワーク問い合わせがすぐに発生するとは限りません。
  2. ドメインに一致するサーバーを選択します。 たとえばgeosite:cnはルールデータベース内のドメイン群を参照するもので、ドメインの末尾から接続先の地域をその場で判定するものではありません。
  3. 失敗時のフォールバックを確認します。 優先サーバーから利用可能な結果が得られず、フォールバックが許可されている設定では、フォールバック対象のサーバーが順に試されます。skipFallback: trueが設定されたサーバーは、通常のフォールバック候補になりません。
  4. 名前解決結果を返します。 結果は問い合わせるアドレスファミリー、expectIPsによるフィルタリング、バージョンごとの動作にも左右されます。再試行の有無は、使用中のバージョンのドキュメントとログで確認してください。

expectIPsを使うと、名前解決で返されるIPアドレスの範囲を絞り込めますが、結果の真正性を検証する仕組みではありません。共有CDN、国境をまたぐサーバー配置、ルールデータベースの分類差異によって、正当な結果が除外されることもあります。初回の設定では追加せず、問い合わせ経路が安定してから個別に試してください。

3. 国内・海外でDNSを使い分ける:DNSと出口をセットで設定

以下は既存の設定に追加するための例です。国内カテゴリのドメインには223.5.5.5を優先し、それ以外のドメインにはhttps://1.1.1.1/dns-queryを使用します。後者は通常のDoHアドレスとしてコアに設定し、宛先IPルールでプロキシ出口を選択します。この例は起動可能な完全設定ではなく、ノード情報も含みません。

53
国内DNSのUDPポート(例)
443
DoHのHTTPSポート(例)
2種類
設定例で使うDNSサーバー
{
  "dns": {
    "servers": [
      {
        "address": "223.5.5.5",
        "domains": [
          "geosite:cn"
        ],
        "skipFallback": true
      },
      {
        "address": "https://1.1.1.1/dns-query"
      }
    ]
  },
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "ip": [
          "223.5.5.5"
        ],
        "port": "53",
        "network": "udp",
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": [
          "1.1.1.1"
        ],
        "port": "443",
        "network": "tcp",
        "outboundTag": "proxy"
      },
      {
        "type": "field",
        "domain": [
          "geosite:cn"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": [
          "geosite:geolocation-!cn"
        ],
        "outboundTag": "proxy"
      },
      {
        "type": "field",
        "ip": [
          "geoip:cn"
        ],
        "outboundTag": "direct"
      }
    ]
  }
}
  • まずアウトバウンドのタグを確認します。 ここで使うdirectとproxyは、既存のoutboundsのtagと一致させてください。通常、直接接続にはfreedomを使用し、プロキシ接続には動作確認済みのノードを使います。
  • 既定の出口を確認します。 従来形式の設定では、ルールに一致しない接続は通常、最初のアウトバウンドを使用します。この例では既定の出口を定義していないため、既存の設定で明示してください。未分類の宛先が必ずプロキシ経由になるとは限りません。
  • 既存のルールを残します。 クライアントの設定に統合する際は、LAN、ブロック、必要なシステムルールを残し、並び順も確認してください。ルーティングでは最初に一致したルールが適用されます。
  • ルールファイルを用意します。 geosite:cn、geosite:geolocation-!cn、geoip:cnの利用には、対応するルールデータが必要です。分類データが不足している場合やファイルを読み込めない場合は、まず読み込みエラーを解消してください。

要点:まずDNS問い合わせの出口を確認し、その後でドメイン分類を調整

ログでDoH接続が直接接続になっている場合は、まず1.1.1.1:443のルーティングとアウトバウンドのタグを修正してください。DNSサーバーを暗号化されたアドレスに変えるだけでは、出口の設定を代替できません。また、プロキシノード自体に接続できない問題も解決しません。

例のIPルールは、同じアドレスとポート宛てのほかの接続にも一致し、DNSだけを識別するものではありません。複雑な設定では、コアが対応していればDNS問い合わせ用のタグで区別できます。通常のhttps://と、ローカル処理を伴うhttps+local://をそのまま置き換えないでください。ルーティングの動作が異なります。

4. domainStrategy:名前解決のタイミングとドメインの保持

routing.domainStrategyは、ルーティングの判定時にIPアドレスをどう扱うかを制御するもので、「すべてのDNS問い合わせをプロキシ経由にする」スイッチではありません。ルーティングモジュールの同名フィールドと、freedomアウトバウンドのdomainStrategyは区別してください。前者はルールの照合方法を決め、後者は直接接続時の宛先ドメインの処理に関わります。対応する値を混同しないようにしてください。

routing.domainStrategyルーティング時の動作利用時の考え方
AsIsドメイン宛ての接続でルーティング用の名前解決を行わない主にドメインルールを使い、余分な問い合わせを減らす
IPIfNonMatchドメインがルールに一致しない場合に名前解決し、IPルールの照合に使うドメインルールを優先し、IPルールで補完する
IPOnDemand照合中にIPが必要なルールに達した時点で名前解決する早い段階でIP分類を使いたい場合に適する

上の例ではIPIfNonMatchを使用します。国内または海外のカテゴリが明確なドメインは、まずドメインルールで振り分けます。未分類の宛先だけが名前解決され、geoip:cnによる判定に進むことがあります。そのため、「海外サイトを開いたのにローカルDNSへの問い合わせが見えない」からといって、設定が無効とは限りません。

  • ローカルでの名前解決を減らすには、まず信頼できるドメインルールを補います。最初から、より積極的に名前解決する戦略へ変更するのは避けてください。
  • ルールによる振り分けが誤っている場合は、最初に一致したルールを確認してから名前解決の結果を調べます。DNSサーバーだけを変更しないでください。
  • 宛先がすでにIPアドレスの場合、これら3つの設定で元のドメインが自動的に復元されることはありません。復元できるかは、スニッフィング情報やFakeDNSのマッピングなどの条件によります。

5. FakeDNS:仮想IPのマッピングには経路全体の連携が必要

FakeDNSが返すのは、ローカルでマッピングを管理する仮想IPであり、Webサイトの実サーバーのアドレスではありません。アプリがこのアドレスに接続すると、コアがマッピングからドメインを復元し、ルーティングや後続のプロキシ処理に使います。これは「アプリが先に名前解決し、プロキシにはIPだけが届く」という情報の欠落を補うもので、DNS問い合わせを自動的に暗号化する仕組みではありません。

  1. DNS問い合わせが横取りされているか確認します。 アプリの問い合わせがFakeDNSに届かなければ、対応するマッピングは作成されません。設定にアドレスプールを追加するだけでは機能しません。
  2. 仮想IP宛ての通信がコアに戻ることを確認します。 デスクトップのTUNまたはAndroid VPNのルーティングでアドレスプールをカバーし、物理ネットワークへ送らないようにしてください。
  3. ドメインを復元できることを確認します。 対応するインバウンドには、コアがサポートするFakeDNSのスニッフィング設定が必要です。関連する一般的なフィールドはsniffing.destOverride内のfakednsです。
  4. 直接接続で実アドレスを取得できることを確認します。 ドメインを復元した後、直接接続する宛先は適切に名前解決する必要があります。仮想IPを実サーバーのアドレスとして接続しないでください。

通常のシステムプロキシ環境でアプリがドメインを渡せる場合は、実際の名前解決を使う方法を優先してください。FakeDNSが本当に必要な場合は、使用するクライアントとコアの機能説明を確認し、横取りの仕組みは一度に1つだけ有効にします。TUN、DNSの横取り、スニッフィング、ルーティング戦略を同時に変更すると、どの層が通信を妨げたのか判断できなくなります。

6. 設定の検証:読み込み、名前解決、ルーティングの順に確認

DNSのトラブルシューティングでは、まず設定の読み込み失敗、問い合わせのタイムアウト、名前解決は成功するが接続できない状態を切り分けます。VMessまたはVLESSのノードが使えない場合、そのノード経由のDoHもタイムアウトすることがあります。反対に、DNSからアドレスが返ってきても、ノードのハンドシェイク、TLS、宛先ポートが正常とは限りません。

  1. 現在の状態を記録します。 動作中の設定を保存し、クライアントのバージョン、実際に使うコアとそのバージョン、システムプロキシまたはVPNのモード、アプリごとの除外設定を記録してください。サブスクリプションの更新前後で、使用中のノードが変わっていないことも確認します。
  2. 変更後にコアを再起動します。 クライアントのDNS設定またはカスタム設定を保存したら、起動ログを確認してください。不明なフィールド、ルールデータの読み込み失敗、アウトバウンドタグの不一致があれば、Webページでのテストに進む前に修正します。
  3. 一時的にログの詳細度を上げます。 クライアントのログ設定で一時的にデバッグレベルを選び、宛先ドメイン、DNS接続先のアドレス、アウトバウンドタグを確認します。テスト後は通常のログレベルに戻し、共有前にノードのアドレスやアクセス履歴を削除してください。
  4. カテゴリごとにテストします。 国内ルールに含まれることを確認したドメイン、海外カテゴリに含まれることを確認したドメイン、どちらにも分類されていないドメインをそれぞれ選びます。各カテゴリで3回連続してアクセスし、初回の問い合わせとキャッシュが使われた場合の違いを確認してください。
  5. 最後にキャッシュの影響を除外します。 アプリまたはコアを再起動して再テストし、必要に応じてシステムDNSキャッシュも消去してください。毎回、DNSサーバー、ノード、ルールファイルを同時に変更するのは避けます。
ipconfig /flushdns
nslookup www.baidu.com 223.5.5.5

以下はWindowsでの補助的な確認コマンドです。1行目はシステムDNSキャッシュを消去し、2行目は指定したDNSサーバーに直接問い合わせます。2行目はこの記事で説明する内蔵DNSの選択処理を経由しないため、そのサーバーに基本的に接続できるかしか確認できず、DNS振り分けの成功を証明するものではありません。問い合わせに失敗する場合は、ローカルネットワークでUDP 53番ポートへの直接接続が制限されていないかも確認してください。

DNSを変更したのに、ブラウザーに古いアドレスが表示されるのはなぜ?

テスト中のページをいったん閉じて開き直し、ブラウザーのセキュアDNSが独立して動作していないか確認してください。Windowsではipconfig /flushdnsを実行してから、クライアントのコアを再起動します。コアのキャッシュとシステムキャッシュは別々です。それでも変化がない場合は、アプリがシステムプロキシを迂回していないか確認してください。

国内サイトのDNS問い合わせもリモート経由になるのは、ルールの指定が逆だから?

まず、ドメインが現在のgeosite:cnカテゴリに含まれているか確認し、次に優先サーバーへの問い合わせ失敗後にフォールバックが発生していないか調べます。skipFallback: trueはフォールバックを禁止する設定ではありません。また、より前のルールによってDNS接続のルーティング先が変わっていないかも確認してください。

Android VPNに接続済みなのに、一部のアプリだけ名前解決に失敗するのはなぜ?

v2rayNGまたはv2flyNGのアプリごとのプロキシ設定を確認し、システムの「設定」にある「プライベートDNS」の状態も記録してください。メーカーによってメニュー名が異なる場合があります。アプリ独自の暗号化DNSが干渉していないか一時的に確認し、原因がわかったら必要な設定に戻してください。

DoHがタイムアウトする場合、証明書の検証を無効にすればよい?

まずシステム時刻、プロキシノードへの接続状況、1.1.1.1:443がプロキシ出口を通っているかを確認します。ログで接続タイムアウトと証明書エラーを区別してください。証明書検証は有効のままにし、ルーティングの問題を隠すためにTLSの検証要件を緩めないでください。

目指すのは、すべてのドメインを同じサーバーで名前解決することではありません。ドメイン分類、DNS問い合わせの出口、実際の通信の出口が整合するように設定することです。DNS汚染対策によって信頼できない問い合わせ経路の影響は抑えられますが、ルール分類が常に正確になるわけではなく、接続ログの確認、証明書検証、定期的なメンテナンスの代わりにもなりません。

クライアントのダウンロード