このドキュメントでは、Android でネットワークリクエストに okhttp ライブラリを使用する場合に、DNS 解決時間を取得する方法について説明します。
1. 概要
Android でネットワークリクエストに okhttp ライブラリを使用する場合、EventListener を介して DNS 解決時間を取得できます。 EventListener は、DNS 解決、接続確立、データ転送など、さまざまな段階でネットワークリクエストを追跡するための複数のコールバックメソッドを提供します。
Android では、InetAddress.getAllByName(String host) メソッドを使用して、ローカル DNS からの解決結果を取得できます。 これらの結果を予想される解決結果と比較して、ハイジャックがあるかどうかを判断できます。
2. DNS 解決時間を取得する方法
okhttp と EventListener を使用して DNS 解決時間を取得する手順は次のとおりです。
ステップ 1:okhttp ライブラリをインポートする
ファイルに build.gradle の okhttp 依存関係を追加してください。
implementation 'com.squareup.okhttp3:okhttp:4.9.3'ステップ 2:カスタム EventListener を作成する
DNS 解決時間を監視および記録するために、カスタム EventListener クラスを作成する必要があります。
import okhttp3.EventListener;
import okhttp3.Call;
import okhttp3.HttpUrl;
public class DnsTimingEventListener extends EventListener {
private long dnsStartTime;
private long dnsEndTime;
@Override
public void dnsStart(Call call, String domainName) {
super.dnsStart(call, domainName);
dnsStartTime = System.currentTimeMillis();
}
@Override
public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
super.dnsEnd(call, domainName, inetAddressList);
dnsEndTime = System.currentTimeMillis();
long dnsDuration = dnsEndTime - dnsStartTime;
System.out.println("DNS 解決時間: " + dnsDuration + " ミリ秒"); // 日本語訳を追加
}
}ステップ 3:OkHttpClient インスタンスを作成し、EventListener.Factory を設定する
カスタム EventListener ファクトリを OkHttpClient インスタンスに設定できます。
import okhttp3.OkHttpClient;
// OkHttpClient インスタンスを作成
OkHttpClient client = new OkHttpClient.Builder()
.eventListenerFactory(new EventListener.Factory() {
@Override
public EventListener create(Call call) {
return new DnsTimingEventListener();
}
})
.build();ステップ 4:ネットワークリクエストを実行する
構成済みの OkHttpClient インスタンスを使用して、ネットワークリクエストを実行できます。
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public void executeNetworkRequest() {
// Request オブジェクトを作成
Request request = new Request.Builder()
// .url() に実際の URL アドレスを設定します
.url("https://www.example.com")
.build();
try {
// リクエストを実行します
Response response = client.newCall(request).execute();
// レスポンスを処理します
if (response.isSuccessful()) {
System.out.println("リクエスト成功"); // 日本語訳を追加
// ここでレスポンスデータを処理できます
} else {
System.out.println("リクエスト失敗、状態コード: " + response.code()); // 日本語訳を追加
}
} catch (IOException e) {
e.printStackTrace();
}
}上記の方法を使用して、DNS 解決時間を取得し、それに応じて処理できます。 これは、ネットワークリクエストの時間消費を理解するのに役立ち、パフォーマンスの最適化と監視に使用できます。
OkHttp DNS インターフェイスを実装して HTTPDNS サービスを使用できます。OkHttp DNS インターフェイスを実装して HTTPDNS を使用する場合、上記の方法で取得する名前解決時間は HTTPDNS の名前解決時間です。OkHttp DNS インターフェイスを実装しない場合、OkHttp はシステムのデフォルト DNS サービスである InetAddress を使用します。この場合、取得する名前解決時間はシステムの DNS サービスの名前解決時間です。
OkHttp の DNS インターフェースを実装するには、次のコードを参照できます。
public class OkHttpDns implements Dns {
private static OkHttpDns instance;
private static Object lock = new Object();
private DNSResolver mDNSResolver = DNSResolver.getInstance();
private OkHttpDns() {
}
public static OkHttpDns getInstance() {
if (null == instance) {
synchronized (lock) {
if (instance == null) {
instance = new OkHttpDns();
}
}
}
return instance;
}
@Override
public List<InetAddress> lookup(@NonNull String hostname) throws UnknownHostException {
// HTTPDNS Android SDK が提供する API を呼び出してドメイン名を解決
String ip = null;
String[] ipv4Array = mDNSResolver.getIpv4ByHostFromCache(hostname,true);
if (ipv4Array != null && ipv4Array.length > 0) {
ip = ipv4Array[0];
}else {
ip = mDNSResolver.getIPV4ByHost(hostname);
}
if (ip != null) {
// IP が null でない場合は、ネットワークリクエストに直接使用
Log.d(TAG, "mDnsCache の IP: " + ip);
return Arrays.asList(InetAddress.getAllByName(ip));
}
// null が返された場合は、システムの DNS サービスを使用してドメイン名を解決
return Dns.SYSTEM.lookup(hostname);
}
}3. LocalDNS 解決結果の取得とハイジャック検出比較の実行
次のコードを使用して、LocalDNS 解決結果を取得できます。
public List<String> getIPAddresses(String domain) {
List<String> ipAddresses = new ArrayList<>();
try {
InetAddress[] addresses = InetAddress.getAllByName(domain);
for (InetAddress address : addresses) {
ipAddresses.add(address.getHostAddress());
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
return ipAddresses;
}
取得した LocalDNS 解決結果を、想定される解決結果と比較してハイジャックがあるかどうかを判断するには、次のコードを参照できます。
public boolean isDnsHijacked(String domain, List<String> expectedIps) {
List<String> localIps = getIPAddresses(domain);
if (localIps.isEmpty()) {
return false; // ドメイン名を解決できません
}
for (String localIp : localIps) {
if (!expectedIps.contains(localIp)) {
return true; // 一致しない IP が見つかりました。DNS ハイジャックが存在する可能性があります
}
}
return false; // すべての解決結果が一致しています
}