まず結論です。Androidでは、DNSリクエストが実際にClashへ届いていることを確認してから、DNSサーバーを調整しましょう。nameserverは通常の名前解決に使う上流DNS、fallbackは結果の選別に使う別の上流DNS群です。「メインのサーバーが落ちたときだけ使うもの」ではありません。fake-ipはアプリに返すアドレスの形式を決め、DNSハイジャックはどのリクエストをコアに取り込むかを決めます。それぞれ役割が異なるため、相互に代用することはできません。

1. AndroidのDNSリクエストがClashに届くまで

アプリでドメインを開くと、通常はまずシステムのリゾルバーにアドレスを問い合わせ、その後に接続を開始します。AndroidクライアントはシステムVPNの許可を得ると、仮想ネットワークインターフェースを通じて通信を受け取れます。ただし、DNSも同時に引き受けるかどうかは、クライアントのVPN実装、DNS設定、アプリごとの通信制御によって異なります。

  1. アプリがシステムの名前解決APIを呼び出し、システムが現在のネットワークに指定されたDNSアドレスへ問い合わせます。
  2. VPNインターフェースが、取り込み対象の通信を受信します。クライアントまたはコアがDNSリクエストを内部リゾルバーに渡します。
  3. 内部リゾルバーがキャッシュやドメインごとのルール、nameserverなどの設定を参照し、必要に応じて上流DNSへ問い合わせます。
  4. コアは実際のIPアドレスまたはFake IPをアプリに返します。アプリがそのアドレスへ接続すると、コアがルールに従って直接接続するか、プロキシノードを使うかを決定します。

つまり、「VPN接続済み」と表示されても、すべてのアプリのDNSがコアに届いているとは限りません。VPNの対象外にしたアプリや、独自の暗号化DNSを有効にしたブラウザーは、別の経路を使うことがあります。問題を切り分ける際は、まずVPN対象外ではないブラウザーで試し、「セキュアDNS」を一時的にオフにしてログを確認しましょう。

DNSハイジャックが主に対象とするのは通常のポート53

一般的なDNSハイジャックは、UDPまたはTCPの53番ポートへのリクエストを対象にします。Androidの「プライベートDNS」を厳格モードで使う場合は、通常DNS over TLSの853番ポートを使います。ブラウザー内蔵のDNS over HTTPSは通常443番ポートを使うため、通常のポート53向けハイジャックルールだけでは、これらをコアのDNS問い合わせに切り替えられません。

「プライベートDNS」の設定場所はAndroidのバージョンによって異なります。一般的には「設定」→「ネットワークとインターネット」→「プライベートDNS」から開けますが、一部の端末では「接続と共有」内にあります。トラブルシューティングでは現在の設定を控えたうえで、厳格モードを一時的にオフにしてVPNを再接続し、動作を確認します。その後、必要に応じて設定を戻してください。すべての端末でオフにする必要があるわけではありません。

2. dns各項目の役割

項目役割と設定のポイント
enableコアのDNS機能を有効にします。クライアントが実行時設定で、サブスクリプション内の値を上書きする場合があります。
listenコアDNSの待ち受けアドレスです。HTTPプロキシのポートとは別物で、システムDNSを引き受けたことを意味するものでもありません。
default-nameserver主にDNS上流サーバー自身のドメイン名を解決し、起動時に必要な名前解決を行います。
nameserver通常のドメイン検索に使う上流サーバーの一覧です。より詳細なドメインルールが優先される場合もあります。
fallback予備の名前解決結果を取得するサーバー群です。フィルター条件と組み合わせて結果を選ぶもので、順番に再試行するリストではありません。
fallback-filterメインの名前解決結果が特定のアドレス範囲に該当する場合など、fallbackの結果を使う条件を指定します。
enhanced-modefake-ipまたはredir-hostを選び、返すアドレスとドメインの関連付け方法を変更します。
ipv6コアがAAAAレコードの問い合わせをどう処理するかを設定します。端末のIPv6通信全体を無効にする設定ではありません。

default-nameserverは「すべてのサイトの標準DNS」ではない

たとえば上流にhttps://dns.alidns.com/dns-queryを指定した場合、このHTTPSサービスに接続するには、まずdns.alidns.comのアドレスを知る必要があります。この最初の名前解決を担うのがブートストラップ用のDNSサーバーです。IPアドレスで指定すれば、「DNSサーバーの名前を解決するために、同じDNSサーバーへ先に接続しなければならない」という循環を避けられます。

従来の設定では、default-nameserverに通常のIPアドレスを指定することが一般的です。この項目で使えるプロトコルはコアによって異なるため、古い設定を移行するときは、まずシンプルな書き方を維持してください。上流サーバーのドメイン名を解決できない問題を、すべてのプロキシノードが同時に使えなくなったと誤認しないようにしましょう。

listenに7890を指定しない

7890はHTTPプロキシや混合ポートによく使われますが、DNSの待ち受けポートとは別のサービスです。以下の例では、特別な権限が必要な低いポートへのバインドを避けるため、ローカルDNSを127.0.0.1:1053で待ち受けます。Androidクライアントが内部ポートを独自に設定する場合や、この待ち受け先を使わない場合もあるため、実行時設定を確認してください。listenを指定するだけでは、AndroidからDNS問い合わせが自動的に送られることはありません。

3. nameserverとfallbackの基本設定

以下は各項目の関係を理解するための設定例で、すべてのサブスクリプションに適用できる完全な設定ではありません。通常のDoH上流とfallback用のDoH上流を1つずつ指定し、GeoIPフィルターを無効にして、明示した予約アドレス範囲で絞り込みの仕組みを示しています。どちらのHTTPSサービスも、現在のネットワークやルーティング条件で到達できる必要があります。

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
  fallback:
    - https://1.1.1.1/dns-query
  fallback-filter:
    geoip: false
    ipcidr:
      - 240.0.0.0/4
  • 198.18.0.1/16はFake IP用のアドレスプールです。ドメイン名と仮想アドレスの対応付けに使うもので、プロキシノードのアドレスを指定する場所ではありません。
  • ここでは240.0.0.0/4を異常な応答を絞り込む例として使っています。異常アドレスを網羅した一覧ではなく、あらゆる誤った名前解決を検出できるわけでもありません。
  • geoip: falseは、GeoIPの条件でfallbackを選ばない設定です。今回のテストでは、地域データベースの違いが影響しないようにしています。
  • ipv6: falseは、まず問題の切り分け範囲を狭めるための設定です。IPv6を使う場合は、ノード、ネットワーク、通信の取り込み経路がすべて対応していることを確認してから、個別に有効化して検証してください。

上流サーバーは多ければよいというものではありません。サーバーを増やすと問い合わせ量が増え、返される結果が異なることもあります。まずは到達可能で動作を把握しやすい上流サーバーだけで基準を作り、その後にドメインルールやfallbackを追加しましょう。暗号化DNSが保護するのは端末とDNSサービス間の問い合わせ通信であり、その後のウェブサイトへの接続が自動的にプロキシ経由になるわけではありません。

4. fallback-filterが採用する結果を決める仕組み

従来のClashで一般的な実装では、fallbackを設定すると2つの上流へ同時に問い合わせる場合があります。コアはフィルター条件に基づいて採用する応答を決めます。nameserverが完全にタイムアウトするまで待ってからfallbackへ問い合わせるわけではありません。ただし、並行処理、キャッシュ、エラー処理の具体的な挙動は、使用中のコアで確認してください。

よく使われる3つのフィルター条件

  • GeoIP:従来の設定では、geoip: trueとgeoip-code: CNを組み合わせ、メインの名前解決結果のIPアドレスの地域情報を選択基準にすることがあります。判定基準はGeoIPデータベースに記録されたIPアドレスの地域情報であり、データベースのバージョンによって結果が変わる場合があります。
  • IPアドレス範囲:ipcidrは、メインの名前解決結果に含まれる特定のアドレス範囲を判定します。上の例で指定した予約アドレス範囲に一致した場合は、fallbackの結果を使います。
  • ドメイン:domainを使うと、一致したドメインにfallbackの結果を適用できます。具体的なマッチ構文はコアのドキュメントで確認してください。プロキシルールの構文をそのままリストに貼り付けることはできません。

GeoIPフィルターを有効にすると、海外CDNのアドレスを使う正常なサイトでもfallbackが選ばれる場合があります。これはフィルター条件によるもので、メインの名前解決が妨害された証拠にはなりません。反対に、異常な応答が一見正常なアドレス範囲に含まれることもあります。fallback-filterを、あらゆる名前解決の正当性を自動判定するセキュリティ機能と考えないでください。

mihomoのドメイン別DNS設定とノードの名前解決

mihomoには、指定ドメインごとにリゾルバーを選べるnameserver-policyと、プロキシノードのサーバードメイン専用のproxy-server-nameserverがあります。後者を使うと、「ノード自体のアドレス解決」と「ユーザーがアクセスするサイトの名前解決」を分けて調べられます。これらの拡張項目を従来のClashコアにそのまま設定しないでください。

# mihomoのdnsセクション内で使う項目の例
nameserver-policy:
  '+.example.com':
    - https://dns.alidns.com/dns-query
proxy-server-nameserver:
  - https://dns.alidns.com/dns-query

ここでのexample.comは構文を示すためのドメインで、実際のサイトに自動で適用されるわけではありません。ドメインごとに上流を指定する場合は、対象のドメインを入力し、クライアントがその項目を保持しているか確認してください。ルール、fallback、ノードの名前解決を同時に変更すると、結果が変わった原因を特定しにくくなります。

5. fake-ipとredir-hostの選び方

比較項目fake-ipredir-host
アプリが受け取るアドレスコアのアドレスプール内にある仮想IP上流DNSから返される実IP
ドメインとの関連付け仮想IPとの対応付けによってドメイン情報を保持DNS応答などの情報からドメインと実IPを関連付け
よくある注意点実際のDNSアドレスを必要とするアプリでは例外設定が必要な場合がある実際の名前解決結果とIPアドレスの関連付けに依存し、キャッシュの影響を受ける場合がある
トラブル時の確認ポイント198.18.x.xが表示されても、必ずしも異常ではない実IPが返されても、接続が正しい経路を通るとは限らない

通常のプロキシ接続では、まずクライアントの初期設定どおりfake-ipを使う方法があります。アプリが仮想アドレスに接続すると、コアは対応するドメインを特定し、ルールに従って実際の接続方法を決めます。アプリへアドレスを返す前に、対象サイトの実IPを毎回取得する必要はありません。ただし、実際の接続先やIPアドレスを使うルール、ルーティングによっては名前解決が必要です。

画面ミラーリング、LAN内のデバイス検出、特定のアプリだけで問題が起きる場合は、fake-ip-filterを使い、特定のドメインにFake IPを返さない設定を検討できます。まず対象ドメインを特定し、必要最小限の例外を追加してください。最初からすべてのドメインを除外しないようにしましょう。除外モードやマッチ機能はバージョンによって異なるため、項目を追加した後は設定読み込みログを確認してください。

redir-hostに切り替えても、アプリに古いDNSキャッシュや接続キャッシュが残っていることがあります。プロキシサービスを停止して再起動し、テストするアプリも完全に終了してから開き直してください。Fake IPに対するpingの結果で、プロキシ経由のサイトが使えるかどうかを判断することはできません。

6. AndroidのDNSハイジャックとTUN設定の違い

オリジナル版Clash for AndroidのVPNによる通信制御は、Androidクライアントとコアが連携して行います。デスクトップ向けのTUN設定をそのままスマートフォンに適用できるわけではありません。まずクライアントの「設定」で、DNSの上書き、ネットワークスタック、アプリごとの通信制御に関する項目を確認してください。派生版によってメニュー名は異なるため、特定の版でのボタンの場所を共通の手順として扱わないようにしましょう。

mihomoのTUN設定に対応したクライアントでは、以下のような項目がよく使われます。DNSハイジャックの対象を示す例であり、AndroidクライアントのVPN設定を置き換える完全な手順ではありません。

tun:
  enable: true
  dns-hijack:
    - any:53
    - tcp://any:53

any:53は一般的なUDP DNSの取り込みに使い、tcp://any:53を追加するとTCP DNSも対象にできます。実際に動作するかどうかは、その通信がTUNに届いているか、クライアントが設定を許可しているか、追加のルーティング除外がないかによって異なります。AndroidクライアントがVPNインターフェースを作成する場合は、クライアントが対応する設定方法を優先してください。この設定例を使うために、別の通信制御設定を重ねて作成しないようにしましょう。

7. 変更後の確認手順とよくある問題

  1. 設定が読み込まれたか確認する。保存後に設定を再読み込みし、YAMLのインデント、未対応の項目、アドレス形式に関するエラーがないか確認します。編集した設定ファイルが選択されていることも確認してください。
  2. 実行時の上書きを確認する。クライアントに「上書き」や「DNS設定」がある場合は、関連するスイッチとサーバー一覧を確認します。サブスクリプションのファイルを編集しても、実行時の設定が変わったとは限りません。
  3. テスト条件をそろえる。ブラウザー、ネットワーク、ノードをそれぞれ1つに絞り、Wi-Fiかモバイルデータかを記録します。まずブラウザー独自のDoHを無効にし、これまで開いたことのないドメインにアクセスしてください。
  4. ログを確認する。一時的に、クライアントが対応するデバッグログレベルに上げ、上流のタイムアウト、TLSエラー、ノードのドメイン解決失敗などを探します。テスト後は通常のログレベルに戻し、ログを共有する前にサブスクリプションURLや認証情報を隠してください。
  5. 一度に変更するのは1項目だけ。「通信の取り込み経路 → 上流への到達性 → モード → fallbackのフィルター」の順に確認します。ネットワークが復旧したら、個別設定を1つずつ戻してください。

ハイジャックを有効にすると、すべてのサイトが開けない

まずDNS上流がタイムアウトしていないか確認してください。上流へプロキシ経由でしか接続できず、さらにプロキシノードのドメイン解決にもその上流が必要な場合、起動時の依存関係が循環することがあります。まず到達可能なブートストラップ用の名前解決経路を確保してください。mihomoでは、ノードのドメイン解決を別に設定する方法も検討できます。ルールモードを何度も切り替えて問題を覆い隠さないようにしましょう。

ウェブサイトは開くが、LAN内の機器や画面ミラーリングが使えない

LAN内のドメインの名前解決に、ルーターや社内DNSが必要か確認してください。パブリックDNSは、家庭用ルーターが管理するデバイス名や、社内ネットワークのDNSレコードを通常は知りません。コアの対応状況に応じて、これらのドメインにローカルの上流DNSを指定し、必要であればFake IPの例外を追加します。LAN内のアドレスが誤ってプロキシへ送られていないかも確認してください。

サブスクリプションを更新するとDNSの変更が消える

リモートサブスクリプションは通常、新しい内容で古いファイルを上書きします。クライアントに永続的な上書き、マージ、パッチ機能があれば、その機能でDNSのカスタマイズを保存してください。そうした機能がない場合は、ローカルのコピーを保管し、更新時にどの項目を再統合する必要があるか明確にしておきましょう。一時的な編集がそのまま維持されると思い込まないでください。

最後に、「どのアドレスが名前解決されたか」と「接続がどこから出ていくか」を分けて確認しましょう。前者はDNS設定、キャッシュ、通信の取り込み経路で決まり、後者はプロキシルール、ポリシーグループ、ノードの状態にも左右されます。設定全体の構造を確認する場合は、設定ガイドも参照してください。DNSだけを変更して、ルールやネットワークの入口を見落とさないようにしましょう。