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

V2Rayのdns設定でservers、domains、expectIPsを使い分け、国内・海外ドメインのDNS振り分けとルーティングによるDNS汚染対策を解説します。

この記事の要点

まず、ドメインをどのDNSサーバーが名前解決しているかを確認します。次に国内ドメイン用と、それ以外のドメイン用にDNSサーバーを設定し、最後にルーティングルールでDNSリクエストの接続先を指定します。ノードに接続でき、コア設定を変更するユーザー向けです。掲載するのは設定例の一部であり、そのままインポートできる完全なノードファイルではありません。

1. DNSリクエストがコアに届いているか確認する

まず、DNS名前解決とルーティングを分けて考えます。DNS名前解決はドメイン名をIPアドレスに変換する処理で、ルーティングは接続を直接接続にするかプロキシ経由にするかを決めます。dnsセクションを変更しただけでは、すべてのアプリのDNSリクエストが自動的にV2Rayへ届くわけではありません。プロキシルールを追加しただけでも、アプリが先に取得したIPアドレスが正しいとは限りません。

アプリがドメイン名を送信 コアがルールを照合 必要に応じてIPアドレスを名前解決 接続先を選択

上記は、アプリがドメイン名をコアに渡す一般的な流れです。アプリ側ですでに名前解決し、IPアドレスだけを送る場合、コアが受け取る情報は異なります。ブラウザーのセキュアDNS、システムDNS、クライアント内蔵DNSが同時に使われることもあるため、DNSの入力欄ひとつだけでは実際の名前解決経路を判断できません。

2. servers、domains、expectIPsの役割

まずドメインを分類し、各グループに使用するDNSサーバーを指定します。serversはDNSサーバーのリストです。単純なアドレスのほか、条件を指定したオブジェクトも設定できます。国内・海外のドメインでDNSサーバーを使い分ける場合は、オブジェクト形式のほうが動作を確認しやすくなります。

項目役割設定のポイント
servers利用するDNSサーバーを指定リストの先頭にあるサーバーだけが常に使われるとは限りません。条件やフォールバック設定によって選択先が変わります。
domains優先的にこのDNSサーバーへ問い合わせるドメインを指定geosite:cnを使うには、コアが対応するドメインデータファイルを読み込める必要があります。
expectIPs応答IPアドレスが想定範囲内か確認geoip:cnはIPアドレスの所属地域による絞り込みです。コンテンツの安全性やドメインの正当性を証明するものではありません。
skipFallback一致しないドメインのフォールバック問い合わせに、このDNSサーバーを使うか指定trueにすると、domainsに一致する問い合わせには引き続き使用できます。
queryStrategy問い合わせるアドレスの種類を指定UseIPv4はIPv4だけを問い合わせる設定です。システム全体のIPv6を無効にするものではありません。
tag内蔵DNSの問い合わせにタグを付与問い合わせがコアのルーティングを通る場合、ルールのinboundTagで照合できます。

geositeはドメインの分類データ、geoipはIPアドレスの分類データで、相互に置き換えることはできません。domainsにはdomain:example.comのように、ドメインとサブドメインを照合する記法も使えます。特定のサイトを調べる場合は、分類データ一式を入れ替えるより、対象ドメインのルールを1つ追加するほうが原因を特定しやすくなります。

ポイント:expectIPsは応答の絞り込み条件であり、DNS汚染を防ぐスイッチではありません

そのドメインに中国本土のIPアドレスを返したい場合に限り、geoip:cnの制限を設定してください。サイトが海外CDNを利用している場合は、除外されたIPアドレスと実際の所属地域を確認し、ルールの対象を絞り込みます。中国本土以外のIPアドレスをすべて汚染と判断しないでください。

3. 国内ドメインを優先し、ほかのドメインは暗号化して名前解決する

以下は動作を確認しやすい基本設定例です。国内向けの分類に一致するドメインは223.5.5.5へ優先的に問い合わせ、それ以外はhttps://1.1.1.1/dns-queryを使います。後者はDoHで、HTTPS経由でDNS問い合わせを送信します。例ではIPv4を使い、デュアルスタック環境での切り分け要因を減らしています。IPv6に問題があるという意味ではありません。

{
  "dns": {
    "tag": "dns-query",
    "queryStrategy": "UseIPv4",
    "servers": [
      {
        "address": "223.5.5.5",
        "port": 53,
        "domains": [
          "geosite:cn"
        ],
        "expectIPs": [
          "geoip:cn"
        ],
        "skipFallback": true
      },
      {
        "address": "https://1.1.1.1/dns-query",
        "skipFallback": false
      }
    ]
  }
}
53
国内向けUDP DNSの例で使用するポート
443
HTTPSの標準接続ポート
2組
DNSサーバー設定例

ここでskipFallback: trueを指定するのは、国内向けDNSサーバーが一致しないドメインの通常のフォールバック問い合わせに使われないようにするためです。「国内向けDNSで名前解決に失敗したら、絶対に再試行しない」という意味ではありません。国内向けDNSからexpectIPsに合致する結果が返らない場合、フォールバックが無効化されていなければ、ほかの適用可能なサーバーも試されます。フォールバックと完全な隔離を混同しないでください。

4. ルーティングルールでDNSの接続先を指定する

まず、既存のアウトバウンドタグを確認します。以下の設定例では、directというタグの直接接続用アウトバウンドと、proxyというタグの利用可能なプロキシアウトバウンドがすでにあるものとします。これらは例で使う名前であり、DNS設定によって自動作成されるものではありません。既存のタグ名が異なる場合は、実際の名前に置き換えてください。VMessやVLESSのノード設定は変更しません。

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "inboundTag": ["dns-query"],
        "ip": ["223.5.5.5"],
        "port": "53",
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "inboundTag": ["dns-query"],
        "outboundTag": "proxy"
      },
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private", "geoip:cn"],
        "outboundTag": "direct"
      }
    ]
  }
}

ルールは記載順に照合されます。1つ目のルールは、dns-queryタグが付いた223.5.5.5:53宛てのリクエストだけを直接接続にします。2つ目は、同じタグが付いたほかの問い合わせをプロキシに送ります。DNSを広く対象にするプロキシルールを先に置くと、国内向けDNSの問い合わせも先に一致し、「国内向けDNSを設定したのに遠回りする」ことがあります。

  1. DNS専用ルールは広範囲のルールより前に置きます。既存設定に全ポート直接接続、グローバルプロキシ、インバウンド別の振り分けルールがある場合は、どのルールが先に一致するか確認してください。
  2. IPIfNonMatchの動作を理解します。ドメイン名が該当ルールに一致しない場合、コアは内蔵DNSでIPアドレスを取得してから、IPルールを照合できます。すべてのドメインを先に名前解決する設定ではありません。
  3. 既存のデフォルト接続先を維持します。この設定例には、最後に適用される全通信向けのフォールバックルールはありません。どのルールにも一致しない通信は、設定全体のデフォルトアウトバウンドに従います。統合時はアウトバウンドの順序も確認してください。
  4. プロキシサーバーの事前名前解決を確認します。プロキシサーバーのアドレスがドメイン名の場合、その唯一の名前解決経路が、まだ確立されていないプロキシ接続に依存しないようにしてください。プロキシサーバーのドメイン名には、到達可能な別の事前名前解決経路を設定できます。

5. ログと比較テストでDNS振り分けを検証する

まず「どのDNSサーバーが名前解決し、どの経路を通るか」を検証してから、Webページにアクセスできるかを確認します。nslookupだけを実行した場合、通常はシステムで指定されたDNSサーバーがテストされるため、V2Rayの内蔵DNSがルールどおりに動作している証明にはなりません。DNSリークテストに表示されるのも、多くの場合は再帰DNSサーバーの接続元であり、端末のプロキシ出口ではありません。

  1. 一時的にログレベルを上げます。既存のlogオブジェクトでloglevelをdebugに変更し、コアを再起動します。確認が終わったらwarningに戻してください。ドメイン名や接続の詳細が大量に記録される状態を長期間続けないようにします。
  2. テスト経路を再起動します。コアを再起動すると、今回の確認に影響するコアのキャッシュをクリアできます。テスト対象のアプリも終了して再起動し、必要に応じてアプリ内のDNSキャッシュを消去してください。Webページを再読み込みするだけでは、新しい問い合わせが発生しないことがあります。
  3. 国内向けルールに一致するドメインを1つテストします。ログに該当するDNS問い合わせが記録されていることを確認し、223.5.5.5:53宛てのリクエストがdirectを通るか調べます。キャッシュ済みのリクエストや、ドメインルールに直接一致した通信では、新しい名前解決ログが記録されないことがあります。
  4. 国内向けグループに含めていないドメインを1つテストします。DoHサーバーが使われ、その接続がproxyを通るか確認します。ログの表示内容はコアによって異なるため、DNSサーバーのアドレス、対象ドメイン、アウトバウンドタグを照らし合わせて判断してください。
  5. アプリ経由とローカル名前解決の経路を個別にテストします。デスクトップでは以下の2つのコマンドを比較できます。実行前に、ポートをクライアントに表示されている実際のSOCKS待ち受けポートに変更してください。
curl --socks5-hostname 127.0.0.1:10808 -I https://example.com
curl --socks5 127.0.0.1:10808 -I https://example.com

1つ目はSOCKSプロキシに接続先ドメインの処理を任せ、2つ目はcurlがローカルで名前解決してからIPアドレスを送信します。10808はコマンド例のポートで、実際の待ち受けポートと同じとは限りません。どちらも成功しても、コアが名前解決したとは限りません。プロキシアウトバウンドがドメイン名をリモートサーバーに渡す場合もあるため、最終的にはログも確認してください。

確認ポイント:リクエストがどの段階で止まったかを特定する

ログにDNS問い合わせがない場合は、まずキャッシュと、アプリがドメイン名を送信しているかを確認します。問い合わせは記録されているのにタイムアウトする場合は、DNSサーバーへの接続経路を調べます。IPアドレスが返っても接続できない場合は、ルーティング、ノード、接続先サービスを確認します。この3段階に分けて調べるほうが、DNSサーバーのアドレスを何度も変えるより効率的です。

6. DNS振り分けのよくある問題と復旧方法

DNSを変更したら、どのサイトにも接続できなくなりました。まず何を確認すればよいですか?

まずバックアップを復元し、ノードが引き続き使えることを確認してから、コアの起動ログを調べます。JSONの構文エラー、分類データの読み込み失敗、存在しないアウトバウンドタグを優先して確認してください。コアが起動したら、DoHの接続先が、まだ名前解決できていないプロキシサーバーのドメイン名に依存していないか確認します。

国内サイトに時々接続できないのは、expectIPsの設定が間違っているからですか?

まず、返されたIPアドレスがgeoip:cnによって除外されていないか確認します。対象ドメインだけ一時的にこの条件を外すか、より限定的な専用ルールを作成して、再起動後にテストしてください。サイトが海外CDNを利用している場合は、そのサイトのDNS設定を見直します。DNSサーバーが汚染されていると決めつけないでください。

DoHを使っているのに、DNS検査ページに国内の通信事業者が表示されるのはなぜですか?

ブラウザーの「設定」にあるセキュアDNS、システムDNS、アプリがプロキシを迂回していないかを確認してください。次に、コアのログに対象ドメインの問い合わせが記録されているか確認します。DoHが暗号化するのは指定したDNSサーバーへの問い合わせ経路だけです。すべてのアプリのDNSを一括して制御するものではありません。

サブスクリプションを更新したらDNS設定が変わったのはなぜですか?

まず、サブスクリプションのノード情報と、クライアントが生成するコア設定を分けて考えます。起動のたびに再生成される一時JSONは編集しないでください。クライアントの保存可能なDNS設定画面か、カスタム設定画面で保存します。更新後は実際に適用された設定を開き、dnsの内容とルールの順序を確認してください。

IPv4だけにすると、一部のアプリに影響しますか?

IPv6に依存する接続先に影響する可能性があります。まずUseIPv4で基本動作を確認し、デュアルスタックに対応した環境ではUseIPに変更して、IPv6のルーティングと接続経路も確認してください。AAAAレコードの問い合わせだけ再開し、対応する接続経路を確認し忘れないようにしてください。

最後に、起動・名前解決・接続のすべてを確認できた設定のコピーを保存してください。変更は一度に1つに絞り、まずDNSサーバー、次にドメインのグループ分け、最後にフォールバックとIPアドレスの絞り込みを調整します。ほかの設定項目を確認する場合は、サイト内の設定項目ガイドを開き、実際のコアのバージョンに合わせて1つずつ確認してください。

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