まずは「横取り」「名前解決」「接続」の3経路を整理
「DNSを有効にした」だけでは、すべてのアプリがこのDNS設定を使うとは限りません。mihomoのDNSトラブルは、アプリの問い合わせがコアに届いているか、コアがどの上流DNSに問い合わせているか、名前解決後の接続がどのプロキシルールで処理されるか、の3段階に分けて確認します。いずれかで問題が起きるとWebサイトを開けなくなることがありますが、同じ設定項目を切り替えるだけで3種類の問題すべてが解決するわけではありません。
- DNSの受け口:
dns.listenでDNSリクエストを待ち受けます。TUNではdns-hijackにより、条件に一致するDNSトラフィックを内蔵リゾルバーへ転送します。 - 上流DNSの選択:
nameserver、nameserver-policy、fallbackなどの項目で、名前解決の経路や結果の選び方を指定します。 - 接続の振り分け:
rulesでWebサイトへの接続を直接接続にするかプロキシ経由にするか決めます。respect-rulesを有効にすると、DNS上流への接続もルーティングルールに従います。
この記事はmihomoコアを使用するクライアントが対象です。オリジナルのClash、Premium、各世代のMetaコアでは、対応する設定項目が異なります。まずクライアントのコア情報や起動ログで実際のコアを確認し、現在有効な設定を編集してください。GUIクライアントのバージョン番号だけではコアのバージョンは判断できません。
default-nameserver:DNSサーバー自身のホスト名を名前解決
上流DNSにhttps://dns.alidns.com/dns-queryを指定した場合、HTTPS接続を確立するには、まずdns.alidns.comのIPアドレスを調べる必要があります。default-nameserverは、この最初の名前解決を行うための設定です。「すべてのWebサイトで使うデフォルトのDNS」ではありません。名前は似ていますが、トラブル時に確認すべき箇所はまったく異なります。
dns:
enable: true
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- https://dns.alidns.com/dns-query
上記の2つのIPアドレスは、初期の名前解決に使用します。通常のIPアドレス形式で指定したDNSは、一般にUDP 53番ポートを使います。後続の上流DNSがDoHでも、この問い合わせが自動的に暗号化されるわけではありません。初期問い合わせも暗号化したい場合は、現在のコアが対応し、別の名前解決に依存しないIPアドレス形式の暗号化エンドポイントを選び、証明書と接続方法が利用環境に適合することを確認してください。
nameserverとfallback:メインのタイムアウト後に予備へ切り替わるわけではない
nameserver:通常の名前解決に使う上流DNS
nameserverは、より具体的なDNSポリシーが適用されない場合に使う、通常の上流DNSです。複数のアドレスを設定すると耐障害性を高められますが、リストの順番どおりに「1つ目が失敗したら2つ目へ問い合わせる」とは限りません。コアが並行して問い合わせる場合もあり、DNSキャッシュにより上流へ問い合わせないこともあります。
DoHのHTTPS接続には通常TCP 443番ポート、DoTには通常TCP 853番ポートが使われます。暗号化プロトコルは問い合わせ経路を保護するもので、接続に使うプロキシノードを直接決めるものではありません。DoHのURLをブラウザーで開けても、現在のルーティング、証明書、プロキシ設定でmihomoから接続できるとは限りません。
fallback:応答結果のフィルタリングと組み合わせて使う
fallbackは、ネットワークがタイムアウトしたときだけ使う従来型の予備サーバーではありません。設定すると、コアはfallback-filterと組み合わせて応答結果を選び、関連する問い合わせを並行して行う場合があります。ログで両方の上流DNSに問い合わせが届いていても、設定を二重に読み込んだわけではありません。
| 項目 | 主な役割 | 誤解しやすい点 |
|---|---|---|
default-nameserver | 上流DNSのホスト名を初期解決する | すべてのサイトで使うデフォルトの上流DNS |
nameserver | 通常のドメイン名解決 | 順番どおりに実行されるリスト |
fallback | フィルタリングに使う別の応答結果を提供 | タイムアウト時だけ問い合わせる予備サーバー |
fallback-filter | fallbackの結果を選択する条件を指定 | プロキシルールやファイアウォールルール |
dns-hijack | TUN経由のDNSトラフィックを条件に応じて受け取る | アプリ独自のDoHを復号する設定 |
fallback-filter:地域、IPアドレス、ドメインでフィルタリング
以下では、中国本土の上流DNSと別のパブリックDoHを組み合わせ、フィルタリングの仕組みを説明します。設定項目の例であり、どのネットワークからもすべてのエンドポイントへ直接接続できるとは限りません。代替の上流DNSに接続できない場合は、まず到達性やルーティングを確認してから、応答結果の信頼性を検討してください。
dns:
enable: true
default-nameserver:
- 223.5.5.5
- 119.29.29.29
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'
geoip: trueとgeoip-code: CN:通常、メインの上流DNSが指定地域に属さないIPアドレスを返した場合、fallbackの結果を優先します。この判定はコアが使用するGeoIPデータに依存します。ipcidr:メインの上流DNSが返したIPアドレスが指定したネットワーク範囲に一致すると、fallbackの結果が選ばれます。例の240.0.0.0/4は予約済みアドレスの範囲であり、異常なアドレスをすべて網羅した一覧ではありません。domain:一致したドメインはfallback経由で解決します。例の+.google.comは該当ドメインとサブドメインを対象にします。引用符で囲んだ文字列にすると、YAMLの解析時の曖昧さを減らせます。
地域によるフィルタリングは運用上の方針であり、DNS汚染を数学的に証明するものではありません。海外のドメインが中国本土のCDNを使うことも、中国本土のサービスが海外のIPアドレスを返すこともあります。GeoIPデータが古い場合は誤判定の原因にもなります。特定のドメインだけ別のリゾルバーを使いたい場合は、複雑な地域条件を重ねるよりnameserver-policyを使う方が簡潔です。このポリシーが適用された場合、必ずここで説明した汎用的なfallbackの処理を通るとは限りません。
地域判定が不要なら、geoip: falseを明示し、根拠のあるドメイン条件やIPアドレス条件だけを残します。タイムアウトのログを消すためだけに、大量のプライベートIPアドレス範囲を安易に追加しないでください。イントラネットのサイトがプライベートIPアドレスを返すのは正常です。
respect-rules:DNS上流への接続にルールを適用
respect-rules: trueは「コアがDNS上流へ接続するときの経路」を制御する設定であり、「ドメインルールを有効にするか」を決めるものではありません。有効にする前に、プロキシノード自身のホスト名を解決するproxy-server-nameserverを用意してください。そうしないと、「ノードを名前解決するにはプロキシが必要だが、プロキシを確立するにはノードの名前解決が必要」という循環依存が起きることがあります。
dns:
respect-rules: true
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
これは差分として追加する設定例であり、DNS設定全体を置き換えるものではありません。初期解決に使うdefault-nameserver、通常の上流DNS、その他の設定を残し、ノードのホスト名解決に使う上流DNSが起動時から接続可能であることを確認してください。ノード用のリゾルバーを設定しても、すべてのドメイン名に対するリゾルバーを設定したことにはなりません。
- まずプロキシノードに接続できることと、ルールで参照しているプロキシグループ名が存在することを確認します。
- DNSサービスのホスト名や接続先IPアドレスに、どのルールが適用されるか確認します。上流DNSへの経路が到達不能なルールに振り分けられている場合、この設定を有効にしても失敗が繰り返されるだけです。
- ログで上流への接続に選ばれた出口を確認してから、Webサイトへの接続をテストします。ノードの遅延表示だけでDNSが正常だと判断しないでください。
TUNのdns-hijack:仮想ネットワークインターフェースに入る53番ポートの通信を受け取る
dns.enable: trueを設定しただけでは、OS全体の名前解決経路は変更されません。TUNモードではdns-hijackを使い、TUNに入って条件に一致するDNSトラフィックをコアへ渡せます。以下は既存のmihomo設定に追加できる基本例です。既存のプロキシノード、プロキシグループ、ルールは残してください。
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
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
any:53はUDP DNS、tcp://any:53はTCP DNSに対応します。接続先のポートをあらかじめローカルの1053番に変更する必要はありません。条件に一致した通信は、横取り処理によって内蔵DNSへ渡されます。listenは明示的な問い合わせに使える独立した待ち受け口です。ループバックアドレスを指定すれば、意図せずLANにDNSサービスを公開するのを防げます。
ここでの198.18.0.1/16はfake-ipのマッピングに使われます。問い合わせ結果としてこの範囲の合成アドレスが返るのは想定どおりで、上流DNSが実際にそのアドレスを返したという意味ではありません。コアはマッピングからドメイン名を復元し、その後の接続を処理します。特定のアプリに実IPアドレスが必要な場合は、用途に応じてfake-ip-filterを設定してください。予約済みアドレス範囲全体をDNS障害とみなす必要はありません。
- デスクトップ:TUNの利用には、クライアントやOSに応じて管理者権限、サービスモード、または適切なネットワーク権限が必要です。
- Android:VPNの許可設定が他のVPNアプリと競合することがあります。システムの「プライベートDNS」によって名前解決の経路が変わる場合もあります。
- ブラウザー:内蔵のセキュアDNSはHTTPSで443番ポートへ送信されるため、53番ポートの横取りですべて捕捉できるとは限りません。
- LANとIPv6:TUNを通らない通信、ルーティング対象から除外されたアドレス、他のインターフェースを通る通信についても個別に確認が必要です。
例のdns.ipv6: falseはDNSによるAAAA問い合わせの処理を制御する設定です。OSのIPv6を無効にするものではなく、IPv6経由の漏えいを完全に防ぐ設定でもありません。Linuxのローカル名前解決サービス、macOSのLAN内名前解決経路、AndroidのVPN実装にも、それぞれ固有の制約があります。DNSの横取りが機能しているかは、実際の問い合わせを確認して判断してください。
コマンドで段階的に検証:待ち受け、横取り、上流DNSの順に確認
手順1:設定とローカルの待ち受けを確認
編集前に現在の設定をバックアップしてください。コアを単独で実行している場合は、まず以下のコマンドで設定を検証します。GUIクライアントでは、実際に使用しているコアと作業ディレクトリを使ってください。同じ名前の別ファイルを誤って検証しないためです。
mihomo -t -f config.yaml
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp
最初の2つの問い合わせで、1053番ポートのUDPとTCPの待ち受けをそれぞれ検証できます。digが使えないWindows環境では、nslookup -port=1053 example.com 127.0.0.1を実行してください。fake-ipが返ることから確認できるのは、問い合わせがリゾルバーに届き、マッピングが返されたことまでです。指定したDoHから実IPアドレスが正常に返された証拠にはなりません。
手順2:53番ポートの通信がTUNに横取りされるか確認
dig @8.8.8.8 example.com A
dig @8.8.8.8 example.com A +tcp
ここで明示的に指定した8.8.8.8はテスト対象です。リクエストがTUNに横取りされた場合、実際に問い合わせを受ける上流DNSは8.8.8.8とは限りません。コアのログとfake-ipの応答をあわせて確認してください。digの出力にあるSERVER行だけでは判断できません。そこにはプログラムで指定した元の接続先が表示されることがあります。
手順3:実際の名前解決とWebサイトへの接続を確認
- ログレベルを一時的に
debugに上げ、問題が起きた問い合わせのドメイン名、エラー内容、上流DNSのアドレスを記録します。ログを共有する前に、サブスクリプションURLやノードの認証情報を伏せてください。 - クライアントのDNSキャッシュを消去するか、コアを再起動して、まだ問い合わせていないドメインでテストします。Windowsでは
ipconfig /flushdnsでシステムのキャッシュを消去できますが、ブラウザーやコアのキャッシュは消去されません。 - 実際の応答を確認するには、管理されたテスト環境で一時的に
enhanced-mode: redir-hostを使い、再起動後にもう一度問い合わせます。テスト後は元の設定に戻してください。アプリに残った古いfake-ipのマッピングが判定に影響するのを防げます。 - 最後にWebサイトへアクセスし、接続に適用されたルールを確認します。DNSの応答が成功しているのにHTTPSがタイムアウトする場合は、プロキシの出口、接続ルーティング、TLS、MTUを調べてください。リゾルバーを何度も変更する必要はありません。
この記事のコマンドは、問題を再現して原因を特定するための手順です。特定のネットワークで実測した遅延値を示すものではありません。性能を比較する場合は、同じネットワークでキャッシュが空の状態と温まった状態をそれぞれ記録してください。2回目の問い合わせ時間だけを比べると、測っているのはキャッシュの働きのよさに過ぎないことがあります。
よくある障害と設定を戻す手順
| 症状 | まず確認する項目 | 対処方法 |
|---|---|---|
| ローカルの1053番ポートへの問い合わせがタイムアウトする | 設定の読み込み、ポートの競合、コアのログ | まず待ち受けを復旧し、その後で上流DNSを確認 |
| 1053番ポートへの問い合わせは正常だが、アプリがシステムDNSを使う | TUNの許可、ルーティング、ブラウザーのセキュアDNS | 問い合わせが横取りの対象範囲に入っているか確認 |
| respect-rulesを有効にするとすべてタイムアウトする | ノードのホスト名解決とDNS上流への接続ルール | ノード用の独立した名前解決経路を用意 |
| 一部のドメインだけ問題が起きる | 適用ポリシー、fallbackの条件、キャッシュ | ドメインごとに確認し、設定全体を一度に変更しない |
| サブスクリプション更新後に障害が再発する | 最終的に有効な設定とオーバーライドのマージ結果 | 変更内容を保持できるオーバーライド設定に移す |
設定を戻すときは、まず「到達可能な上流DNSを1つだけ設定し、複雑なフィルタリングを無効にした状態」にして、通常の名前解決を確認します。次にTUNの横取りを有効にし、最後にfallbackとルールに応じたルーティングを追加します。各段階で設定と問い合わせ結果を記録してください。設定項目を増やすほど名前解決が安定するわけではありません。各問い合わせがどの上流DNSに進むのか説明できる設定こそ、保守しやすい設定です。