Clash DNSが実際に処理する内容

Webサイトにアクセスすると、通常はまずドメイン名がシステムDNSに渡され、返されたIPアドレスを使って接続が確立されます。システム側で先に名前解決が完了すると、Clashからは宛先IPしか見えず、ドメインルールやGeoSiteルール、スニッフィングで復元する必要があるドメイン情報が機能しなくなる場合があります。Clash内蔵DNSを有効にすると、同じプロキシコアで名前解決を処理できるため、ドメイン、ルールマッチング、出力先選択の関係が明確になります。

DNS設定は、単にパブリックDNSを1つ入力すればよいものではありません。1回の問い合わせには、起動用リゾルバー、通常のリゾルバー、プロキシノード用リゾルバー、フォールバックリゾルバー、ドメインポリシー、TUNハイジャックなどが関わることがあります。各項目は異なる段階を担当するため、重複して設定しても信頼性が自動的に上がるわけではなく、むしろ名前解決のループや結果の不一致を招くことがあります。

1回の問い合わせにおける主な経路

  1. ブラウザやアプリが、たとえば www.example.com の名前解決を要求します。
  2. システムDNS、TUNハイジャック、または手動指定したローカルポートが問い合わせをClashへ渡します。
  3. コアはまずキャッシュ、hosts、fake-ip-filter、nameserver-policyを確認します。
  4. 特定のポリシーに一致しない場合、問い合わせはnameserverへ渡されます。fallbackを有効にしている場合は、fallback-filterと組み合わせて結果が判定されます。
  5. コアは実際のIPアドレスを返すか、Fake-IPモードでは 198.18.0.0/16 の範囲にあるマッピングアドレスを返します。
  6. アプリが接続を開始すると、Clashはドメインルール、IPルール、プロキシグループに基づいて出力先を決定します。

nameserverdefault-nameserverproxy-server-nameserver

nameserver:通常のドメイン解決の入口

dns.nameserverはデフォルトのリゾルバー一覧です。nameserver-policyに一致せず、fallbackに任せる必要もない場合、通常のドメインはここに指定したサーバーへ問い合わせます。従来のUDP DNSのほか、DoHやDoTなどの暗号化プロトコルも利用できます。UDP DNSは通常IPアドレスで指定し、デフォルトポートは53です。DoHは完全なHTTPSアドレス、DoTは通常 tls://ホスト名:853 の形式で記述します。

dns:
  enable: true
  listen: 127.0.0.1:1053
  nameserver:
    - 223.5.5.5
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query

同じリストに複数のサーバーを登録できますが、「複数」だからといって厳密な順番でフェイルオーバーするとは限りません。コアのバージョンによっては並列で問い合わせ、先に返った結果や条件に合う結果を採用します。日本国内のドメインとそれ以外のドメインで固定のリゾルバーを使い分けたい場合は、リストの順番に頼らずnameserver-policyを使用してください。

default-nameserver:DNSサーバー自身のドメインを解決

nameserverに https://dns.alidns.com/dns-query と記述した場合、コアはHTTPS接続を確立する前に dns.alidns.com のIPアドレスを知る必要があります。default-nameserverはこの起動時の名前解決を担当し、bootstrap DNSとも呼ばれます。ここには直接アクセスできるIP形式のリゾルバーを優先して指定し、「リゾルバーのドメインを先に解決する」という循環依存を避けます。

dns:
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query

default-nameserverは、すべてのWebサイトに対する強制的な解決先ではありません。通常の起動後、サービス用ドメインはnameserver、fallback、nameserver-policyによって処理されます。ここで発生する問い合わせは通常少数ですが、ネットワーク切り替え、キャッシュの期限切れ、リゾルバー接続の再確立時には再び使用されます。

proxy-server-nameserver:ノードのドメイン専用リゾルバー

プロキシノードのアドレスは固定IPではなく、node.example.net のようなドメイン名の場合があります。ノードの名前解決まで、まだ接続できていないプロキシに依存すると循環が発生します。プロキシへの接続前にノードを解決する必要がある一方、その名前解決には先にプロキシへ接続しなければならないためです。mihomoの proxy-server-nameserver を使うと、ノードのサーバードメインを直接アクセス可能なDNSへ渡せます。

dns:
  proxy-server-nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query

ノードのドメイン解決に失敗すると、ログには lookupno such hosti/o timeout などがよく表示されます。この場合、通常のWebドメインを解決できても、プロキシノードがすべてタイムアウトすることがあります。切り分けではnameserverとproxy-server-nameserverを分けて確認し、ブラウザでWebページを開けるかどうかだけで判断しないでください。

fallbackfallback-filterの設定方法

fallbackは予備のリゾルバーグループで、異なるネットワーク経路から得たDNS結果を選別するためによく使われます。「nameserverがタイムアウトした後だけ問い合わせる」単純な予備リストではありません。従来のClash構成ではnameserverとfallbackへ並列で問い合わせ、fallback-filterで予備結果を採用するか判断することがよくあります。mihomoも互換性のためこの書式を残していますが、ドメイン単位で正確に振り分けるならnameserver-policyのほうが適しています。

fallback-filterの4つの条件

  • geoip:IP地理情報データベースに基づく結果判定を有効にします。
  • geoip-code:基準地域コードを指定します。たとえば CN です。この判定は、ローカルのGeoIPデータが最新かどうかに左右されます。
  • ipcidr:メインの解決結果が指定したネットワーク範囲に入った場合、フィルター条件に従ってfallbackの結果を選択します。明らかに異常なアドレス範囲を除外する用途などに使われます。
  • domain:指定したドメインでfallback側の結果を直接使用します。ドメインサフィックス形式にも対応します。
dns:
  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query
  fallback:
    - https://1.1.1.1/dns-query
    - https://dns.google/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 240.0.0.0/4
    domain:
      - +.google.com
      - +.githubusercontent.com

このような設定は、ローカルの名前解決と別経路の解決結果を使い分ける必要があるネットワーク環境に向いていますが、すべての地域に適しているわけではありません。中国本土以外で利用する端末の geoip-codeCN に固定すると、判定が実際の接続地域と合わなくなる可能性があります。地域をまたいで長期間利用する端末では、ドメインごとにリゾルバーを明示したほうが保守しやすくなります。

nameserver-policyでドメインごとのリゾルバーを指定する

mihomoの nameserver-policy を使うと、ドメインのマッチ結果に応じてDNSを指定できます。「メインリゾルバーと地域判定」を組み合わせる方法より直接的で、ルールに一致したドメインは指定サーバーへ、未一致のドメインはnameserverへ戻ります。完全修飾ドメイン名やドメインサフィックスのほか、GeoSiteデータに対応するコアでは geosite: によるマッチングも利用できます。

dns:
  enable: true
  nameserver:
    - https://1.1.1.1/dns-query
    - https://dns.google/dns-query
  nameserver-policy:
    "geosite:cn":
      - https://dns.alidns.com/dns-query
      - https://doh.pub/dns-query
    "+.example.cn":
      - https://dns.alidns.com/dns-query
    "intranet.example.net":
      - 192.168.1.1

最後の例はイントラネットのケースです。企業や家庭内のドメインをLAN内DNSだけで解決できる場合は、そのドメインに対して 192.168.1.1 を個別指定します。LAN内DNSをすべてのドメインで共用するnameserverに入れる必要はありません。これにより内部サービスの名前解決を維持しながら、すべてのパブリックドメインをルーター経由にすることも避けられます。

設定で geosite:cn を参照する場合は、GeoSiteデータが存在し、コアと互換性のある形式であることを確認してください。起動ログにルールセットの読み込み失敗、データベース不足、matcherエラーが出る場合は、まずコアのデータファイルを更新します。外部データへの依存を減らすなら、+.example.com のようなドメインサフィックスルールだけを使う方法もあります。

ドメインポリシーとプロキシルールは別物

nameserver-policyは「どのDNSへ問い合わせるか」を決め、プロキシルールは「どの出力先を経由して接続するか」を決めます。あるドメインをローカルのDoHで解決しても、接続が必ずDIRECTになるわけではありません。リモートDNSで結果を取得しても、接続が必ずプロキシ経由になるわけではありません。DNSの選択をプロキシグループの選択と混同せず、2つのルールを分けて確認してください。

Fake-IPredir-hostと除外リスト

enhanced-modeでよく使われる値は fake-ipredir-host です。Fake-IPモードではアプリへ実際のアドレスをすぐ返さず、まずマッピングアドレスを返します。アプリがそのアドレスへ接続すると、Clashは接続を元のドメインへ正確に戻してから、ドメインルールを適用できます。デフォルトのマッピング範囲には通常 198.18.0.1/16 が使われます。この範囲はベンチマーク用に予約されており、一般的なパブリックアドレスではありません。

dns:
  enable: true
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - "*.lan"
    - "+.local"
    - "localhost"
    - "time.*.com"
    - "ntp.*.com"

LAN機器の検出、プリンター、画面ミラーリング、NTP時刻同期、実IPに依存する一部のアプリはFake-IPに向かない場合があります。対象ドメインを fake-ip-filter に追加すると、実際の名前解決結果が返されます。除外範囲を主要なトップレベルドメイン全体へ広げると、Fake-IPによるドメイン識別や振り分けの利点が大きく損なわれるため避けてください。

redir-hostは実際のIPアドレスをそのままアプリへ返すため、互換性の仕組みは分かりやすい一方、接続がコアに入った時点でIP情報しか残らない場合があります。このときドメインルールが機能するかは、接続メタデータ、DNSマッピングキャッシュ、ドメインスニッフィングに左右されます。デスクトップ環境でTUNを使い、ドメインルールを中心に運用するなら、まずFake-IPを試してください。LANサービスの不具合が多い場合は、モード全体を無効にするのではなく、項目ごとに除外を追加します。

TUNモードでのDNSハイジャック

dns.enableを有効にしただけで、すべてのプログラムが自動的にClash DNSを使うとは限りません。ブラウザが独自のセキュアDNSを使うこともあれば、システムがUDP 53の問い合わせをルーターへ送ることもあります。一部のアプリはシステムプロキシを迂回します。TUNモードの dns-hijack は、指定ポートのDNSトラフィックを捕捉してコアへ渡すために使います。

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

any:53は通常のUDP 53問い合わせを対象にし、tcp://any:53はTCP 53を使う問い合わせを対象にします。DoHはHTTPS上で動作し、通常は443番ポートを使うため、これらでアプリが直接送信するDoHリクエストを自動的に捕捉することはできません。ブラウザが独自にDoHを指定していると、問い合わせがClash DNSに入らない場合があります。切り分けでは一時的にブラウザのセキュアDNSを「システム設定を使用」に変更し、ログを比較してください。

TUNを有効にしても、システム側の権限は必要です。Windowsでは通常、コアによる仮想ネットワークアダプターとルートの作成が必要です。macOSではネットワーク拡張機能またはVPN構成の許可を求められ、LinuxではTUNデバイスへのアクセスとルート変更が必要になります。ログに permission denied、インターフェース作成失敗、ルート追加失敗が出た場合は、まず権限を解決し、nameserverを何度も変更しないでください。

listenポートの選び方

listen: 127.0.0.1:1053はローカルテストに適しており、LAN上の他の端末へ直接公開されません。他の端末からこのPCをDNSとして使う必要がある場合は、LANインターフェースで待ち受けたうえで、システムファイアウォールと固定アドレスも設定します。ポート53はシステムの名前解決サービス、仮想マシンソフト、別のDNSプログラムが使用していることがあるため、1053や5353などの高位ポートが切り分けに向いています。ただし5353はmDNSサービスと競合する可能性があります。

mihomoの推奨設定例

以下はデスクトップ環境で使い始めるのに適したmihomo設定です。Fake-IP、2台のDoHリゾルバー、ノード専用リゾルバー、TUN DNSハイジャックを使用します。DNSは利用中のネットワークから到達できるものに合わせて調整し、「完全さ」のために安定して接続できないアドレスまで残す必要はありません。

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16

  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29

  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query

  proxy-server-nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query

  nameserver-policy:
    "+.local":
      - 192.168.1.1
    "+.lan":
      - 192.168.1.1

  fake-ip-filter:
    - "*.lan"
    - "+.local"
    - "localhost"
    - "time.*.com"
    - "ntp.*.com"

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

この例では ipv6false に設定しています。ローカルのIPv6ルートが不安定な場合や、プロキシノードがIPv6に対応していない場合に適しています。回線、LAN、ノードがすべてIPv6を正しく扱えるなら true に変更し、ルールにIPv6アドレス範囲が含まれているかも確認してください。DNSでIPv6の応答だけを有効にし、利用可能なIPv6の出力先がないと、アプリがAAAAアドレスを優先してタイムアウトすることがあります。

インポートする前に、現在動作している設定をコピーしておきます。一般的なデスクトップクライアントでは、「設定」から現在のサブスクリプションまたはローカル設定の編集画面を開けます。サブスクリプション設定は更新時に手動変更を上書きすることがあるため、クライアントのオーバーライド、拡張設定、Mixin機能を使うほうが安全です。保存後はコアの起動ログを確認し、YAMLのインデントエラー、未知の項目、ポート競合がないことを確認してください。

DNSが想定どおり動作するか確認する

手順1:コアのログを確認する

設定を保存してコアを再起動したら、まず30秒間ログを観察します。DNSlookuptimeoutconnection refusedaddress already in usefailed to parse を重点的に検索してください。127.0.0.1:1053が使用中なら、占有しているプログラムを終了するか、listenを空いているポートへ変更します。

手順2:ローカルの待ち受けポートへ直接問い合わせる

digがインストールされている環境では、ブラウザのキャッシュを介さずClash DNSを直接テストできます。以下のコマンドでは、ローカルアドレスと1053番ポートを明示します。

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

Fake-IPモードでは、Aレコードが 198.18.0.0/16 内のアドレスを返すことがありますが、これは想定された動作です。fake-ip-filterに追加したドメインは実際のアドレスを返すはずです。両方のドメインで結果がまったく同じ場合は、enhanced-modeが有効か、サブスクリプションに設定を上書きされていないか、現在実行されている設定が編集したものかを確認してください。

手順3:ルールと接続ログを比較する

テスト用のドメインを1つ開き、接続記録に宛先IPだけでなくドメイン名が表示されることを確認します。次に、適用されたルールとプロキシグループを確認してください。DNSの問い合わせに成功して接続だけ失敗するなら、問題は通常ノード、ルート、ルールの段階にあります。DNSログが直接タイムアウトする場合は、リゾルバーへの到達性、プロキシノードのドメイン、ファイアウォールを引き続き確認します。

手順4:ネットワークを切り替えてテストする

家庭の固定回線、スマートフォンのテザリング、その他の利用可能なネットワークでそれぞれテストします。切り替えるたびに10~30秒待ち、インターフェース、ルート、DNSキャッシュの更新を完了させてください。特定のネットワークだけで失敗する場合は、そのネットワークが特定のDNSプロトコルを遮断している、IPv6ルートに問題がある、またはDoHサーバーへ到達できない可能性があります。この場合は、すべての項目を一度に置き換えず、UDP DNSを1台、DoHを1台だけ残して比較します。

よくあるエラーと対処の順番

エラー1:ノードがすべてタイムアウトするが、Webドメインは解決できる

まずproxy-server-nameserverを確認します。ノードアドレスにドメイン名を使っている場合、通常のnameserverが正常でも、ノードのドメインが利用可能な経路で解決されているとは限りません。ノードのドメインが、プロキシ接続後でなければアクセスできないDNSへnameserver-policyで振り分けられていないかも確認してください。

エラー2:TUNを有効にするとLAN機器へ接続できない

ルーター、NAS、プリンター、画面ミラーリングサービスが使用するドメインをfake-ip-filterに追加し、内部ドメインにはnameserver-policyを設定します。LANでよく使われるサフィックスには .lan.local がありますが、実際の名称はルーターのDHCPまたは内部DNS設定に合わせてください。DHCPリース更新でアドレスが変わる可能性があるため、現在のIPアドレスだけを追加しないでください。

エラー3:ブラウザでは開けるが、コマンドラインのプログラムが失敗する

ブラウザが独自のDoHを使い、コマンドラインはシステムDNSに依存している可能性があります。また、ブラウザはシステムプロキシを使い、コマンドラインはTUNだけを使っていることもあります。まずブラウザ独自のセキュアDNSを無効にして比較し、次にdigでClashの待ち受けポートへ問い合わせます。ローカル問い合わせが正常なら、システムプロキシ、TUNルート、そのコマンドラインプログラムがリゾルバーを固定指定していないかを確認します。

エラー4:ルールがドメインではなくIPにマッチすることがある

DNS問い合わせが本当にClashを経由しているか、enhanced-modeがどう設定されているかを確認します。redir-hostを使っている場合は、コアが対応するドメインスニッフィングを有効にできますが、すべてのプロトコルでドメインを復元できるわけではありません。ドメインルールへの依存が強いデスクトップ環境では、適切な除外リストとFake-IPを組み合わせるほうが安定しやすいです。

エラー5:設定更新後に手動変更が消える

サブスクリプションの更新では、通常設定ファイルが再書き込みされます。DNSのカスタム項目は、クライアントのオーバーライド、拡張スクリプト、Mixin、または独立したローカル設定で管理してください。編集前に「設定」→「コア」に表示される実際のコアを記録し、「ログ」で読み込まれたファイルのパスを確認します。現在の設定で使われていないコピーを編集する事態を避けるためです。

設定方針のまとめ

  • 通常のドメイン解決はnameserverに置き、DoHの起動に必要な基礎名前解決はdefault-nameserverに置きます。
  • プロキシノードにドメイン名を使う場合は、直接アクセスできるproxy-server-nameserverを設定し、循環依存を避けます。
  • ドメインごとの振り分けにはnameserver-policyを優先し、fallback-filterは従来型の2系統リゾルバーを選別する互換構成に向いています。
  • TUN環境ではdns-hijackでUDP 53とTCP 53を取り込みますが、アプリが独自に送信するDoHを自動的に取り込むことはできません。
  • Fake-IPはドメイン情報の保持に役立ちます。LAN、時刻同期、機器検出に問題がある場合は、fake-ip-filterを項目ごとに追加してください。
  • 1回に変更するのは1グループの設定だけにし、コアを再起動した後にログを確認し、ローカルポートへの問い合わせで検証します。DNS、ルール、ノードを同時に変更するのは避けてください。

保守しやすいClash DNS設定に、大量のサーバーを詰め込む必要はありません。まず通常のドメイン、ノードのドメイン、内部ドメインをそれぞれどこで解決するかを決め、そのうえでfallback、Fake-IP、TUNハイジャックが必要か判断します。経路を整理すれば、名前解決の失敗、ルールの誤判定、LANの競合を対応する項目から切り分けられます。