This topic describes how to obtain Domain Name System (DNS) resolution duration when you execute network requests by using the OkHttp
library on an Android app.
1. Overview
You can use EventListener
to obtain DNS resolution duration when you execute network requests by using the OkHttp
library on an Android app. EventListener
provides multiple callback methods to track network requests at different phases, including DNS resolution, connection establishment, and data transmission.
You can use InetAddress.getAllByName(String host)
to obtain the DNS resolution resolution of local DNS servers. This allows you to determine whether domain hijacking occurs by comparing the obtained resolution with the expected resolution.
2. Procedure
You can perform the following steps to use OkHttp
and EventListener
to obtain DNS resolution duration:
Step 1: Import the OkHttp
library
Add the OkHttp
dependency in the build.gradle
file.
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
Step 2: Create a custom EventListener
class
Create a custom EventListener
class to listen to and record DNS resolution duration.
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 resolution duration: " + dnsDuration + "Milliseconds");
}
}
Step 3: Create an OkHttpClient
instance and configure the EventListener.Factory
parameter
Configure the custom EventListener.Factory
parameter for the OkHttpClient
instance.
import okhttp3.OkHttpClient;
// Create an OkHttpClient instance.
OkHttpClient client = new OkHttpClient.Builder()
.eventListenerFactory(new EventListener.Factory() {
@Override
public EventListener create(Call call) {
return new DnsTimingEventListener();
}
})
.build();
Step 4: Execute a network request
Execute a network request by using the configured OkHttpClient
instance.
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public void executeNetworkRequest() {
// Create a Request object.
Request request = new Request.Builder()
// Enter an actual URL in .url()
.url("https://www.example.com")
.build();
try {
// Execute the request.
Response response = client.newCall(request).execute();
// Process the response.
if (response.isSuccessful()) {
System.out.println("The request is successful");
// You can process the response here.
} else {
System.out.println("The request failed, Status code:" + response.code());
}
} catch (IOException e) {
e.printStackTrace();
}
}
You can perform the preceding steps to obtain DNS resolution duration and process the response. This can not only help you understand the periods of time consumed by network requests but also can be used for performance improvement and monitoring.
If you have integrated Alibaba Cloud Public DNS SDK with your Android app that uses the OkHttp
library, you can obtain the DNS resolution duration of Alibaba Cloud Public DNS by performing the preceding steps. If you have not integrated Alibaba Cloud Public DNS SDK with your Android app that uses the OkHttp
library, you can obtain only the DNS resolution duration of local DNS server InetAddress
by performing the preceding steps.
The following sample code provides an example on how to access Alibaba Cloud Public DNS SDK on Android apps that use OkHttp
:
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 {
//Call the API operation in Alibaba Cloud Public DNS SDK for Android to resolve a domain name.
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) {
//If the returned ip value is not null, directly use the IP address to send network requests.
Log.d(TAG, "mDnsCache IP: " + ip);
return Arrays.asList(InetAddress.getAllByName(ip));
}
//If null is returned, use the system DNS service to resolve the domain name.
return Dns.SYSTEM.lookup(hostname);
}
}
3. Obtain the DNS resolution result of local DNS servers and determine whether domain hijacking occurs
The following sample code provides an example on how to obtain DNS resolution duration of local DNS servers:
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;
}
The following sample code provides an example on how to determine if domain hijacking occurs by comparing the obtained DNS resolution duration of local DNS servers with the expected duration:
public boolean isDnsHijacked(String domain, List<String> expectedIps) {
List<String> localIps = getIPAddresses(domain);
if (localIps.isEmpty()) {
return false; // Domain name cannot be resolved.
}
for (String localIp : localIps) {
if (!expectedIps.contains(localIp)) {
return true; // The unexptected IP address indicates that DNS may be hijacked.
}
}
return false; // All DNS resolutions match the expected duration.
}