Loading packages/NetworkStack/src/com/android/networkstack/util/DnsUtils.java 0 → 100644 +119 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.networkstack.util; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; import android.annotation.NonNull; import android.net.DnsResolver; import android.net.Network; import android.net.TrafficStats; import android.util.Log; import com.android.internal.util.TrafficStatsConstants; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; /** * Collection of utilities for dns query. */ public class DnsUtils { // Decide what queries to make depending on what IP addresses are on the system. public static final int TYPE_ADDRCONFIG = -1; private static final String TAG = DnsUtils.class.getSimpleName(); /** * Return both A and AAAA query results regardless the ip address type of the giving network. * Used for probing in NetworkMonitor. */ @NonNull public static InetAddress[] getAllByName(@NonNull final DnsResolver dnsResolver, @NonNull final Network network, @NonNull String host, int timeout) throws UnknownHostException { final List<InetAddress> result = new ArrayList<InetAddress>(); result.addAll(Arrays.asList( getAllByName(dnsResolver, network, host, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, timeout))); result.addAll(Arrays.asList( getAllByName(dnsResolver, network, host, TYPE_A, FLAG_NO_CACHE_LOOKUP, timeout))); return result.toArray(new InetAddress[0]); } /** * Return dns query result based on the given QueryType(TYPE_A, TYPE_AAAA) or TYPE_ADDRCONFIG. * Used for probing in NetworkMonitor. */ @NonNull public static InetAddress[] getAllByName(@NonNull final DnsResolver dnsResolver, @NonNull final Network network, @NonNull final String host, int type, int flag, int timeoutMs) throws UnknownHostException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<List<InetAddress>> resultRef = new AtomicReference<>(); final DnsResolver.Callback<List<InetAddress>> callback = new DnsResolver.Callback<List<InetAddress>>() { @Override public void onAnswer(List<InetAddress> answer, int rcode) { if (rcode == 0) { resultRef.set(answer); } latch.countDown(); } @Override public void onError(@NonNull DnsResolver.DnsException e) { Log.d(TAG, "DNS error resolving " + host + ": " + e.getMessage()); latch.countDown(); } }; final int oldTag = TrafficStats.getAndSetThreadStatsTag( TrafficStatsConstants.TAG_SYSTEM_PROBE); if (type == TYPE_ADDRCONFIG) { dnsResolver.query(network, host, flag, r -> r.run(), null /* cancellationSignal */, callback); } else { dnsResolver.query(network, host, type, flag, r -> r.run(), null /* cancellationSignal */, callback); } TrafficStats.setThreadStatsTag(oldTag); try { latch.await(timeoutMs, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { } final List<InetAddress> result = resultRef.get(); if (result == null || result.size() == 0) { throw new UnknownHostException(host); } return result.toArray(new InetAddress[0]); } } packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +8 −36 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC; import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.DnsResolver.FLAG_EMPTY; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; Loading Loading @@ -56,6 +57,8 @@ import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS; import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY; import static android.net.util.NetworkStackUtils.isEmpty; import static com.android.networkstack.util.DnsUtils.TYPE_ADDRCONFIG; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; Loading Loading @@ -113,6 +116,7 @@ import com.android.internal.util.TrafficStatsConstants; import com.android.networkstack.R; import com.android.networkstack.metrics.DataStallDetectionStats; import com.android.networkstack.metrics.DataStallStatsUtils; import com.android.networkstack.util.DnsUtils; import java.io.IOException; import java.net.HttpURLConnection; Loading @@ -129,7 +133,6 @@ import java.util.Random; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; /** Loading Loading @@ -994,8 +997,8 @@ public class NetworkMonitor extends StateMachine { private void resolveStrictModeHostname() { try { // Do a blocking DNS resolution using the network-assigned nameservers. final InetAddress[] ips = mCleartextDnsNetwork.getAllByName( mPrivateDnsProviderHostname); final InetAddress[] ips = DnsUtils.getAllByName(mDependencies.getDnsResolver(), mCleartextDnsNetwork, mPrivateDnsProviderHostname, getDnsProbeTimeout()); mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips); validationLog("Strict mode hostname resolved: " + mPrivateDnsConfig); } catch (UnknownHostException uhe) { Loading Loading @@ -1489,39 +1492,8 @@ public class NetworkMonitor extends StateMachine { @VisibleForTesting protected InetAddress[] sendDnsProbeWithTimeout(String host, int timeoutMs) throws UnknownHostException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<List<InetAddress>> resultRef = new AtomicReference<>(); final DnsResolver.Callback<List<InetAddress>> callback = new DnsResolver.Callback<List<InetAddress>>() { public void onAnswer(List<InetAddress> answer, int rcode) { if (rcode == 0) { resultRef.set(answer); } latch.countDown(); } public void onError(@NonNull DnsResolver.DnsException e) { validationLog("DNS error resolving " + host + ": " + e.getMessage()); latch.countDown(); } }; final int oldTag = TrafficStats.getAndSetThreadStatsTag( TrafficStatsConstants.TAG_SYSTEM_PROBE); mDependencies.getDnsResolver().query(mCleartextDnsNetwork, host, DnsResolver.FLAG_EMPTY, r -> r.run() /* executor */, null /* cancellationSignal */, callback); TrafficStats.setThreadStatsTag(oldTag); try { latch.await(timeoutMs, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { } List<InetAddress> result = resultRef.get(); if (result == null || result.size() == 0) { throw new UnknownHostException(host); } return result.toArray(new InetAddress[0]); return DnsUtils.getAllByName(mDependencies.getDnsResolver(), mCleartextDnsNetwork, host, TYPE_ADDRCONFIG, FLAG_EMPTY, timeoutMs); } /** Do a DNS resolution of the given server. */ Loading packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +16 −5 Original line number Diff line number Diff line Loading @@ -226,11 +226,6 @@ public class NetworkMonitorTest { /** Starts mocking DNS queries. */ private void startMocking() throws UnknownHostException { // Queries on mCleartextDnsNetwork using getAllByName. doAnswer(invocation -> { return getAllByName(invocation.getMock(), invocation.getArgument(0)); }).when(mCleartextDnsNetwork).getAllByName(any()); // Queries on mNetwork using getAllByName. doAnswer(invocation -> { return getAllByName(invocation.getMock(), invocation.getArgument(0)); Loading @@ -251,6 +246,22 @@ public class NetworkMonitorTest { // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE. return null; }).when(mDnsResolver).query(any(), any(), anyInt(), any(), any(), any()); // Queries on mCleartextDnsNetwork using using DnsResolver#query with QueryType. doAnswer(invocation -> { String hostname = (String) invocation.getArgument(1); Executor executor = (Executor) invocation.getArgument(4); DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(6); List<InetAddress> answer = getAnswer(invocation.getMock(), hostname); if (answer != null && answer.size() > 0) { new Handler(Looper.getMainLooper()).post(() -> { executor.execute(() -> callback.onAnswer(answer, 0)); }); } // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE. return null; }).when(mDnsResolver).query(any(), any(), anyInt(), anyInt(), any(), any(), any()); } } Loading Loading
packages/NetworkStack/src/com/android/networkstack/util/DnsUtils.java 0 → 100644 +119 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.networkstack.util; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; import android.annotation.NonNull; import android.net.DnsResolver; import android.net.Network; import android.net.TrafficStats; import android.util.Log; import com.android.internal.util.TrafficStatsConstants; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; /** * Collection of utilities for dns query. */ public class DnsUtils { // Decide what queries to make depending on what IP addresses are on the system. public static final int TYPE_ADDRCONFIG = -1; private static final String TAG = DnsUtils.class.getSimpleName(); /** * Return both A and AAAA query results regardless the ip address type of the giving network. * Used for probing in NetworkMonitor. */ @NonNull public static InetAddress[] getAllByName(@NonNull final DnsResolver dnsResolver, @NonNull final Network network, @NonNull String host, int timeout) throws UnknownHostException { final List<InetAddress> result = new ArrayList<InetAddress>(); result.addAll(Arrays.asList( getAllByName(dnsResolver, network, host, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, timeout))); result.addAll(Arrays.asList( getAllByName(dnsResolver, network, host, TYPE_A, FLAG_NO_CACHE_LOOKUP, timeout))); return result.toArray(new InetAddress[0]); } /** * Return dns query result based on the given QueryType(TYPE_A, TYPE_AAAA) or TYPE_ADDRCONFIG. * Used for probing in NetworkMonitor. */ @NonNull public static InetAddress[] getAllByName(@NonNull final DnsResolver dnsResolver, @NonNull final Network network, @NonNull final String host, int type, int flag, int timeoutMs) throws UnknownHostException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<List<InetAddress>> resultRef = new AtomicReference<>(); final DnsResolver.Callback<List<InetAddress>> callback = new DnsResolver.Callback<List<InetAddress>>() { @Override public void onAnswer(List<InetAddress> answer, int rcode) { if (rcode == 0) { resultRef.set(answer); } latch.countDown(); } @Override public void onError(@NonNull DnsResolver.DnsException e) { Log.d(TAG, "DNS error resolving " + host + ": " + e.getMessage()); latch.countDown(); } }; final int oldTag = TrafficStats.getAndSetThreadStatsTag( TrafficStatsConstants.TAG_SYSTEM_PROBE); if (type == TYPE_ADDRCONFIG) { dnsResolver.query(network, host, flag, r -> r.run(), null /* cancellationSignal */, callback); } else { dnsResolver.query(network, host, type, flag, r -> r.run(), null /* cancellationSignal */, callback); } TrafficStats.setThreadStatsTag(oldTag); try { latch.await(timeoutMs, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { } final List<InetAddress> result = resultRef.get(); if (result == null || result.size() == 0) { throw new UnknownHostException(host); } return result.toArray(new InetAddress[0]); } }
packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +8 −36 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC; import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.DnsResolver.FLAG_EMPTY; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; Loading Loading @@ -56,6 +57,8 @@ import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS; import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY; import static android.net.util.NetworkStackUtils.isEmpty; import static com.android.networkstack.util.DnsUtils.TYPE_ADDRCONFIG; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; Loading Loading @@ -113,6 +116,7 @@ import com.android.internal.util.TrafficStatsConstants; import com.android.networkstack.R; import com.android.networkstack.metrics.DataStallDetectionStats; import com.android.networkstack.metrics.DataStallStatsUtils; import com.android.networkstack.util.DnsUtils; import java.io.IOException; import java.net.HttpURLConnection; Loading @@ -129,7 +133,6 @@ import java.util.Random; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; /** Loading Loading @@ -994,8 +997,8 @@ public class NetworkMonitor extends StateMachine { private void resolveStrictModeHostname() { try { // Do a blocking DNS resolution using the network-assigned nameservers. final InetAddress[] ips = mCleartextDnsNetwork.getAllByName( mPrivateDnsProviderHostname); final InetAddress[] ips = DnsUtils.getAllByName(mDependencies.getDnsResolver(), mCleartextDnsNetwork, mPrivateDnsProviderHostname, getDnsProbeTimeout()); mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips); validationLog("Strict mode hostname resolved: " + mPrivateDnsConfig); } catch (UnknownHostException uhe) { Loading Loading @@ -1489,39 +1492,8 @@ public class NetworkMonitor extends StateMachine { @VisibleForTesting protected InetAddress[] sendDnsProbeWithTimeout(String host, int timeoutMs) throws UnknownHostException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<List<InetAddress>> resultRef = new AtomicReference<>(); final DnsResolver.Callback<List<InetAddress>> callback = new DnsResolver.Callback<List<InetAddress>>() { public void onAnswer(List<InetAddress> answer, int rcode) { if (rcode == 0) { resultRef.set(answer); } latch.countDown(); } public void onError(@NonNull DnsResolver.DnsException e) { validationLog("DNS error resolving " + host + ": " + e.getMessage()); latch.countDown(); } }; final int oldTag = TrafficStats.getAndSetThreadStatsTag( TrafficStatsConstants.TAG_SYSTEM_PROBE); mDependencies.getDnsResolver().query(mCleartextDnsNetwork, host, DnsResolver.FLAG_EMPTY, r -> r.run() /* executor */, null /* cancellationSignal */, callback); TrafficStats.setThreadStatsTag(oldTag); try { latch.await(timeoutMs, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { } List<InetAddress> result = resultRef.get(); if (result == null || result.size() == 0) { throw new UnknownHostException(host); } return result.toArray(new InetAddress[0]); return DnsUtils.getAllByName(mDependencies.getDnsResolver(), mCleartextDnsNetwork, host, TYPE_ADDRCONFIG, FLAG_EMPTY, timeoutMs); } /** Do a DNS resolution of the given server. */ Loading
packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +16 −5 Original line number Diff line number Diff line Loading @@ -226,11 +226,6 @@ public class NetworkMonitorTest { /** Starts mocking DNS queries. */ private void startMocking() throws UnknownHostException { // Queries on mCleartextDnsNetwork using getAllByName. doAnswer(invocation -> { return getAllByName(invocation.getMock(), invocation.getArgument(0)); }).when(mCleartextDnsNetwork).getAllByName(any()); // Queries on mNetwork using getAllByName. doAnswer(invocation -> { return getAllByName(invocation.getMock(), invocation.getArgument(0)); Loading @@ -251,6 +246,22 @@ public class NetworkMonitorTest { // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE. return null; }).when(mDnsResolver).query(any(), any(), anyInt(), any(), any(), any()); // Queries on mCleartextDnsNetwork using using DnsResolver#query with QueryType. doAnswer(invocation -> { String hostname = (String) invocation.getArgument(1); Executor executor = (Executor) invocation.getArgument(4); DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(6); List<InetAddress> answer = getAnswer(invocation.getMock(), hostname); if (answer != null && answer.size() > 0) { new Handler(Looper.getMainLooper()).post(() -> { executor.execute(() -> callback.onAnswer(answer, 0)); }); } // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE. return null; }).when(mDnsResolver).query(any(), any(), anyInt(), anyInt(), any(), any(), any()); } } Loading