DNS解決・ルールによる振り分け・通信の取り込みを区別する
ClashのDNS設定は、ドメイン名をIPアドレスに変換するほか、Fake-IPモードではドメイン名と仮想IPアドレスを対応付けます。接続先のプロキシはルールで決まり、システムプロキシやTUNはどの通信がコアに取り込まれるかを決めます。この3つは関連していますが、互いに代用できるものではありません。パブリックDNSを設定しても、ブラウザーの通信がプロキシ経由になるわけではなく、TUNを有効にしても、すべての暗号化DNSが取り込まれるわけではありません。
この記事では、Clash Metaの後継として開発されているmihomoコアを主な対象として解説します。従来のClashや各クライアントで対応する設定項目は異なり、特にtunやproxy-server-nameserverには違いがあります。トラブルシューティングの前に、クライアントの「バージョン情報」またはコア情報で、実際のコア名とバージョンを確認してください。クライアントの製品名だけで判断しないようにしましょう。
- DNSリクエストの入口:アプリ、システムリゾルバー、またはTUNが取り込んだ53番ポートの通信。
- DNSの上流:
nameserverやfallbackなどのリストに設定するDNSリゾルバー。 - アプリ通信の出口:
rulesとプロキシポリシーで決まり、DNSサーバーの設置地域で直接決まるものではありません。
dns設定ブロック:最小構成の例から始める
デバッグ時はまずredir-hostを使って実際のIPアドレスを確認し、上流に接続できることを確かめてから、必要に応じてFake-IPに切り替えてください。以下の例では、ローカルの127.0.0.1:1053でDNSサービスを待ち受けます。1053はサンプルの待ち受けポートであり、すべてのクライアントで変更が必要な既定値ではありません。
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: redir-host
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- https://dns.alidns.com/dns-query
fallback:
- https://1.1.1.1/dns-query
fallback-filter:
geoip: true
geoip-code: CN
ipcidr:
- 240.0.0.0/4
| 項目 | 設定例の意味 | 確認ポイント |
|---|---|---|
enable | コアのDNS機能を有効化 | 起動ログにDNS初期化エラーが出ていないか |
listen | ループバックアドレスの1053番ポートで待ち受け | ポートの競合がないか、テスト時に正しいポートを指定しているか |
ipv6 | この例ではAAAAレコードを返さない | OSのIPv6通信を無効にする設定ではない |
enhanced-mode | 実際のIPアドレスを返すモードを使用 | Fake-IPモードで仮想IPアドレスが返るのは正常 |
default-nameserver | 上流DNSのホスト名を名前解決するためのサーバー | ブートストラップ用リゾルバー自体に接続できるか |
listen: 127.0.0.1:1053はローカルからの接続のみを受け付けるため、デスクトップでのデバッグに適しています。0.0.0.0:1053に変更すると、待ち受け範囲が広がります。LAN内の端末にDNSサービスを提供する場合は、信頼できないネットワークに公開しないよう、ファイアウォールで接続元を制限してください。
default-nameserverは、通常のクエリで使う「第3の予備サーバー」ではありません。上流にhttps://dns.alidns.com/dns-queryを指定した場合、コアはまずこのホスト名に対応するIPアドレスを知る必要があります。例ではIPアドレスを直接指定し、リゾルバーの起動に自身の名前解決が必要になる事態を避けています。通常のUDPによるブートストラップクエリには、DoHのような通信経路の暗号化はありません。利用するネットワークのプライバシー要件と接続性に応じて選択してください。
nameserverとfallback:単純な優先・予備の関係ではない
nameserverは通常の名前解決に使う
nameserverは通常の上流DNSサーバーのリストです。ドメインごとのポリシーを別途設定していない場合、通常のクエリはこのリストで処理されます。複数のアドレスを指定しても、1番目、2番目の順に必ず試すという意味ではありません。コアが複数の上流へ同時に問い合わせ、利用可能な結果を選ぶ場合があるため、並び順をドメインの振り分けに利用しないでください。
fallbackは別の候補となる結果を提供する
fallbackを有効にしても、「nameserverがタイムアウトしたときだけ問い合わせる」という意味ではありません。一般的なnameserver/fallbackの仕組みでは、両方のグループに並行して問い合わせ、fallback-filterに基づいて採用する結果を決めます。別の結果に切り替える際の待ち時間を減らせますが、もう一方のサービスにもクエリが送られる可能性があります。
プロキシ経由になるかどうかは別の問題です。https://1.1.1.1/dns-queryをfallbackに指定しても、このDoH接続が自動的にプロキシノードを経由するわけではありません。実際の通信経路は、コアのバージョン、上流DNSの指定方法、関連するルーティング設定によって異なります。現在のネットワークから接続できない場合は、フィルター条件を何度も変えるのではなく、まず接続性を確認してください。
- 基本的な名前解決だけを確認する場合:接続できる
nameserverを1つ残し、fallbackとそのフィルターを一時的に外します。 - 2組の結果から選択する必要がある場合:fallbackを追加し、フィルター条件を明示的に設定します。
- 特定のドメインに指定したリゾルバーを使う場合:リストの順序に頼らず、
nameserver-policyを使います。
fallback-filterの判定:geoip・ipcidr・domain
fallback-filterは、fallbackの結果を採用する条件を判定します。ファイアウォールのルールでも、アプリ通信のプロキシ先を指定するルールでもありません。geoip-code: CNを設定しても、中国本土のサイトが必ず直接接続になるわけでも、その他の地域のサイトが必ずプロキシ経由になるわけでもありません。
geoip:nameserverが返したIPアドレスの地域を確認
geoip: trueとgeoip-code: CNを指定した場合、通常はCNに属するnameserverの結果を採用し、条件に合わない場合はfallbackの結果を使う方向で判定します。この判定はDNSサービス事業者の所在地ではなく、コアが使用するGeoIPデータに依存します。データがない、古い、またはCDNのIPアドレスの割り当て先が変わった場合、判定に影響することがあります。
ipcidr:特定のIPアドレス範囲に別の結果を適用
例の240.0.0.0/4は、この範囲に一致したnameserverの結果をfallbackで処理する設定です。あくまで疑わしいアドレス範囲の例であり、あらゆる誤った名前解決を検出できるわけではありません。192.168.0.0/16などのプライベートアドレス範囲をフィルターにまとめて追加しないでください。企業内ネットワーク、ルーターの管理画面、ローカルドメインでは、プライベートIPアドレスが正しい応答の場合があります。
domain:指定したドメインにfallbackを適用
ドメインのフィルター条件はIPアドレスの条件と異なり、ドメイン名に基づいてfallbackを選択できます。以下はGeoIP判定を無効にした独立した例で、予約済みの例示用ドメインexample.comとそのサブドメインにのみ適用します。実際の環境では、この動作が本当に必要なドメインを指定してください。
dns:
fallback-filter:
geoip: false
domain:
- '+.example.com'
domain、ipcidr、有効にしたGeoIP判定は、それぞれ単独でfallbackを適用する条件になり得ます。3つすべてが同時に成立する必要はありません。「特定のドメインだけ別の上流を使う」場合は、不要なGeoIP条件を明示的に無効にし、設定全体にほかのフィルター条件が残っていないか確認してください。
nameserver-policyとノードのホスト名:名前解決のループを防ぐ
LAN内のドメイン名は、通常パブリックDNSに送るのに適していません。mihomoではnameserver-policyを使って、特定のドメインに上流を指定できます。以下の192.168.1.1は、そのアドレスが実際にローカルDNSサーバーであるネットワークでのみ使えます。ゲートウェイが192.168.50.1の環境で、そのまま使わないでください。
dns:
nameserver-policy:
'+.home.arpa':
- 192.168.1.1
proxy-server-nameserver:
- 223.5.5.5
- 119.29.29.29
home.arpaは家庭内ネットワーク用の特殊なドメイン空間です。個別にポリシーを指定すると、LAN内のレコードをパブリックfallbackに推測させず、ローカルリゾルバーに問い合わせられます。ポリシーに一致すると専用の名前解決経路が使われるため、そのドメインが一般的なnameserver/fallbackの選択手順にそのまま従うとは限りません。
proxy-server-nameserverは、プロキシノードのホスト名を名前解決するために使います。「接続先サイトの名前解決をどのノード経由で行うか」とは別の問題です。DoHへの接続にプロキシが必要で、そのプロキシノードのホスト名も同じDoHに依存している場合、起動時に依存関係がループします。ノードのホスト名用に接続可能な独立した名前解決経路を用意すると、このリスクを減らせます。対応状況は、実際に使うmihomoのバージョンで確認してください。
名前解決のループを直そうとして、複数のルーティングオプションを一度に追加しないでください。まずノードのホスト名が解決できること、ノード経由で接続できることを確認し、その後で通常のDNSにもアプリのルールを適用するか判断します。変更後は、クライアントが最終的に生成した実行用設定を確認し、サブスクリプションのオーバーライドで新しい項目が削除されていないかチェックしてください。
TUNでのdns-hijack:設定階層とプロトコルの書き方
dns-hijackはトップレベルのtun設定ブロックに記述する項目で、dnsの中ではありません。TUNに取り込まれたDNS通信のうち条件に一致するものを、コアのDNSモジュールへ転送します。以下はmihomoで一般的な書き方です。有効にする前に、クライアントに仮想ネットワークアダプターの作成とルーティング変更に必要な権限があることを確認してください。
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- 'any:53'
- 'tcp://any:53'
any:53:TUNに取り込まれたUDP 53番ポートのDNSリクエストに一致します。tcp://any:53:TCP 53番ポートも対象にします。TCPでの問い合わせや、一部の応答が切り詰められた際の再試行に対応します。auto-route:必要なルートを自動設定します。ただし、すべてのプラットフォームでLAN内の通信がTUNに入るとは限りません。auto-detect-interface:通信に使うインターフェースを検出します。複数のネットワークアダプター、ほかのVPN、複雑なルーティングがある環境では、実際の出口を確認してください。
dns-hijackは、システムのDNSアドレスを127.0.0.1:1053に変更する設定でも、hijack先を1053に書き換える設定でもありません。前者は元々53番ポートに送られるリクエストに一致する設定です。一方、dns.listenは独立したDNSサービスの待ち受け先です。役割は異なりますが、併用できます。
hijackを有効にしても、別のDNS通信が見えるのはなぜ?
DoHは通常HTTPSの443番ポート、DoTは一般にTCP 853番ポート、DoQはUDP 853番ポートを使います。これらは一般的な53番ポートのDNS通信ではないため、上記の2つの設定だけでは横取りして復号できません。ブラウザーの「セキュアDNS」やAndroidの「プライベートDNS」が有効な場合、またはアプリが独自のリゾルバーを内蔵している場合、問い合わせが暗号化されたアプリ通信として残ることがあります。
また、同じサブネット内のルーター宛て通信は、TUNに入らず物理インターフェースから直接送信される場合があります。スイッチがオンかどうかだけで判断せず、プラットフォームのルーティングとシステムDNSアドレスを確認し、実際の通信経路を特定してください。調査のためにアプリの暗号化DNSを一時的に無効にする場合は、元の設定を記録し、確認後に必要に応じて戻してください。
コマンドで検証する:待ち受け・上流・通信の取り込みを順に確認
以下のコマンドはテスト手順を再現するためのもので、特定のネットワーク環境での実測結果を示すものではありません。実際の名前解決結果を確認しやすいよう、例ではredir-hostを使い、Fake-IPの仮想アドレスによる影響を避けています。設定項目は一度に1組だけ変更し、そのたびに設定を再読み込みしてください。
手順1:コアのDNS待ち受けポートに直接問い合わせる
digを利用できるmacOSまたはLinuxのターミナルで、UDPとTCPをそれぞれテストします。Windowsでも、対応ツールをインストールした環境なら同じコマンドを使えます。標準搭載のnslookupを対話モードで起動し、ポートを指定して確認する方法もあります。
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp
nslookup
server 127.0.0.1
set port=1053
set type=A
example.com
exit
NOERRORが返り、ANSWERにAレコードがあれば、その問い合わせで名前解決できています。SERVFAILは名前解決の処理に失敗したことを示します。タイムアウトした場合は、待ち受け、上流、ファイアウォールも確認してください。NOERRORでもAレコードがない場合、ドメインに対応するレコードが存在しない可能性があるため、直ちに失敗とは判断できません。
手順2:上流とフィルターの問題を切り分ける
- fallbackを一時的に外し、nameserverを1組だけ残して同じドメインを再度問い合わせます。
- テストするfallbackサーバーを一時的に唯一のnameserverとして設定し、単独で名前解決できるか確認します。
- 2組の上流を元に戻し、GeoIP、IPアドレス範囲、ドメインの各条件を1つずつ有効にして変化を確認します。
- ログに記録された上流への接続エラー、タイムアウト、設定の読み込みエラーを手掛かりに原因を特定してください。すべての異常をDNS汚染のせいにしないようにしましょう。
手順3:待ち受けではなくTUNを検証する
127.0.0.1:1053に直接問い合わせても、確認できるのはDNSの待ち受けが使えることだけで、TUNによるhijackが成功した証明にはなりません。システムやアプリから通常のDNSアドレスの53番ポートへ問い合わせを送り、コアのログと接続情報を確認してください。パケットをキャプチャできる場合は、物理インターフェースから元の問い合わせが送信されていないかも確認します。テスト中はブラウザーのDoHを無効にし、ローカルキャッシュにより問い合わせ自体が発生しない可能性にも注意してください。
Windowsではipconfig /flushdnsでシステムのDNSキャッシュを削除できます。macOSではsudo dscacheutil -flushcacheとsudo killall -HUP mDNSResponderを実行します。Linuxのキャッシュサービスはディストリビューションによって異なりますが、systemd-resolvedを使っている場合はresolvectl flush-cachesを実行します。これらのコマンドですべてのブラウザーキャッシュが消えるわけではなく、クライアント内部のDNSキャッシュを消去する代わりにもなりません。
よくある症状と設定の仕上げ
| 症状 | まず確認する項目 | 次に行うこと |
|---|---|---|
| 1053番ポートへの問い合わせがタイムアウトする | DNSモジュールが無効、ポートが競合、または上流に接続できない | 実行中の設定と起動ログを確認し、上流を1組ずつテストする |
| 198.18で始まるアドレスが返る | 実際の設定でFake-IPが有効になっている | 仮想IPアドレスの範囲とTUNのルートを確認し、直ちに名前解決エラーと判断しない |
| LAN内のホスト名を解決できない | 問い合わせがパブリックDNSに送られている、またはプライベートIPアドレスがフィルターされている | 内部ドメインにローカルの名前解決ポリシーを設定し、フィルターリストを確認する |
| ノードを有効にすると、すべてのドメインがタイムアウトする | ノードのホスト名とDNSの通信経路に依存関係のループがある | ノードのホスト名の名前解決とノードへの接続を個別に確認する |
| TUNは有効だが、ブラウザーが別のリゾルバーを使っている | ブラウザーのセキュアDNSが有効、または通信がTUNに入っていない | 暗号化DNS、システムDNS、ルーティングをそれぞれ確認する |
設定の仕上げでは、用途が明確な項目だけを残しましょう。nameserverは通常の名前解決に使い、fallbackはフィルターと組み合わせて別の結果を選択します。nameserver-policyは特定のドメインを処理し、dns-hijackはTUNに取り込まれた従来のDNSリクエストを転送します。最後に、サブスクリプション更新後の実行用設定を確認し、デバッグ中に一時変更したブラウザーやシステムのDNS設定、ログレベルを必要に応じて元に戻してください。段階ごとに検証できるシンプルな設定のほうが、パブリックDNSを次々に追加するより管理しやすくなります。