1. DNSリークの見分け方:まずプロキシ経由にするクエリを確認

Webサイトで確認できる接続元IPがプロキシのものに変わっていても、DNSクエリはローカルネットワークから送信されている可能性があります。Web接続と名前解決は別の経路だからです。システムプロキシの設定が適用されるのは通常、その設定に従うアプリだけで、システムからUDP 53番ポートに送られるクエリまで自動的に処理するわけではありません。ブラウザが独自の暗号化DNSを使う場合もあります。

この記事では、本来プロキシ経由で処理するはずのドメイン名クエリが、誤ってローカルの直接接続経由でDNSサーバーに送られる状態を「リーク」と呼びます。中国国内のドメインをローカルDNSで名前解決する設定なら、その直接接続は想定どおりです。テストページに複数のDNSサーバーが表示されただけで、設定が機能していないと判断しないでください。

確認できた現象わかること次に確認すること
Webの接続元IPがプロキシノードのものそのWeb接続がプロキシ経由であるDNSの経路を続けて確認
ローカル回線事業者のDNSが表示されるローカルDNSで再帰問い合わせされた可能性ルール設定とパケットキャプチャを確認
パブリックDNSサービスが表示されるそのサービスが再帰問い合わせに関与した名称だけではプロキシ経由か判断できない
クエリの応答が 198.18.x.xfake-ipにマッピングされた可能性上流への問い合わせと接続ルートも確認

2. DNSリークの確認手順:基準値・比較・パケットキャプチャ

まずテスト条件をそろえる

  1. クライアント名、クライアントのバージョン、コアのバージョンを記録します。以下の設定例はmihomo向けです。オリジナル版Clashや古いコアでは、すべての項目を使えるとは限りません。
  2. 現在のプロキシモード、ノード、TUNの有効・無効、ブラウザのセキュアDNS設定を記録します。テスト中はノードとDNSサービスを同時に変更しないでください。
  3. 同じネットワークでプロキシをオフにし、DNSテストを実行して、DNSサーバー名・IPアドレス・Webの接続元IPを記録します。この結果を直接接続時の基準値にします。
  4. プロキシを有効にして、テストページで新たにテストを実行します。キャッシュの影響を抑えるため、ランダムなサブドメインを生成するテスト機能を優先してください。
  5. 次にTUNを有効にし、同じテストを繰り返します。TUNを有効にしたときだけ結果が変わる場合は、システムDNSがコアを迂回していた可能性を優先して調べます。

キャッシュを消去して、ローカルの待ち受けを確認

Windowsでは、ターミナルで以下のコマンドを実行できます。1つ目はシステムのキャッシュを消去し、2つ目はこの記事の設定例で使うローカルDNSの待ち受けポートに直接問い合わせます。ブラウザには独自のキャッシュや接続プールがあるため、テスト前に完全に終了してから再起動してください。ページを再読み込みするだけでは、新しい名前解決が行われないことがあります。

ipconfig /flushdns
nslookup example.com 127.0.0.1

後述の例では 127.0.0.1:1053 で待ち受けます。一方、上記の nslookup は既定で53番ポートに問い合わせるため、PC上で53番ポートから転送している場合に限り使用できます。1053番ポートを確認するには、インストール済みの dig など、ポートを指定できるツールを使ってください。

dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com AAAA

偽IPが返ってきた場合、このクエリがコアのDNS処理を通ったことはわかります。ただし、すべてのアプリがこの経路を使っている証明にはなりません。クライアントの接続ログで、対象ドメインに適用されたルールと送信先ポリシーも確認してください。

パケットキャプチャでローカル経路を確認

実際に通信している物理ネットワークインターフェースでパケットをキャプチャし、udp.port == 53 || tcp.port == 53 で絞り込んでから、テストを再実行します。テスト用のランダムなドメインがルーターや回線事業者のDNSへ直接送信され、想定した直接接続ルールにも該当しないことを確認できれば、迂回の明確な証拠になります。キャプチャにはドメイン名などのプライバシー情報が含まれるため、共有前に必ずマスキングしてください。

DoHはTCP 443番やQUIC 443番、DoTは通常TCP 853番を使います。53番ポートに通信がないからといって、DNSが迂回していないとは限りません。暗号化されたクエリは、接続先DNSサービスのIPアドレス、プロセス、クライアントの接続ログもあわせて確認します。

3. fake-ip・DNSルール・TUNハイジャックの役割

仕組み実際の役割制約
fake-ipドメインに偽IPを割り当て、コアがドメイン名を復元してルールを適用できるようにするアプリ内蔵のDoHまでは自動的に処理しない
nameserver-policyドメインごとにDNSサービスを選択するDNSサーバーの選択と、プロキシの送信経路の指定は別
respect-rulesDNSの上流接続にルーティングルールを適用するルールが直接接続に一致すれば、上流にも直接接続する
TUNの dns-hijackTUNを通る対象のDNSトラフィックをコアに処理させる任意のHTTPS通信内にあるDNSを復号して書き換えることはできない

198.18.0.0/16 はfake-ipでよく使われる範囲で、ベンチマーク用に予約されたアドレス空間です。プロキシノードの実際のグローバルIPアドレスではありません。アプリがこれらの偽IPにアクセスすると、コアがマッピングからドメイン名を復元し、ルールに基づいて接続を処理します。

つまり、fake-ipはドメイン名をマッピングする仕組みであり、「すべてのDNSをプロキシ経由にする」ためのスイッチではありません。確実に設定するには、アプリがクエリをどこへ送るか、コアがどのDNSサーバーを選ぶか、そのDNSサーバーへの接続がどの経路を通るか、3つの入口を確認する必要があります。

4. mihomoのDNS設定:まず検証できる基本設定を作る

まず現在の設定をバックアップしてください。以下の設定例は、各項目に対応するmihomo設定へ追加できます。既存のノード、プロキシグループ、ルールは残してください。完全なサブスクリプション設定として読み込まないでください。同じ名前の dns: セクションは1つだけにし、YAMLのインデントにはスペースを使います。

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - "*.lan"
    - "*.local"
  respect-rules: true
  default-nameserver:
    - 223.5.5.5
  proxy-server-nameserver:
    - https://223.5.5.5/dns-query
  nameserver:
    - https://1.1.1.1/dns-query

設定が読み込めるだけでなく、項目ごとに動作を確認

  • listen はローカルループバックアドレスだけにバインドし、DNSサービスをLANに公開しないようにします。通常、OSのネットワーク設定ではDNSポートに1053番を指定できません。接続にはTUNによるハイジャックかローカル転送が必要です。
  • ipv6: false はコアのDNSがAAAAクエリをどう処理するかを制御します。OSのIPv6を無効にする設定ではなく、アプリが別の方法でIPv6アドレスを取得するのを防ぐものでもありません。
  • default-nameserver は、DNSサービス自体のドメイン名を解決するために使います。例では平文の初期問い合わせ先を残しているため、すべてのクエリが暗号化されるとは言えません。IPアドレス形式のDoH URLを使うと、この初期問い合わせを減らせます。
  • proxy-server-nameserver はプロキシサーバーのドメイン名を解決し、「プロキシに接続するために、先にプロキシのアドレスを解決する」という循環依存を避けるために使います。例では別のDoHサービスを指定していますが、現在のネットワークから接続できるかは実際に確認してください。
  • respect-rules: true を使うには、利用可能なプロキシサーバー用のDNS設定も必要です。さらに、1.1.1.1:443 への接続が想定したプロキシルールに一致するか確認してください。既存ルールが直接接続を指定していれば、クエリはプロキシを経由しません。

適用後はまず設定の検証結果を確認し、次に実行ログを確認します。未知の項目が表示されたら、現在読み込まれているコアを確認してください。古いコアに新しい項目を追加し続けないでください。クライアントの画面上の設定がサブスクリプションのDNS設定を上書きしたり、更新によって手動変更が消えたりすることがあります。クライアントの永続的な上書き機能を使い、最終的に適用される設定を確認してください。

5. nameserver-policy:LAN内ドメインに専用のDNSを指定する

社内ネットワーク、家庭のNAS、ルーターの管理用ドメインは、ローカルDNSでしか解決できないことがあります。すべてをパブリックDNSに任せても、安全性が高まるどころか名前解決できなくなるのが一般的です。以下はドメインごとにDNSを指定する例です。ルーターの実際のアドレスが 192.168.1.1 で、対象ドメインを解決できる場合に限り使用してください。

  nameserver-policy:
    "+.lan":
      - 192.168.1.1
    "+.home.arpa":
      - 192.168.1.1

この設定を既存の dns: セクション内に追加し、nameserver と同じ階層に置きます。ここでの2文字分のインデントには意味があります。+.lan はそのドメインとサブドメインに一致し、home.arpa は家庭内ネットワーク専用のドメインです。LAN内サービスを1つ復旧させるためだけに、パブリックドメイン全体をローカルDNSに任せないでください。

アプリがLAN内の実IPアドレスを必要とする場合は、対象ドメインを既存の fake-ip-filter に追加します。たとえば "*.home.arpa" です。フィルター項目が変えるのは偽IPを返すかどうかだけで、DNSサーバーの選択や直接接続ルートの指定は行いません。LANのIPアドレス範囲には、別途正しい直接接続ルールが必要です。

テストでは、まずLAN内サービス、次にパブリックドメインを問い合わせます。LAN内のクエリがルーターへ直接接続するのは、この設定で想定される動作です。パブリックドメインの意図しない迂回と混同しないでください。

6. TUN DNSハイジャック:システムのクエリやシステムプロキシに従わないアプリをカバー

システムプロキシを有効にしただけでは、アプリによっては独自にDNSクエリを送信します。デスクトップ版mihomoクライアントでは、TUNを使うと処理対象を広げられます。通常はサービスモードか管理者権限が必要です。以下は前述のDNS設定と併用できる基本例です。

tun:
  enable: true
  stack: system
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53

any:53 はTUNを通るUDP DNSを対象とし、もう一方の設定はTCP DNSを処理します。重要なのは、トラフィックが実際にTUNを通ることです。別のVPN、仮想マシンのブリッジ接続、コンテナネットワーク、IPv6ルート、アプリの除外設定などにより、別の経路が生じる場合があります。プラットフォームによっては、LAN内DNSを処理できない制約もあるため、実際のパケットキャプチャで確認してください。

ブラウザのセキュアDNSは個別にテスト

Chromeでは「設定」→「プライバシーとセキュリティ」→「セキュリティ」→「セキュア DNS を使用する」で現在の設定を確認できます。表示名はバージョンによって多少異なります。切り分けの際はまずこの設定をオフにして、ブラウザにシステムのDNSを使わせた状態でTUNを検証します。その後、設定を再びオンにして、ブラウザからDNSサービスへの接続が想定したプロキシルールに一致するか確認してください。

暗号化DNSを常に無効にするという意味ではありません。原因を切り分けるための手順です。アプリ内蔵のDoHは通常の暗号化ネットワーク接続なので、53番ポートをハイジャックする設定だけでは自動的に置き換わりません。Androidの「プライベートDNS」も別途確認が必要です。通常は「設定」→「ネットワークとインターネット」→「プライベートDNS」にありますが、メーカー独自のOSでは場所が異なる場合があります。

7. よくあるトラブルと最終チェックリスト

fake-ipを有効にしたらプリンターやNASに接続できない

まずLAN内ドメインをどのDNSが解決しているか確認し、必要に応じて適切な nameserver-policy とfake-ipフィルターを追加します。mDNSはUDP 5353番を使うため、通常のユニキャストDNSとは別の仕組みです。53番ポートのハイジャックを追加するだけでは、あらゆる .local のデバイス検出が解決するわけではありません。

respect-rulesを有効にしたらノードのドメイン名を解決できない

まず proxy-server-nameserver への接続と、そのDNSサービスへの接続自体が未解決のプロキシに依存していないかを確認します。必要ならバックアップした設定に戻し、ノードのドメイン名を独立して解決できる経路を復旧してから、DNSの送信ルールを段階的に厳しくしてください。障害の原因をすぐにノードの故障と決めつけないでください。

テスト結果が変わらない

「実際に適用された設定 → DNSキャッシュ → ブラウザのDoH → TUNルート → ルールの一致」の順で確認します。ログに今回のテストドメインがまったく記録されていない場合は、まずクエリの入口を調べます。クエリは記録されているのに送信先が直接接続ならルールを確認します。送信経路が想定どおりで地理情報だけが異なる場合は、DNSサービスのエニーキャストや転送状況を確認してください。

  • パブリックなテストドメイン:新しいクエリがコアに届き、DNSサービスへの接続が想定した送信経路に一致する。
  • ローカルの物理ネットワークインターフェース:ポリシーに反する平文のテストドメインクエリが見つからない。
  • ブラウザとシステム:セキュアDNSのオン・オフを個別にテストし、1つのWebページの結果だけで判断しない。
  • LAN内サービス:ルーター、NAS、プリンターが使え、直接接続が想定されるドメインには明確な例外がある。
  • 設定の維持:クライアントの再起動後、サブスクリプションの更新後にも再テストし、上書き設定が有効なままか確認する。

合格基準は「テストページの表示が1行だけ」ではありません。クエリの種類ごとに、入口・DNSサーバー・送信経路を説明できることです。まず経路を見える状態にし、不要な例外を減らしてください。設定を検証しやすくしておけば、次にネットワーク環境が変わったときも原因を特定しやすくなります。