• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.networkstack.util;
18 
19 import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
20 import static android.net.DnsResolver.TYPE_A;
21 import static android.net.DnsResolver.TYPE_AAAA;
22 
23 import android.annotation.NonNull;
24 import android.net.DnsResolver;
25 import android.net.Network;
26 import android.net.TrafficStats;
27 import android.util.Log;
28 
29 import com.android.internal.util.TrafficStatsConstants;
30 
31 import java.net.InetAddress;
32 import java.net.UnknownHostException;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.concurrent.CountDownLatch;
37 import java.util.concurrent.TimeUnit;
38 import java.util.concurrent.atomic.AtomicReference;
39 
40 /**
41  * Collection of utilities for dns query.
42  */
43 public 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
getAllByName(@onNull final DnsResolver dnsResolver, @NonNull final Network network, @NonNull String host, int timeout)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 
58         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         }
75         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
getAllByName(@onNull final DnsResolver dnsResolver, @NonNull final Network network, @NonNull final String host, int type, int flag, int timeoutMs)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 }
131