DNSリークの検出と設定

ClashのDNSリークを確認する方法と、dnsセクションのnameserver・fallback・nameserver-policyの設定例を解説します。すぐに使えるDNS漏えい対策も紹介します。

まずDNSリークの判定基準を決める

ClashのDNSリークとは、本来指定したDNSリゾルバーに送る、またはプロキシ経由で処理するはずのドメイン検索が、想定した経路を外れてローカルネットワークや通信事業者、別のDNSサービスに送信される状態を指します。判定する前に、期待する動作を明確にしましょう。たとえば、日本国内のドメインは直接名前解決し、それ以外はプロキシ経由で指定したDoHサービスに問い合わせる、といった形です。この基準がなければ、検査ページに表示された国名やサービス名だけでリークの有無は判断できません。

通信には少なくとも3つの独立した経路があります。アプリが問い合わせを渡す先、Clashが問い合わせを送る上流DNS、そして上流DNSへの接続が直接かプロキシ経由かです。nameserver-policyが制御するのは、ドメインごとに上流DNSを選ぶことだけです。これ自体に通信を横取りする機能はなく、DNS接続をプロキシ経由にする設定でもありません。

確認できたこと判断できる内容追加で確認すること
検査ページにパブリックDNSサービスが表示されるテストクエリがそのサービスの再帰DNSサーバーに届いたそのサーバーへの接続がプロキシ経由かどうか
物理ネットワークアダプターからルーター宛てのUDP 53クエリが確認されるローカルから平文DNSクエリが送信されている直接接続を許可したドメインか、起動時の名前解決か
返されたアドレスが 198.18.0.0/16 に含まれるFake-IPによるマッピングの可能性がある実際のクエリで使われた上流DNSと通信経路
ブラウザーは使えるが、ほかのアプリでは名前解決に失敗するアプリによって名前解決の入口が異なる可能性があるシステムDNS、ブラウザーのセキュアDNS、TUNの適用範囲

再現可能なDNSテストを行う

1. 基準値を記録してからプロキシを有効にする

  1. ほかのVPN、プロキシ、通信高速化ツールを終了し、現在のネットワークアダプターに設定されているDNSアドレスを記録します。Windowsでは ipconfig /all、macOSでは scutil --dns、systemd-resolvedを使うLinuxでは resolvectl status を実行します。
  2. ブラウザーでセキュアDNSが有効かどうかも記録します。まずシステムDNSを使ってテストし、その後ブラウザーのDoHを個別にテストして、2つの経路を混同しないようにします。
  3. Clashを有効にする前にDNS検査を実行し、DNSサービス事業者、リゾルバーのアドレス、テスト時刻を記録します。Clashを有効にしたら、同じネットワークとブラウザーで再度テストします。
  4. 同時にクライアントのログや接続一覧を開き、テスト中のドメイン、宛先アドレス、適用ルール、出力先を確認します。検査ページは手がかりにすぎません。実際の経路を把握するには、端末上の記録を確認してください。

パブリックDNSはエニーキャストアドレスを使う場合があり、再帰DNSサーバーの所在地もプロキシの出口とは異なることがあります。検査ページに複数のDNSアドレスが表示されても、複数の上流DNSを使っている場合と、同じサービスのサーバープールが表示されている場合があります。アドレスの数や所在地だけでリークの回数を判断しないでください。

2. ClashのDNSリスナーを個別に確認する

後述の設定では、DNSを 127.0.0.1:1053 で待ち受けます。このアドレスはローカル端末からのみアクセスできます。1053はDNSポートであり、HTTPプロキシのポートではありません。アプリが引き続きルーターの53番ポートに問い合わせる場合、このリスナーを有効にしただけでは経路は切り替わりません。

# macOS / Linux(digのインストールが必要)
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com AAAA

# Windows
nslookup -port=1053 example.com 127.0.0.1

コマンドから応答が返れば、端末からClashのDNS入口へ接続できています。ただし、システムDNSがClashに切り替わったことを示すものではありません。タイムアウトする場合は、設定が読み込まれているか、コアが起動しているか、1053番ポートが競合していないかを確認してください。すぐにプロキシノードを変更する必要はありません。

3. 物理ネットワークアダプター上の平文クエリを確認する

権限のある端末では、パケットキャプチャツールで udp.port == 53 || tcp.port == 53 をフィルターに設定します。Linuxでは次のコマンドも使えます。anyには仮想インターフェースも含まれるため、物理ネットワークアダプターとTUNインターフェースを区別して確認してください。

sudo tcpdump -ni any '(udp port 53 or tcp port 53)'

ローカルネットワーク内のDNS宛てクエリが見つかった場合は、該当ドメインが直接接続を許可した範囲に含まれるか確認します。53番ポートの通信が見えなくても、すべてのDNSがプロキシ経由とは限りません。DoHは通常HTTPSの443番ポート、DoTは通常TCPの853番ポートを使うため、このフィルターでは検出されません。

nameserverと名前解決の振り分けを理解する

dns.enableはコアのDNSサービスを有効にし、listenは待ち受けアドレスを指定します。nameserverには通常のクエリを処理する上流DNSを設定します。上流には通常のDNSアドレスのほか、コアが対応する暗号化DNSのURLも指定できます。通常のDNSをDoHに変更すると、端末からDoHサービスまでの通信は保護されますが、そのサービスに対する問い合わせ内容まで隠せるわけではありません。

  • default-nameserver:主にDNS上流自体のホスト名を名前解決するために使われます。リゾルバーのアドレスを先に調べる必要がある場合の設定で、一般ドメインすべてのデフォルトグループではありません。
  • proxy-server-nameserver:mihomoでプロキシノードのホスト名を解決するための専用入口です。ノードに接続する前から、そのノード自身を使った名前解決が必要になる状況を避けられます。
  • nameserver:個別のポリシーが適用されていない通常のクエリを処理します。
  • nameserver-policy:指定したドメインまたは対応するドメイン集合に、特定のリゾルバーを割り当てます。

以下の例では、IPアドレス形式のDoH URLを名前解決の起点として使います。利用するネットワークからこれらのアドレスに接続でき、コアのTLS証明書検証が成功する必要があります。ネットワークで該当サービスがブロックされている場合は、利用地域から到達できる信頼性の高いリゾルバーを選び、直接接続する範囲を見直してください。証明書検証を無効にして問題を回避しないでください。

そのまま使えるmihomo DNS設定

既存設定に統合するための設定例です。ノードやサブスクリプション設定は含みません。通常のドメインにはCloudflare DoHを使い、.cnで終わるドメインにはAliDNS DoHを使います。また、ルールでDNSサービスへの接続経路を分けます。.cnはドメインの末尾を示すもので、中国国内のすべてのWebサイトを意味するわけではありません。

適用前に、既存設定に名前が完全一致する PROXY ポリシーグループがあり、利用可能なノードが選択されていることを確認してください。ポリシーグループ名が異なる場合は、ルール内の PROXY を置き換えます。以下のルールを既存の rules リストの先頭付近に追加し、既存の通信ルールと末尾のフォールバックは残してください。同じ名前のYAMLキーを重複して作成しないでください。

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  respect-rules: true
  default-nameserver:
    - https://1.1.1.1/dns-query
  proxy-server-nameserver:
    - https://1.1.1.1/dns-query
  nameserver:
    - https://cloudflare-dns.com/dns-query
  nameserver-policy:
    "+.cn":
      - https://dns.alidns.com/dns-query

# 既存のrulesの先頭に追加し、後続の通信ルールは残してください。
rules:
  - DOMAIN,cloudflare-dns.com,PROXY
  - DOMAIN,dns.alidns.com,DIRECT
  - IP-CIDR,1.1.1.1/32,DIRECT,no-resolve

respect-rules: trueを設定すると、通常のDNS上流への接続にルーティングルールが適用されます。この例では、ドメインを指定するルールでCloudflare DoHを PROXY 経由にし、AliDNS DoHは直接接続にします。IPルールでは、名前解決の起点となるアドレスへの直接接続を維持します。プロキシノードのホスト名を解決する専用経路も起動時に必要なため、この設定ですべてのDNSクエリがプロキシ経由になるわけではありません。

ipv6: falseが制限するのは、コアDNSが返すAAAAレコードです。OSのIPv6機能を無効にする設定でも、IPv6通信のリークを防ぐ設定でもありません。IPv6が必要な環境では、IPv6ルーティング、TUNによる通信の取り込み、上流DNSの対応状況を個別に検証してから有効にしてください。

nameserver-policyのマッチングと適用範囲

mihomoのドメインマッチング構文では、"+.example.com"でそのドメインとサブドメインを対象にできます。特殊文字を含むポリシーキーは引用符で囲み、インデントには半角スペース2つを使うことをおすすめします。ポリシー値にはリゾルバーのリストを指定できますが、複数を指定した場合、リストの順序が厳密な優先順位を示すとは限りません。

dns:
  nameserver-policy:
    "+.example.com":
      - https://cloudflare-dns.com/dns-query
    "+.cn":
      - https://dns.alidns.com/dns-query

この例はポリシーの書き方を示すものです。重複するキーを新たに作らず、前述の dns セクション内に統合してください。example.comはマッチング確認用のドメインです。実際に使う際は、用途に合ったドメインに置き換えてください。範囲の広いポリシーを重ねて優先順位を推測するのではなく、対象範囲を明確にし、ルートドメインとサブドメインを個別にテストしてください。

社内ドメインは個別に設定する

社内ドメインは通常、社内ネットワークのDNSでのみ名前解決できます。実際に使っている社内ドメインのサフィックスを社内DNSに割り当て、そのDNSアドレスへの直接接続ルートを設定してください。Fake-IPを使う場合は、アプリの要件に応じて fake-ip-filter に追加するかどうかも検討します。社内ドメインをパブリックDNSに送信しないでください。また、パブリックDNSが返すエラーをノードの障害と誤認しないようにしましょう。

ドメインを fake-ip-filter に追加すると、実際のアドレスを返すかマッピングアドレスを返すかが変わります。上流DNSが指定されるわけでも、直接接続が強制されるわけでもありません。リゾルバーの選択、Fake-IPの例外、接続ルーティングは別々の設定レイヤーなので、それぞれ個別に確認してください。

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

fallbackは予備の上流DNSを指定し、fallback-filterは応答の選択に関わります。「プライマリDNSが完全に失敗してから初めて予備DNSに接続する」と単純に解釈することはできません。関連するクエリが並行して送信される場合もあり、具体的な動作はコアとフィルター条件によって変わります。2つの上流DNSが異なる信頼境界にある場合、問い合わせ内容が両方に送られる可能性があります。

以下は、異常なアドレス応答を対象にした個別設定の例です。既存の dns セクションに追加し、設定全体を置き換えないでください。Quad9を使う場合は、該当する接続の出力先も確認します。HTTPS URLを指定するだけでは、プロキシ経由にはなりません。

  fallback:
    - https://dns.quad9.net/dns-query
  fallback-filter:
    geoip: false
    ipcidr:
      - 0.0.0.0/32
      - 127.0.0.0/8

この例ではGeoIPによる絞り込みを無効にし、指定した異常アドレス範囲だけをフィルタリングします。汚染を判定するための完全なルールではありません。セキュリティフィルターが意図的に空のアドレスを返す場合や、テスト用ドメインが正当にループバックアドレスを返す場合もあります。条件は必要な場合にのみ追加してください。フィルターを増やしても、必ず信頼性が高まるわけではありません。

システムプロキシ、TUN、ブラウザーDoHで見落としやすい点

システムプロキシですべてのDNSが切り替わるわけではない

HTTPプロキシでは、リクエストに含まれる接続先ドメインの名前解決をプロキシ側に任せられますが、システムプロキシを使わないアプリはシステムのリゾルバーを呼び出すことがあります。SOCKSアプリがドメイン名をプロキシに渡すかどうかも、リモートDNSの設定によって異なります。システムプロキシを有効にしてWebサイトを閲覧できても、コマンドラインツール、ゲーム、バックグラウンドサービスが同じDNS経路を使うとは限りません。

TUNのDNSリダイレクトにはプロトコル上の制限がある

システムプロキシに従わないアプリも制御するには、対応プラットフォームでTUNを有効にします。以下はmihomoでよく使われる設定例です。自動ルートにはOSの権限が必要な場合があります。また、LAN宛てのDNSを取り込めるかどうかは、プラットフォームのルーティングとクライアントの実装にも左右されます。

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

これらのリダイレクト設定が対象とするのは、従来型DNSのUDP/TCP 53番ポートです。ブラウザーのDoHを復号する機能はなく、443番ポートの接続をすべてコアのDNSクエリに変換するものでもありません。ブラウザー内蔵のDoHは独立した接続のままです。TUNによってプロキシ経由でルーティングされることはありますが、問い合わせ内容が nameserver-policy で処理されるわけではありません。

ブラウザーとシステムのキャッシュは分けてテストする

デスクトップ版Chromeの場合、「設定」→「プライバシーとセキュリティ」→「セキュリティ」で「セキュアDNSを使用する」を確認できます。画面上の表記はバージョンによって異なる場合があります。ClashコアのDNSを検証する際は、カスタムセキュアDNSを一時的に無効にしてください。ブラウザーのDoHを使い続ける場合は、DoHサービスへの接続に適用される出力先を別途確認します。

Windowsでは ipconfig /flushdns を実行してシステムのキャッシュを消去できます。systemd-resolvedを使うLinuxでは resolvectl flush-caches を実行します。ブラウザーやコアにキャッシュが残っている場合もあるため、該当するプロセスを再起動してから再テストしてください。キャッシュから返された応答が速かったというだけで、上流DNSが切り替わったと判断しないでください。

症状に応じて最終確認する

症状優先して確認する項目確認方法
1053番ポートへの問い合わせがタイムアウトするDNSリスナー、設定エラー、ポートの競合起動ログを確認し、ローカルの待ち受け先に直接問い合わせる
ブラウザーだけで異なるリゾルバーが表示されるブラウザーのDoHまたはプロキシ設定システムDNSに切り替え、同じテストをもう一度行う
TUNを有効にしてもルーター宛てのDNSクエリが残る宛先ルート、プラットフォーム側の制限、ほかの仮想ネットワークアダプター物理ネットワークアダプターでパケットを取得し、問い合わせ元のプロセスを確認する
ノードを切り替えた後に名前解決できないノードのホスト名解決と上流DNSへのルーティングループノード用の専用リゾルバーに個別に接続できるか確認する
サブスクリプション更新後に設定が消える更新時に置き換えられるリモート設定を編集している永続化されるオーバーライドを使い、最終設定を確認する

最後に、同じ順序で再テストします。ローカルの1053番ポートで待ち受けできること、システムまたはTUNから対象の問い合わせがコアに届くこと、ポリシーで想定した上流DNSが選ばれること、そしてその上流DNSへの接続に正しい出力先が適用されることを確認してください。テスト時刻、問い合わせたドメイン、リゾルバー、適用ポリシーを記録します。4つの段階すべてが想定どおりであれば、その問い合わせ経路は適切です。検査ページのスクリーンショット1枚だけでは、すべてのアプリ、ネットワーク、IPv6環境を判断できません。

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