ClashのDNS設定を解説:nameserver・fallback・DNS hijackの使い方

ClashのDNS設定を項目別に解説。nameserver、fallback、fallback-filter、dns-hijackの役割と、fake-ipとredir-hostの違い、DNSの不具合を切り分ける手順を紹介します。

まずDNS解決・DNSリクエストの取り込み・プロキシ振り分けを区別する

ClashのDNS設定では、ドメインをどのDNSサーバーで解決するか、アプリのDNSリクエストをどうカーネルに取り込むか、接続を最終的にどの経路へ流すかを、それぞれ考える必要があります。nameserver は上流DNSサーバーを指定し、tun.dns-hijack は条件に合うDNS通信を取り込み、rules はアプリの通信経路を決めます。3つは関連しますが、互いに代用できる設定ではありません。

この記事では、現在mihomoカーネルを使うクライアントを主な対象とします。旧版Clashや各種フォーク、クライアントの設定生成機能では、利用できる項目が異なる場合があります。また、画面上の「DNS上書き」によって、サブスクリプション内のdnsセクション全体が置き換わることもあります。トラブル時はサブスクリプションの編集画面だけでなく、クライアントが生成してカーネルに渡す実際の設定を確認してください。

  • カーネルDNS:dns.enableを有効にすると、カーネルがこのセクションの設定に従ってDNS解決を行います。
  • システムDNS:OSが現在使用している名前解決の窓口です。HTTPシステムプロキシを有効にしても、すべてのDNSリクエストがカーネルに送られるとは限りません。
  • プロキシルール:ドメインやIPアドレスに適用されるルールによって、直接接続かプロキシ経由かが決まります。特定地域のDNSを使うことと、その地域のプロキシノードを選ぶことは別です。
  • アプリ内蔵DNS:ブラウザーのセキュアDNSやアプリ内蔵のDoHは、OSの従来型DNS設定を経由しない場合があります。

ここでいう「DNS hijack」は、指定したDNS通信をローカルのカーネルへリダイレクトすることを指します。通信事業者がDNS応答を書き換えることとは異なります。取り込みに成功したかは、DNSクエリと接続ログで確認してください。

nameserverとdefault-nameserver:通常の名前解決とDNSサーバーの名前解決

まず単独でテストできるDNS待ち受け口を用意する

以下は既存のmihomo設定に追加するDNSセクションの例です。プロキシノードやルールを含む完全な設定ではありません。待ち受け先をローカルに限定し、ポートには1053を指定して、システムが使う53番ポートとの競合を避けています。この段階ではシステムは自動的にこの待ち受け口を使いません。後ほど明示的なクエリで動作を確認します。

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

nameserverは通常のドメイン問い合わせに使う上流DNSサーバーのリストです。従来型DNSやDoH(DNS over HTTPS)、カーネルが対応するほかのプロトコルを指定できます。アドレスを2つ並べても、厳密な「優先・予備」の順序を宣言したことにはなりません。障害時の切り替えをリストの順番に依存させないでください。

default-nameserverは主に、上流DNSサーバー自体のホスト名を解決するために使います。たとえばhttps://dns.alidns.com/dns-queryへ接続するには、先にdns.alidns.comのIPアドレスを知る必要があります。IPアドレスでブートストラップ用DNSサーバーを明示すれば、「DNSサーバーのホスト名を解決するために、そのDNSサーバーが必要」という依存関係のループを避けられます。

ノードのホスト名解決とDNSの送信経路は分けて確認する

mihomoのproxy-server-nameserverは、プロキシノードのサーバーホスト名を解決するために使えます。ノードのアドレス自体を解決できなければ、アプリのドメインを正常に解決できてもプロキシ接続は確立できません。DNS上流への接続にルーティングルールを適用するrespect-rulesを有効にする場合は、ノードの名前解決経路も適切に設定してください。DNSサーバーがプロキシに依存し、プロキシも同じDNSサーバーに依存する状態を避ける必要があります。

トラブルの切り分け中に、高度な設定を一度にすべて追加しないでください。まず、選んだDoHサーバーへ現在のネットワークから接続できることを確認し、その後でルールに従った送信などを追加します。DoHは通常TCPの443番ポートを使いますが、HTTPSだからといって自動的にプロキシ経由になるわけではありません。実際の経路はカーネル設定とルーティング条件で決まります。

fallbackとfallback-filter:タイムアウト時の予備ではなく、応答の振り分け

fallbackは、プライマリDNSがタイムアウトした場合だけ使う予備リストだと誤解されがちです。実際にはカーネルがnameserverとfallbackの両方に問い合わせ、fallback-filterの条件に基づいて採用する応答を判断します。プロキシノードの予備グループではなく、特定のドメインをプロキシ経由にする機能でもありません。

以下は条件を明示して絞り込む例です。前述のdnsセクションに統合してください。同じ名前のトップレベルセクションをファイル内に重複して記述してはいけません。例ではGeoIP判定を無効にし、ドキュメント用のテストネットワークと指定ドメインを使って判定方法を示します。記載したネットワークは、異常なアドレスを網羅した一覧ではありません。

  fallback:
    - https://cloudflare-dns.com/dns-query
  fallback-filter:
    geoip: false
    ipcidr:
      - 0.0.0.0/8
      - 192.0.2.0/24
      - 198.51.100.0/24
      - 203.0.113.0/24
    domain:
      - '+.github.com'
項目判定対象設定の意味
geoip通常の名前解決で返されたIPアドレスの地域GeoIP判定を有効にします。利用可能な地理情報データが必要です。
geoip-codeGeoIPの国・地域コードGeoIP判定が有効な場合、通常の応答が指定地域の条件に合わなければ、fallbackの応答が使われます。
ipcidr通常の名前解決で返されたIPアドレス指定したIPアドレス範囲に該当すると、fallbackの応答が使われます。
domain問い合わせたドメイン一致したドメインにはfallback側の応答が直接使われます。

geoip: trueとgeoip-code: CNを設定しても、「中国のサイトは直接接続する」という意味にはなりません。解決されたIPアドレスの地理情報を基に、応答を採用するか判定します。CDNのアドレス、地理情報データの更新状況、ネットワークの出口によって判定結果が変わることがあります。プロキシ経由かどうかは引き続きルールで決まります。特定のドメインに固定のDNSサーバーを使いたい場合は、地理条件を重ねるよりnameserver-policyを使うほうが分かりやすいでしょう。

fallback側のDNSサーバーにも接続できる必要があります。現在のネットワークから上流サーバーへ接続できない状態で、特定のドメインにfallbackを強制すると、障害の範囲が広がるだけです。フィルターを有効にする前に、上流サーバーへ単独で接続できることを確認してください。

fake-ipとredir-host:仮想IPを返すか、実IPを返すか

fake-ipはIPアドレスとの対応付けでドメイン情報を保持する

fake-ipモードでは、カーネルがアプリに198.18.0.0/16の範囲にある仮想IPv4アドレスを返し、ドメインと仮想アドレスの対応を保存します。アプリがそのアドレスへ接続すると、通信が同じカーネルに再び届く必要があります。カーネルはそこでドメイン名を復元し、ルールを照合して実際の接続を確立します。このアドレス範囲はネットワーク試験用に予約されており、WebサイトのグローバルIPではありません。

そのため、問い合わせ結果が198.18.x.xでも、それだけでDNS汚染とは判断できません。確認すべきなのは、DNSの問い合わせはカーネルに届いているのに接続が通常のルートから出ていないか、クライアントを切り替えたり対応表を消去した後もOSが古い仮想アドレスをキャッシュしていないかです。DNSだけを取り込み、後続の接続を取り込まないことは、fake-ipで通信できないよくある原因です。

redir-hostは実IPを返すが、接続の取り込みは別途必要

redir-hostモードでは通常、上流DNSが返した実IPアドレスをアプリに返すため、アプリが仮想アドレスへ接続する必要はありません。実IPアドレスを必要とする一部のプログラムでは互換性を得やすい一方、ドメインと接続の対応付けはキャッシュや共有IPの影響を受けます。また、このモード名はLinuxのREDIRECTファイアウォールルールが必須という意味でも、透過プロキシが自動で設定されるという意味でもありません。

  • TUNを使い、ドメインルールとの照合に必要な情報を保ちたい場合は、まずfake-ipを試してください。
  • LAN内のデバイス検出、特定の機器、ゲームで互換性の問題が起きた場合は、まず該当するドメインを特定し、その後でfake-ip-filterの利用を検討してください。
  • デフォルトのblacklistフィルターモードでは、fake-ip-filterに追加したドメインには仮想アドレスが割り当てられません。ほかのフィルターモードの意味は、利用中のmihomo設定で確認してください。
  • 拡張モードを切り替えたら、影響を受けるアプリを再起動してDNSキャッシュを消去し、2つのモードの古い結果が混在しないようにしてください。

dns.ipv6: falseは、カーネルDNSによるAAAA問い合わせの処理を制御します。システム上のすべてのIPv6接続を無効にする設定ではありません。ブラウザーが独自のDoHを使っていたり、アプリがIPv6アドレスをキャッシュしていたりすると、別の経路で接続する可能性があります。

tun.dns-hijack:53番ポートのDNSを取り込む範囲

dns-hijackはdnsセクションではなく、tunセクションに記述します。以下はmihomoでよく使われるTUN設定例です。ルーティングが変更されるため、リモートサーバーで操作する場合は、コンソールなど復旧手段を用意してください。デスクトップクライアントでは、通常サービスモードや権限ヘルパーを使ってTUN権限を管理します。権限の出所が不明なまま、2つ目のカーネルを起動しないでください。

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番ポートを補います。ネットワーク全体をスキャンしたり遮断したりする設定ではありません。カーネルが処理するには、まず通信がTUNを通る必要があります。ルートの除外設定、OSの動作、ローカルのループバック名前解決サービスなどにより、一部のリクエストがこの経路に入らないことがあります。

  • DoH:通常はHTTPSの443番ポートを使います。any:53を設定しても、カーネルDNS問い合わせとして扱われるわけではありません。
  • DoT:通常はTLSの853番ポートを使うため、従来型DNSの53番ポートを取り込む設定の対象外です。
  • Ubuntuのローカル名前解決:127.0.0.53はsystemd-resolvedのローカルスタブアドレスとして使われることがあります。このアドレスが表示されても、DNSが取り込まれていないとは限りません。
  • LAN内のデバイス:ローカルPCでTUNを有効にしても、ルーターやほかのデバイスのDNSが自動的に取り込まれるわけではありません。ゲートウェイとして運用するには、転送とファイアウォールを別途設計する必要があります。

ローカルPCのDNS問題を解決するために、待ち受けアドレスを0.0.0.0:53へ変更してインターネットに公開しないでください。LAN内にDNSサービスを提供する場合は、接続を許可するネットワークを限定し、UDPとTCPそれぞれのファイアウォールルールを確認してください。

Ubuntuでの確認手順:待ち受け・問い合わせ・取り込み・接続経路

手順1:実際の設定と待ち受けプロセスを確認する

コマンドラインで運用している場合は、実際の設定ディレクトリを指定してテストできます。以下では/etc/mihomo/config.yamlを例にしています。デスクトップクライアントを使う場合は、クライアントが提供する実行時設定を確認してください。このパスを実際の設定ディレクトリの代わりに使わないでください。

mihomo -t -d /etc/mihomo -f /etc/mihomo/config.yaml
sudo ss -lntup 'sport = :1053'
resolvectl status

設定テストで分かるのは、主に構文や設定の問題です。上流ネットワークへ接続できることまでは確認できません。ssで1053番ポートを正しいプロセスが待ち受けているか確認します。アドレスの競合が見つかった場合は、別のDNSサービスを特定してください。システムの名前解決サービスを安易に停止しないでください。

手順2:システムDNSを経由せず、カーネルに直接問い合わせる

Ubuntuのdigはdnsutilsパッケージに含まれています。まず接続先アドレスを明示して問い合わせ、「カーネルDNS自体が失敗している」のか「システムのリクエストがカーネルに届いていない」のかを切り分けます。

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

応答ステータス、回答レコード、タイムアウトの有無を確認してください。fake-ipモードでは、Aレコードの問い合わせに成功しても、カーネルが仮想アドレスを割り当てられたことしか分からず、実際の上流DNSで名前解決できた証明にはなりません。実際にアクセスし、ログも確認してください。dns.ipv6: falseの場合、AAAAの応答にアドレスがなくても必ずしも障害ではありません。

手順3:システムの入口とアプリの接続を確認する

resolvectl query example.com
curl -I --connect-timeout 10 https://example.com
curl -I --connect-timeout 10 --proxy http://127.0.0.1:7890 https://example.com

最後のコマンドは、既存設定のmixed-portが7890で、明示的にHTTPプロキシを指定してHTTPSトンネルを確立できることを前提としています。これだけでは、システムDNSが取り込まれているとは証明できません。2つ目のコマンドは環境変数のプロキシ設定にも影響されるため、結果を比較する前にターミナルの環境を確認してください。明示的なプロキシ経由ならアクセスできるのに通常のアプリでは失敗する場合は、システムプロキシの適用範囲、TUNのルーティング、アプリ内蔵DNSを重点的に確認します。

手順4:キャッシュを消去し、設定を一つずつ戻す

sudo resolvectl flush-caches

systemd-resolvedのキャッシュを消去した後、ブラウザーを終了して再起動してください。ブラウザー独自のDNSキャッシュや既存の接続プールは、システムのキャッシュを消去しても残ることがあります。短時間だけカーネルのログレベルを上げ、DNSのタイムアウト、ノードのホスト名解決の失敗、ルールの一致状況を確認したら、ログレベルを元に戻します。ログにはアクセスしたドメインが含まれる場合があります。共有する前に、サブスクリプションURL、認証情報、個人のアクセス履歴を削除してください。

よくある症状と変更を最小限にするための考え方

症状まず確認する項目次に行うこと
1053番ポートへの明示的な問い合わせがタイムアウトする待ち受けアドレス、ポートの競合、カーネルの起動状態まずssと実行ログを確認し、その後で上流サーバーへの接続を調べます。
198.18で始まるアドレスが返るが、接続できないfake-ip後の通信とアドレスの対応付けTUNのルートを確認し、キャッシュを消去してから再接続します。
特定のドメインだけ失敗するfallback-filter、nameserver-policy、ドメインルール該当ドメインだけに設定した特別なポリシーを一時的に外し、ログを比較します。
ノード一覧に表示されるが、どのノードにも接続できないノードのホスト名解決とノード自体への到達性proxy-server-nameserverとノード接続時のエラーを確認します。
ブラウザーだけ挙動が異なるセキュアDNS、拡張機能のプロキシ設定、ブラウザーのキャッシュ一時的に名前解決の経路を統一し、ブラウザーを再起動して再確認します。
サブスクリプションの更新後に再び問題が起きるクライアントの上書き設定と生成後の設定クライアントがサポートする永続的な上書き機能に変更を追加します。

確実に調整するには、まずDNSの待ち受け口を1つ用意して問い合わせ可能な状態にし、次に上流DNSサーバーへ接続できることを確認します。その後、システムのリクエストとアプリの通信がカーネルに届くかを確かめ、最後にfallback、ドメイン別のDNSポリシー、TUNによるDNS取り込みを追加します。1回の変更で変える項目は1つに絞り、変更前後の問い合わせ結果を記録してください。こうすれば、すべての問題を「DNS汚染」と決めつけず、名前解決・ルーティング・ノードのどこに原因があるか切り分けられます。

ポート、プロキシグループ、ルールの関係をまとめて知りたい場合は入門ガイドを、設定項目を確認する場合はプロトコルリファレンスをご覧ください。この記事のDNSとTUNの設定例は、既存の設定に統合してください。元のノードとルールを残し、サブスクリプション全体を置き換えないでください。

Clashをダウンロード