iOSでhostsファイルを編集するようにDNS解決をカスタマイズする方法
私は以前の会社でDNS解決の問題に悩まされた経験があります。
当時、社内プロジェクトでは本番環境とテスト環境で同じドメインを使用しており、アプリの通信をテスト環境に向けるにはドメイン解決を変更する必要がありました。PCであれば、システムの hosts ファイルをちょっと編集するだけで簡単に済みます。しかしiOSでは、サンドボックスとセキュリティ制限のため、hosts を直接変更することはできません。
当時はWi-FiのDNSサーバーをカスタムDNSサーバーに設定することで回避していました。しかし、次のような問題が頻繁に発生しました:
- DNSのキャッシュが残るため、変更のたびにキャッシュをクリアしてアプリを再起動しなければならない
- キャッシュの影響で、DNS解決が反映されたかどうかはAPIレスポンスを見て判断するしかない
- 毎回Wi-FiのDNSサーバー設定を変更するのが面倒
- 変更すると、スマホ上の他のアプリの動作に影響が出る可能性がある
これらの問題を解決するために、ApiCatcherにDNSスプーフィング機能 「DNSマッピング」 を実装しました。これによりiOS上で「カスタムhosts」を実現し、指定したドメインを任意のIPアドレスにリダイレクトできます。
DNSマッピングの仕組み
iOSのシステム hosts を変更できない中で、ApiCatcherはどのようにしてドメイン解決の結果を変えているのでしょうか?
その核心は、プロキシ層のTCP接続確立段階でのインターセプトとリダイレクトにあります:
- 通信の捕捉:ApiCatcherでパケットキャプチャを開始すると、スマホ上のアプリが発行するHTTP/HTTPSリクエストはすべてローカルVPNトンネルを通り、ApiCatcherのローカルプロキシサーバーを経由します。
- プロキシ層でのHostインターセプト:アプリが対象ドメイン(例:
echo.apicatcher.net)に接続を試みる際、プロキシサーバーは実際のTCP接続を開始する前に、ローカルのDNSマッピングルールを照合します。 - 物理IPへの置き換え:設定したマッピングルールにマッチした場合、プロキシサーバーはパブリックDNSへの問い合わせをスキップし、指定されたIPアドレスに直接TCP接続を確立します。
- TLSハンドシェイクへの透過性:IPアドレスの置き換えはTCPの物理接続確立段階でのみ行われるため、HTTPパケットの
HostヘッダーやTLSハンドシェイク時のSNI(Server Name Indication)情報はそのまま維持されます。そのため、厳格なHTTPSハンドシェイクでもクライアント側の証明書検証は正常に通過し、アプリにとっては完全に透過的で違和感がありません。
設定方法
-
ApiCatcherアプリを開き、ホーム画面の上部にある 「+」 ボタンをタップし、ポップアップメニューから DNSマッピング を選択して 「DNSマッピング」 設定画面に入ります。
-
右上の 「+」 ボタンをタップして新しいルールを作成します:
- ドメイン:マッピングしたいドメインを入力します。ワイルドカードにも対応しています(例:
*.apicatcher.netはすべてのサブドメインにマッチします)。 - IPアドレス:接続先のサーバーまたはローカルPCのIPアドレスを入力します。
- ドメイン:マッピングしたいドメインを入力します。ワイルドカードにも対応しています(例:
-
キャプチャ開始で即時に反映 ホーム画面に戻り、キャプチャ開始ボタンをタップしてプロキシサービスを起動します。すると、スマホ上の該当するすべてのリクエストが、設定したIPアドレスに自動的に振り向けられます。 パケットキャプチャをせずにDNSマッピングのみ使いたい場合は、ホストのホワイトリスト/ブラックリストルールを設定することもできます。
DNSマッピングルールの変更は、キャプチャがオンの状態であれば即座に反映されます。
