DNS名前解決・ルールによる振り分け・通信の取り込みを区別する

Clashでノードに接続できているのに、一部のサイトが開かない場合、原因はノードの停止とは限りません。アクセス時には少なくとも、ドメイン名をIPアドレスに変換する、ルールに応じて通信経路を選ぶ、アプリの通信をプロキシコアに取り込む、という3つの処理が関係します。DNS設定が主に担うのは最初の処理です。TUNやシステムプロキシは3つ目の処理を左右します。DNSサーバーを変更しただけでは、すべてのアプリの通信が自動的に取り込まれるわけではありません。

この記事では、一般にClash Metaのコアとして知られるmihomoを主な設定対象とします。オリジナル版Clashや各派生版、クライアントの画面によって、対応する設定項目は異なります。まずクライアントのコア情報または起動ログで実際のコアを確認し、対応する設定を使ってください。アプリのバージョンとコアのバージョンは別の番号です。

  1. アプリから名前解決:OSのDNSを使う場合もあれば、ブラウザー独自のセキュアDNSを使う場合もあります。
  2. コアがクエリを処理:クエリを受け取ると、DNS設定に応じて実IPまたはfake-ipを返します。
  3. 接続にルールを適用:ドメイン名、宛先IP、プロセスなどの情報をもとにルールを照合し、直結またはプロキシのポリシーを選びます。

nameserver・default-nameserver・fallbackの役割

nameserverは通常のドメイン名解決に使う上流DNSサーバーの一覧です。default-nameserverは主に、DNS上流サーバー自身のホスト名を解決します。たとえば上流にhttps://dns.alidns.com/dns-queryを指定すると、暗号化接続を確立する前に、dns.alidns.comのIPアドレスを調べる必要があります。この処理はブートストラップ名前解決と呼ばれます。

項目用途誤解しやすい点
enableコアのDNS機能を有効にする。有効にしても、システムのクエリをコアに取り込む設定は別途必要。
listenDNSの待ち受けアドレスとポートを指定する。HTTPプロキシやSOCKSプロキシのポートではない。
default-nameserverホスト名で指定したDNS上流のブートストラップ名前解決を行う。すべての通常クエリに使うデフォルトの優先DNS一覧ではない。
nameserver通常のDNSクエリを処理する。厳密な優先・予備の順番で切り替わる仕組みではない。
fallback別の名前解決結果を用意し、フィルター条件に応じて応答を選ぶ。プライマリーDNSがタイムアウトしたときだけ使う予備一覧ではない。
fallback-filterどのクエリ、または通常の名前解決結果にfallbackを使うかを決める。広告ブロッカーではなく、Web通信の接続先ノードを決める設定でもない。

よく使われる上流DNSの形式には、通常のDNSの223.5.5.5、DoTのtls://1.1.1.1:853、DoHのhttps://dns.google/dns-queryがあります。通常のDNSは一般に53番ポート、DoTは853番ポート、DoHはHTTPSの443番ポートを使います。ポートに接続できても、名前解決が成功するとは限りません。応答内容とログも確認してください。

暗号化DNSが保護するのは、クライアントからDNSサービスまでの通信です。上流DNSの信頼性を自動的に保証するわけではなく、すべてのドメイン情報を隠せるわけでもありません。また、DNSクエリがプロキシノード経由になったことを意味するものでもありません。まず現在のネットワークから上流DNSに接続できることを確認し、そのうえで上流への接続をルールに応じてプロキシ経由にする必要があるか検討してください。

fake-ipとredir-host:互換性に応じて選ぶ

fake-ipでは、アプリにコアが管理する仮想IPアドレスを返し、そのアドレスとドメイン名の対応を保存します。アプリがそのアドレスに接続すると、コアは宛先のドメイン名を復元してからルールを照合できます。よく使われるアドレス範囲は198.18.0.1/16です。これはベンチマーク用のアドレス範囲であり、Webサイトの実サーバーのIPアドレスではありません。

redir-hostでは、名前解決した実IPをアプリに返し、記録済みの名前解決情報をできる限りドメイン名の判定に利用します。アプリが独自の暗号化DNSを使う場合や、接続情報にIPアドレスしか含まれない場合、コアが元のドメイン名を正確に取得できるとは限りません。ドメイン名のスニッフィングで情報を補える場合もありますが、すべてのプロトコルに対応できるわけではありません。

  • まずはfake-ipを試す:ドメイン名に基づくルール振り分けを安定して使いたい、通信を正しく取り込めているデスクトップ環境に適しています。
  • 特定のドメインだけ例外にする:LAN機器の検出、実IPを必要とするプログラム、疎通確認に問題がある場合は、まずfake-ip-filterを調整します。
  • 次にredir-hostを検討する:業務アプリが仮想IPに対応できない状態が続く場合は、ほかのDNS上流を一度に変更せず、モードを切り替えて比較テストします。

トラブルシューティングでは、fake-ipに対するpingの結果だけで、接続先のWebサイトが正常かどうかを判断しないでください。仮想IPはドメインとの対応付けと通信の取り込みに使われます。確認すべきなのは、アプリが接続を確立できるか、クライアントの接続詳細で認識されたドメイン名と最終的なポリシーが正しいかどうかです。

仕組みを把握しやすいDNS設定例

以下の設定例では、ローカルDNSを有効にし、fake-ipと2種類のDNS上流の組み合わせを示します。待ち受け先は127.0.0.1:1053で、ローカルマシンからのみアクセスできます。意図せず端末をLAN向けDNSサーバーとして公開するのを防ぐためです。1053はシステムのデフォルトDNSポートではありません。設定に追加しただけでは、OSから自動的にこのポートへクエリは送られません。

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:
    - localhost
    - "*.lan"
    - "*.local"
    - "+.msftconnecttest.com"
    - "+.msftncsi.com"
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
  fallback:
    - https://dns.google/dns-query
    - https://cloudflare-dns.com/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 0.0.0.0/32
      - 240.0.0.0/4

設定を適用する前に確認する3項目

  1. 既存のdnsセクションに統合:同じYAMLファイルにトップレベルのdns:を2つ書かないでください。同名のキーが上書きされたり、構文エラーになったりする可能性があります。インデントにはスペースを使い、Tabは使わないでください。
  2. 上流DNSへの接続を確認:現在のネットワークからGoogleやCloudflareのDoHに接続できない場合、このfallback設定でネットワークが自動的に直ることはありません。まず実際に到達できる信頼性の高い上流DNSに変更するか、DNS上流への接続経路をプロキシ経由に設定してください。
  3. IPv6設定の範囲を理解:ここでのdns.ipv6: falseは、このDNSサービスがAAAAレコードを返さないようにする設定です。OSのIPv6を無効にするものではなく、アプリのIPv6通信が迂回するのを単独で防ぐこともできません。

*.localをフィルターに追加しても、機器検出の通信を取り込めるわけではありません。一般的なmDNSはUDP 5353とマルチキャストアドレスを使い、通常のユニキャストDNSとは異なります。プリンター、画面共有機器、NASが見つからない場合は、TUNのLANルーティング、OSのファイアウォール、マルチキャスト処理も確認してください。

fallback-filterによる名前解決結果の判定方法

上記の設定では、geoip: trueとgeoip-code: CNにより、通常の名前解決結果が指定地域の判定に一致しない場合にfallbackの結果を使います。ipcidrでは、0.0.0.0/32のように、除外対象のアドレス範囲を追加できます。この判定はIPジオロケーションデータベースに依存するため、すべてのCDNアドレスを正しく分類できるとは限りません。

重要なのは、CN以外のIPアドレスがDNS汚染を意味するわけではないという点です。正規のWebサイトでも、ほかの地域にサーバーを配置している場合があります。これはネットワーク環境に応じて応答を選ぶための仕組みであり、応答の正しさを絶対的に証明するものではありません。正規のIPアドレスが返されているのに接続が遅い場合は、フィルター対象の範囲をむやみに広げず、出口ルールやCDNの振り分けを確認してください。

特定のドメインに別のDNS上流を指定する

mihomoはnameserver-policyにも対応しています。特定の種類のドメインに決まったDNSを使わせたい場合は、fallbackの条件を増やし続けるより、ポリシーを直接設定するほうが明快です。以下の部分設定では、example.comとそのサブドメインに指定したDoHを使い、それ以外のクエリには通常の設定を適用します。

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

この例ではポリシーの書き方だけを示しています。既存のdnsセクションに統合してください。社内ドメインを使う場合は、会社から指定されたDNSアドレスを設定し、VPNまたは専用線経由で接続できることを確認します。公共DNSを次々に変更しても、社内ネットワークだけで使えるプライベートレコードは名前解決できません。

DNS上流をプロキシ経由にする場合の循環依存を防ぐ

mihomoのrespect-rulesを使うと、DNS上流への接続にルーティングルールを適用できます。ただし有効にする場合は、プロキシノードのホスト名を解決できるようproxy-server-nameserverも適切に設定する必要があります。設定を誤ると、「DNSにはノード経由の接続が必要だが、ノードのドメイン名解決にはDNSが必要」という依存の循環が起こることがあります。基本設定が正常に動くまでは、これらの設定をまとめて有効にしないでください。

TUNのDNSハイジャック:システムのクエリを確実にコアへ渡す

システムプロキシだけを有効にした場合、通常はプロキシ設定に対応するアプリのHTTPまたはSOCKS接続がコアに渡されます。一方、OSのDNSクエリはルーターや通信事業者のDNSサーバーに送られることがあります。TUNは仮想ネットワークアダプターを使って、より多くのIP通信を取り込みます。また、捕捉したDNSクエリをコアのDNSサービスに渡すこともできます。

クライアントのサービスモードや必要な権限を準備してから、以下のmihomo部分設定を参考にしてください。デスクトップクライアントではTUN関連の項目を独自に管理することがよくあります。画面側ですでに同じ設定が生成されている場合は、最終的に適用される設定を確認し、画面のスイッチと手動のオーバーライドが互いに上書きしないようにしてください。

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クエリに対応します。どちらも通信が取り込み経路に入っている場合に適用されます。
  • auto-routeは関連するルートを自動設定します。ほかのVPN、仮想マシンのネットワーク、企業向けセキュリティソフトに影響することがあるため、個別にテストしてください。
  • auto-detect-interfaceは出口ネットワークアダプターの自動検出を試みます。複数のネットワークアダプター、テザリング、複雑なVPN環境では、出口を明示的に指定する必要がある場合があります。

TUNを使わず、OSから直接ローカルDNSを利用する場合は、通常、ローカルマシンの53番ポートでサービスを待ち受けさせ、OSのDNSをそのアドレスに向ける必要があります。ポートの競合、管理者権限、OSの名前解決サービスとの競合が関係するため、例の1053を、IPアドレスしか入力できないOSのDNS設定欄にそのまま指定することはできません。

順番に確認する:名前解決の失敗、fake-ipが効かない、DNS漏えい

手順1:コアの待ち受けポートに直接クエリする

digがインストールされたLinuxまたはmacOS環境で、まず以下のコマンドを実行します。Windowsでも同ツールが使えるターミナル環境で同様にテストできます。通常のnslookupがデフォルトの53番ポートを使うテストを、1053番ポートの確認と取り違えないでください。

dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp

fake-ipモードでは、フィルターリストに該当しないドメインに対して、通常は198.18.0.0/16の範囲内のマッピング用アドレスが返されます。タイムアウトする場合は、まずDNS機能が有効か、ポートが使用中でないか、設定が読み込まれているかを確認してください。fake-ipが返っても、ローカルのマッピング処理が正常だと確認できるだけで、実際の上流DNSやWebサイトへの接続まで正常とは限りません。

手順2:OSとアプリが同じ経路を使っているか確認する

  1. 設定を再読み込みし、ログに未対応の項目、YAMLのインデントエラー、ポートのバインドエラーがないことを確認します。
  2. TUNを有効にし、ブラウザーでテスト用ドメインにアクセスします。クライアントの接続詳細で、ドメイン名、適用されたルール、出口ポリシーを確認してください。
  3. ブラウザーのセキュアDNSを一時的にオフにして、症状を比較します。オフにすると解決する場合は、fallbackだけを変更するのではなく、ブラウザーのDoH経路を確認してください。
  4. ほかのVPN、手動設定したDNS、アプリ独自のプロキシを1つずつ無効にし、通信の取り込み経路が複数同時に動作していないか確認します。

手順3:キャッシュを消去して再テストする

Windowsではipconfig /flushdnsを実行します。systemd-resolvedを使うLinuxではsudo resolvectl flush-cachesを実行できます。macOSでは一般に以下のコマンドを使います。OS、ブラウザー、コアのfake-ipマッピングはそれぞれ別のキャッシュです。必要に応じてテスト対象のアプリを再起動するか、クライアントにDNSキャッシュの消去機能があれば利用してください。

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

fake-ipからredir-hostに切り替える際は、アプリに古い仮想IPアドレスが残らないよう注意してください。コアのマッピングを消去しても、ブラウザーが以前のfake-ipをキャッシュしていると、一時的に接続に失敗することがあります。ルールをさらに変更するより、ブラウザーを再起動して試すほうが適切です。

手順4:「DNS漏えいテスト」は手がかりとして使う

DNSテストページに表示されるのは、多くの場合、再帰DNSサーバーの出口であり、ローカル端末やプロキシノードのIPアドレスとは限りません。DNSサービスの所在地とノードの所在地が異なっていても、それだけでクエリがプロキシを迂回した証拠にはなりません。まず、通信事業者への平文クエリを防ぎたいのか、アプリの名前解決経路を統一したいのか、特定の上流DNSをプロキシ経由にしたいのかを明確にします。そのうえでログや接続履歴を確認し、必要に応じてパケットキャプチャで判断してください。

DNS設定のまとめ:まず動作させてから、ポリシーを1つずつ追加する

安定した構成の出発点は、接続可能なDNS上流、明確な名前解決モード、そして実際に有効な通信の取り込みです。まずローカルポートへのクエリでDNSサービスを確認し、次にアプリからアクセスしてルールと出口を検証します。具体的な問題を確認してから、fake-ip-filter、nameserver-policy、DNS上流へのプロキシ設定を追加してください。

  • LAN内のドメインだけ解決できない:公共DNSをすぐに変更せず、社内DNS、mDNS、ルーティングを確認する。
  • 特定のアプリだけ失敗する:アプリ独自のDoH、プロキシ設定、fake-ipとの互換性を確認する。
  • すべてのドメインがタイムアウトする:DNSサービスの待ち受け、上流への接続、名前解決の循環依存を確認する。
  • 名前解決は成功するのにWebサイトが開かない:ノードへの接続、ルールの適用、宛先ポートを確認し、すべての問題をDNSのせいにしない。

変更は一度に1項目だけ行い、変更前後の設定とエラーログを保存してください。効果のあった変更を特定しやすくなり、サブスクリプションの更新、コアのアップデート、ネットワークの切り替え後もすぐに元の状態へ戻せます。