blob: 4767d5574a006d2a631e2fa341c77bed2a745fc9 [file] [log] [blame]
Chiachang Wang2d5847b2019-05-10 02:26:23 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.networkstack.util;
18
19import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
20import static android.net.DnsResolver.TYPE_A;
21import static android.net.DnsResolver.TYPE_AAAA;
22
23import android.annotation.NonNull;
24import android.net.DnsResolver;
25import android.net.Network;
26import android.net.TrafficStats;
27import android.util.Log;
28
29import com.android.internal.util.TrafficStatsConstants;
30
31import java.net.InetAddress;
32import java.net.UnknownHostException;
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.List;
36import java.util.concurrent.CountDownLatch;
37import java.util.concurrent.TimeUnit;
38import java.util.concurrent.atomic.AtomicReference;
39
40/**
41 * Collection of utilities for dns query.
42 */
43public class DnsUtils {
44 // Decide what queries to make depending on what IP addresses are on the system.
45 public static final int TYPE_ADDRCONFIG = -1;
46 private static final String TAG = DnsUtils.class.getSimpleName();
47
48 /**
49 * Return both A and AAAA query results regardless the ip address type of the giving network.
50 * Used for probing in NetworkMonitor.
51 */
52 @NonNull
53 public static InetAddress[] getAllByName(@NonNull final DnsResolver dnsResolver,
54 @NonNull final Network network, @NonNull String host, int timeout)
55 throws UnknownHostException {
56 final List<InetAddress> result = new ArrayList<InetAddress>();
57
Chiachang Wang3134eb42019-05-15 15:33:46 +080058 try {
59 result.addAll(Arrays.asList(
60 getAllByName(dnsResolver, network, host, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
61 timeout)));
62 } catch (UnknownHostException e) {
63 // Might happen if the host is v4-only, still need to query TYPE_A
64 }
65 try {
66 result.addAll(Arrays.asList(
67 getAllByName(dnsResolver, network, host, TYPE_A, FLAG_NO_CACHE_LOOKUP,
68 timeout)));
69 } catch (UnknownHostException e) {
70 // Might happen if the host is v6-only, still need to return AAAA answers
71 }
72 if (result.size() == 0) {
73 throw new UnknownHostException(host);
74 }
Chiachang Wang2d5847b2019-05-10 02:26:23 -070075 return result.toArray(new InetAddress[0]);
76 }
77
78 /**
79 * Return dns query result based on the given QueryType(TYPE_A, TYPE_AAAA) or TYPE_ADDRCONFIG.
80 * Used for probing in NetworkMonitor.
81 */
82 @NonNull
83 public static InetAddress[] getAllByName(@NonNull final DnsResolver dnsResolver,
84 @NonNull final Network network, @NonNull final String host, int type, int flag,
85 int timeoutMs) throws UnknownHostException {
86 final CountDownLatch latch = new CountDownLatch(1);
87 final AtomicReference<List<InetAddress>> resultRef = new AtomicReference<>();
88
89 final DnsResolver.Callback<List<InetAddress>> callback =
90 new DnsResolver.Callback<List<InetAddress>>() {
91 @Override
92 public void onAnswer(List<InetAddress> answer, int rcode) {
93 if (rcode == 0) {
94 resultRef.set(answer);
95 }
96 latch.countDown();
97 }
98
99 @Override
100 public void onError(@NonNull DnsResolver.DnsException e) {
101 Log.d(TAG, "DNS error resolving " + host + ": " + e.getMessage());
102 latch.countDown();
103 }
104 };
105 final int oldTag = TrafficStats.getAndSetThreadStatsTag(
106 TrafficStatsConstants.TAG_SYSTEM_PROBE);
107
108 if (type == TYPE_ADDRCONFIG) {
109 dnsResolver.query(network, host, flag, r -> r.run(), null /* cancellationSignal */,
110 callback);
111 } else {
112 dnsResolver.query(network, host, type, flag, r -> r.run(),
113 null /* cancellationSignal */, callback);
114 }
115
116 TrafficStats.setThreadStatsTag(oldTag);
117
118 try {
119 latch.await(timeoutMs, TimeUnit.MILLISECONDS);
120 } catch (InterruptedException e) {
121 }
122
123 final List<InetAddress> result = resultRef.get();
124 if (result == null || result.size() == 0) {
125 throw new UnknownHostException(host);
126 }
127
128 return result.toArray(new InetAddress[0]);
129 }
130}