ClashのDNS設定方法:nameserver・fallback・DNS hijackを解説
dnsセクションのenhanced-mode、nameserver、fallback、fallback-filter、dns-hijackを取り上げ、YAML例を交えてDNS汚染対策とルールに応じた名前解決の考え方を解説します。
まずカーネルとDNSリクエストの入口を確認
結論は、まずDNSクエリをClash DNSに通し、その後で上流DNSを選ぶことです。nameserverを変更するだけでは、システムやブラウザー、LAN内の端末からのDNSクエリを自動的にすべて取り込めるわけではありません。Webページが開けても、この設定を経由したとは限りません。システムやブラウザーのキャッシュ、アプリ内蔵の名前解決機能によって迂回されることがあります。
「Clashクライアント」は操作画面を提供するアプリで、YAMLを解釈するのはカーネルです。オリジナルのClash、旧Premiumカーネル、Clash Meta(現mihomo)では、対応する設定項目が完全には一致しません。この記事のサンプルはmihomoカーネルを対象にしています。旧カーネルにproxy-server-nameserverやTUNの設定をそのまま適用しないでください。まずクライアントの「バージョン情報」または起動ログでカーネル名とバージョンを確認し、対応するカーネルで設定を検証しましょう。
- 現在の設定をバックアップし、元の
dns、tunとクライアント側のDNS上書き設定を記録します。 - 「設定」で実際に有効になっている設定ファイルを確認します。サブスクリプションの上書き機能がある場合は、次回更新で置き換わる一時ファイルではなく、保存される上書き設定を編集してください。
- 実行中の設定またはエクスポートした統合設定を確認し、画面上のDNS設定がYAMLを上書きしていないか確認します。
- 一度に変更するのは1グループだけにします。再読み込み後に起動エラーと名前解決ログを確認してから、次の変更に進みましょう。
dns設定:リッスンアドレスと名前解決モードの選び方
| 項目 | 役割 | 設定のポイント |
|---|---|---|
enable | カーネルのDNSサービスを有効化 | trueにしても、クエリの入口を別途設定する必要があります |
listen | DNSクエリを受け付けるリッスンアドレス | ローカルでのテストには127.0.0.1:1053を使用できます |
enhanced-mode | 拡張名前解決モードを選択 | 一般的な値はfake-ipとredir-hostです |
fake-ip-range | 仮想IPv4アドレスのプール | 設定例は198.18.0.1/16です |
default-nameserver | DNS上流のホスト名を名前解決 | IPアドレス形式のリゾルバーを指定し、初期解決の依存関係が循環しないようにします |
nameserver | 標準のDNS上流サーバー群 | プロキシノードの一覧でも、厳密な優先・予備の順序でもありません |
fake-ipで仮想アドレスが返っても、名前解決の失敗ではありません
fake-ipはドメイン名に仮想アドレスを割り当て、ドメイン名とアドレスの対応を保持します。アプリがそのアドレスに接続すると、カーネルはドメイン名を特定してルールを照合できます。クエリの結果が198.18.x.xになるのは通常の動作です。パブリックDNSの実アドレスと直接比較したり、pingが通らないだけで設定失敗と判断したりしないでください。
redir-hostは実際の名前解決結果を使うため、実IPアドレスに依存するアプリとの互換性を得やすい一方、DNS汚染への対策やドメイン情報の保持にはより注意が必要です。どちらのモードでも、通信が必ずプロキシ経由になるわけではありません。名前解決モードはドメイン名とアドレスを扱い、接続先はルールで決まります。
listenの設定はシステムDNSの設定ではない
127.0.0.1:1053は、この端末上で標準とは異なるポートを使うDNSサービスを提供します。多くのOSのDNS設定ではIPアドレスしか指定できず、標準の53番ポートに接続するため、このアドレスとポートをそのまま設定できません。まずクエリコマンドで1053番ポートへの応答を確認し、その後TUNのDNS hijackを設定します。ほかの端末からアクセスさせるために、安易に0.0.0.0:53へ変更しないでください。リッスン範囲が広がるため、ポートの競合やファイアウォール、LAN内のアクセス範囲も確認する必要があります。
nameserver:最小構成で上流DNSを検証
以下はmihomoのdnsセクションの例です。ノード設定一式ではなく、サブスクリプション、プロキシグループ、ルールは含みません。既存の設定に追加する際は、トップレベルのdns:を1つだけ残してください。同じキーを含む2つ目のセクションをファイル末尾に追加しないでください。
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
ここでdefault-nameserverは、dns.alidns.comやdoh.pubなどの上流ホスト名を名前解決するために使います。通常のDNSクエリはnameserverが処理します。DoHはHTTPSを使い、一般的な接続ポートは443番です。ただし、暗号化されていても常に接続できるとは限らず、どのプロキシ出口にも適した結果が得られるとは限りません。
- リストを「1つ目が失敗したら2つ目を使う」設定だと思わないでください。カーネルは複数のDNSサーバーへ同時にクエリを送ったり、内部の選択ロジックを使ったりすることがあります。記載順は、信頼できる優先順位や予備の順番ではありません。
- 上流DNSを一度に何台も指定しないでください。まずは到達可能なサーバーを1~2台に絞ると、障害時にどこでタイムアウトしているか特定しやすくなります。
- IPv6の設定範囲に注意してください。ここでの
dns.ipv6: falseは、DNSのAAAAクエリに空の結果を返す設定です。システムのIPv6を無効にする設定ではなく、アプリが既知のIPv6アドレスへ接続するのを防ぐものでもありません。
プロキシサーバー自体をドメイン名で指定している場合、mihomoのdns.proxy-server-nameserverでノードサーバーのドメイン名を名前解決できます。プロキシ経由でアクセスするWebサイトの名前解決に使う上流DNSではありません。「ノードのドメイン名を解決できない」場合は、この処理が単独で完了するか先に確認し、「プロキシサーバーの名前解決にプロキシ接続が必要」という循環依存を避けましょう。
fallbackとfallback-filter:タイムアウト時の予備設定ではない
fallbackは、名前から誤解されやすい設定です。fallback-filterと組み合わせて名前解決結果の選別に関わるもので、nameserverがタイムアウトしてから有効になるだけの設定ではありません。上流DNSを2グループ設定すると、両方にクエリが送られる場合があります。どの結果が採用されるかは、フィルター条件とカーネルの実装にも左右されます。
以下の設定は既存のdnsセクションに追加し、nameserverと同じ階層に置きます。地域データベースへの依存を避けるためGeoIP判定を無効にし、明示的なドメイン条件と疑わしいアドレスのフィルタリングだけを示しています。
fallback:
- https://cloudflare-dns.com/dns-query
fallback-filter:
geoip: false
ipcidr:
- 0.0.0.0/32
- 127.0.0.0/8
domain:
- '+.google.com'
- '+.github.com'
3種類のフィルター条件の役割
domain:指定したドメインにfallbackの名前解決結果を使います。例の+.github.comは該当ドメインとそのサブドメインに一致します。Webサイトへの通信を自動的にプロキシ経由にする設定ではありません。ipcidr:通常の上流DNSが返したアドレスが指定したネットワーク範囲に一致した場合、fallbackの結果を使います。例では未指定アドレスとループバックアドレスを疑わしい結果として扱います。内部ドメインがループバックアドレスに解決される必要がある場合、このフィルターをそのまま使わないでください。geoipとgeoip-code:GeoIP判定を有効にすると、期待する地域に基づいて通常の上流DNSの結果を置き換えるか判断できます。よく使われる設定はgeoip: true、geoip-code: CNですが、データベースが必要です。海外CDNのアドレスだからといって、必ずDNS汚染とは限りません。
「特定のドメインを決まったDNSサーバーで名前解決したい」場合は、複雑なfallback条件を重ねる前にnameserver-policyを検討しましょう。これは名前解決に使う上流DNSを選ぶ設定です。プロキシの出口は引き続き接続ルールで決まります。
nameserver-policy:
'+.cn':
- https://dns.alidns.com/dns-query
'+.github.com':
- https://cloudflare-dns.com/dns-query
この設定もdnsセクション内に置きます。ポリシーに一致したクエリは指定の上流DNSで処理されるため、fallbackの標準フィルターが適用されると推測しないでください。設定を始めたばかりの段階では、「ポリシーによる振り分け」と「fallbackによるフィルタリング」のどちらか一方で検証し、ログと結果が一致することを確認してから組み合わせましょう。
dns-hijack:TUNで53番ポートのDNSクエリを取り込む
mihomoのdns-hijackはトップレベルのtunセクションに属し、dnsには属しません。TUNに入り、条件に一致したDNS通信をカーネルのDNSモジュールへ渡します。以下の例は既存のTUN設定と併用してください。クライアントの画面でTUNを管理する場合は、画面の設定がYAMLを上書きしていないか、最終的な実行設定を確認します。
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番ポートを補います。TUNを有効にするには通常、システム管理者権限かクライアントのサービスモードが必要です。既存の設定にtun:がある場合は、その中の項目を変更し、同じセクションを重ねて定義しないでください。
any:53を設定しただけでは、次の通信は自動的に取り込まれません
- ブラウザーのDoH:通常はHTTPSの443番ポートを使うため、53番ポートには一致しません。確認中はブラウザーの「セキュアDNS」を一時的に無効にできます。Firefoxでは「設定」→「プライバシーとセキュリティ」→「HTTPS経由のDNS」が一般的な設定場所です。確認後は、必要に応じて元に戻してください。
- AndroidのプライベートDNS:厳格モードでは通常DoTの853番ポートを使います。端末によっては「設定」→「ネットワークとインターネット」→「プライベートDNS」から設定します。メーカーによって項目名や場所が異なる場合があります。通常のUDP 53番ポートの通信として扱うことはできません。
- TUNに入っていない通信:LANへの直接ルート、別のVPN、特殊なネットワークインターフェース、OSの処理経路などが原因で、通信がTUNを迂回することがあります。システムDNSがルーターを指していても、その通信が実際に取り込まれているか確認してください。
リッスンの成功、TUNの有効化、DNS hijackの適用は、それぞれ別の状態です。スマートフォンではVpnServiceの許可や、ほかのVPNとの競合も確認してください。デスクトップではサービス権限、ルーティング、ファイアウォールを確認します。DNSの入口の問題を解決するために、リゾルバーを何度も入れ替えないでください。
検証手順:設定確認、指定先へのクエリ、システムのDNS経路
手順1:YAMLと起動ログを確認
この端末でmihomoを直接実行できる場合は、設定ファイルのあるディレクトリで以下のコマンドを実行します。クライアントを使っている場合は、画面に用意された設定チェック機能も利用できます。コマンドの検証に成功しても、設定を読み込めることが分かるだけで、上流DNSに接続できるとは限りません。
mihomo -t -f config.yaml
不明な項目がある場合は、まずカーネルを確認します。インデントや重複キーに問題がある場合は、設定ファイルを修正してください。ログにaddress already in useと表示されたら、1053番ポートを使用しているプロセスを調べるか、テスト用ポートを変更します。上流URLを変えても、リッスンポートの競合は解決しません。
手順2:ローカルの1053番ポートにクエリを送る
digをインストールしたmacOSまたはLinuxでは、以下の3つのコマンドを実行できます。1つ目はUDP、2つ目はTCPでのクエリ、3つ目はAAAAレコードの応答を確認します。
dig @127.0.0.1 -p 1053 www.example.com A
dig @127.0.0.1 -p 1053 www.example.com A +tcp
dig @127.0.0.1 -p 1053 www.example.com AAAA
Windowsのnslookupは、対話モードに入ってからテスト用ポートを指定できます。テストが終わったらexitで終了します。
nslookup
server 127.0.0.1
set port=1053
set type=A
www.example.com
exit
fake-ipモードでAレコードに仮想アドレスが返るのは正常です。実際の上流DNSの結果を確認するには、設定をバックアップしてから一時的にredir-hostへ切り替え、再読み込みして関連キャッシュを消去したうえで比較してください。テスト後は元の設定に戻します。fake-ipの応答時間を、実際の上流DNSへの通信遅延とみなさないでください。
手順3:システムの標準DNS経路を確認
ローカルからのクエリが成功することを確認してからTUNを有効にし、システムの標準リゾルバーでクエリしながらクライアントのログを確認します。Windowsではipconfig /flushdnsでシステムのDNSキャッシュを消去できます。systemd-resolvedを使うLinuxではresolvectl flush-cachesを実行します。ブラウザーにも独自のキャッシュや接続が残る場合があるため、再起動するか、別途キャッシュを消去してください。
| 症状 | まず確認する項目 | 次の対応 |
|---|---|---|
| ローカルの1053番ポートへのクエリがタイムアウトする | DNSのリッスン状態、設定の読み込み、上流DNSへの接続 | 起動ログを確認し、上流DNSを1つに絞って再試行 |
| 指定先へのクエリは成功するが、ブラウザーで問題が起きる | セキュアDNS、キャッシュ、システムのDNS経路 | ブラウザーのDoHを一時的に無効にし、標準のクエリ結果と比較 |
| ドメイン名は解決できるが、Webサイトがタイムアウトする | プロキシグループ、接続ルール、接続先ポート | 接続ログでドメイン名、適用ルール、接続先の出口を確認 |
| ノードのドメイン名だけ名前解決に失敗する | ノードの初期解決がプロキシ接続に依存していないか | proxy-server-nameserverとルーティングの依存関係を確認 |
| サブスクリプションの更新後に設定が消える | 設定の統合方法と上書きの優先順位 | クライアントの永続化される上書き設定を使い、実行中の設定を確認 |
日常の設定方針:名前解決の経路を把握しやすくする
普段使いの設定は、「DNSの入口を1つ、到達可能な上流DNSを少数、明確なルールモード」から始めるとよいでしょう。上流DNSを固定したい場合はnameserver-policyを追加し、誤った結果を選別する必要がある場合にfallback-filterを設定します。設定を1層増やすたびに、影響するドメイン、上流DNSへの接続経路、障害時に確認するログを説明できる状態にしておきましょう。
DNSの暗号化はリゾルバーまでのクエリ通信を保護しますが、接続情報をすべて隠すものではありません。DNSリークテストに特定のDNSサービスが表示されても、すべてのアプリの通信経路が分かるわけではありません。想定したDNS経路を迂回していないか調べるには、一度のWebテストだけで判断せず、パケットキャプチャ、名前解決ログ、接続ログを合わせて確認してください。
最後に、3つの役割を整理しましょう。nameserverは問い合わせ先、fallback-filterは採用する名前解決結果の選別、tun.dns-hijackは従来型のDNSクエリをカーネルに取り込む範囲を決めます。この3層を分けて検証すると、「汎用DNS設定」を丸ごと何度も入れ替えるより、問題を早く特定できます。ほかの基本項目はYAMLマニュアルを、接続や起動の問題はトラブルシューティングを参照してください。