Merge "Private DNS connectivity check"

This commit is contained in:
TreeHugger Robot
2018-12-08 22:50:21 +00:00
committed by Android (Google) Code Review
6 changed files with 147 additions and 16 deletions

View File

@@ -49,6 +49,8 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
import android.net.NetworkUtils;
import android.net.PrivateDnsConnectivityChecker;
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Binder;
@@ -79,6 +81,7 @@ import android.security.keystore.StrongBoxUnavailableException;
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -2031,6 +2034,35 @@ public class DevicePolicyManager {
@Retention(RetentionPolicy.SOURCE)
public @interface InstallUpdateCallbackErrorConstants {}
/**
* The selected mode has been set successfully. If the mode is
* {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} then it implies the supplied host is valid
* and reachable.
*/
public static final int PRIVATE_DNS_SET_SUCCESS = 0;
/**
* If the {@code privateDnsHost} provided was of a valid hostname but that host was found
* to not support DNS-over-TLS.
*/
public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1;
/**
* General failure to set the Private DNS mode, not due to one of the reasons listed above.
*/
public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2;
/**
* @hide
*/
@IntDef(prefix = {"PRIVATE_DNS_SET_"}, value = {
PRIVATE_DNS_SET_SUCCESS,
PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING,
PRIVATE_DNS_SET_ERROR_FAILURE_SETTING
})
@Retention(RetentionPolicy.SOURCE)
public @interface SetPrivateDnsModeResultConstants {}
/**
* Return true if the given administrator component is currently active (enabled) in the system.
*
@@ -9897,6 +9929,16 @@ public class DevicePolicyManager {
* Sets the global Private DNS mode and host to be used.
* May only be called by the device owner.
*
* <p>Note that in case a Private DNS resolver is specified, the method is blocking as it
* will perform a connectivity check to the resolver, to ensure it is valid. Because of that,
* the method should not be called on any thread that relates to user interaction, such as the
* UI thread.
*
* <p>In case a VPN is used in conjunction with Private DNS resolver, the Private DNS resolver
* must be reachable both from within and outside the VPN. Otherwise, the device may lose
* the ability to resolve hostnames as system traffic to the resolver may not go through the
* VPN.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with.
* @param mode Which mode to set - either {@code PRIVATE_DNS_MODE_OPPORTUNISTIC} or
* {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}.
@@ -9906,6 +9948,9 @@ public class DevicePolicyManager {
* @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858), if
* {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} was specified as the mode,
* null otherwise.
*
* @return One of the values in {@link SetPrivateDnsModeResultConstants}.
*
* @throws IllegalArgumentException in the following cases: if a {@code privateDnsHost} was
* provided but the mode was not {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}, if the mode
* specified was {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} but {@code privateDnsHost} does
@@ -9913,15 +9958,23 @@ public class DevicePolicyManager {
*
* @throws SecurityException if the caller is not the device owner.
*/
public void setGlobalPrivateDns(@NonNull ComponentName admin,
public int setGlobalPrivateDns(@NonNull ComponentName admin,
@PrivateDnsMode int mode, @Nullable String privateDnsHost) {
throwIfParentInstance("setGlobalPrivateDns");
if (mService == null) {
return;
return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
if (mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME && !TextUtils.isEmpty(privateDnsHost)
&& NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
if (!PrivateDnsConnectivityChecker.canConnectToPrivateDnsServer(privateDnsHost)) {
return PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING;
}
}
try {
mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
return mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}

View File

@@ -415,7 +415,7 @@ interface IDevicePolicyManager {
boolean isMeteredDataDisabledPackageForUser(in ComponentName admin, String packageName, int userId);
void setGlobalPrivateDns(in ComponentName admin, int mode, in String privateDnsHost);
int setGlobalPrivateDns(in ComponentName admin, int mode, in String privateDnsHost);
int getGlobalPrivateDnsMode(in ComponentName admin);
String getGlobalPrivateDnsHost(in ComponentName admin);

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2018 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 android.net;
import android.annotation.NonNull;
import android.util.Log;
import java.io.IOException;
import java.net.InetSocketAddress;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
/**
* Class for testing connectivity to DNS-over-TLS servers.
* {@hide}
*/
public class PrivateDnsConnectivityChecker {
private static final String TAG = "NetworkUtils";
private static final int PRIVATE_DNS_PORT = 853;
private static final int CONNECTION_TIMEOUT_MS = 5000;
private PrivateDnsConnectivityChecker() { }
/**
* checks that a provided host can perform a TLS handshake on port 853.
* @param hostname host to connect to.
*/
public static boolean canConnectToPrivateDnsServer(@NonNull String hostname) {
final SocketFactory factory = SSLSocketFactory.getDefault();
TrafficStats.setThreadStatsTag(TrafficStats.TAG_SYSTEM_APP);
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
socket.setSoTimeout(CONNECTION_TIMEOUT_MS);
socket.connect(new InetSocketAddress(hostname, PRIVATE_DNS_PORT));
if (!socket.isConnected()) {
Log.w(TAG, String.format("Connection to %s failed.", hostname));
return false;
}
socket.startHandshake();
Log.w(TAG, String.format("TLS handshake to %s succeeded.", hostname));
return true;
} catch (IOException e) {
Log.w(TAG, String.format("TLS handshake to %s failed.", hostname), e);
return false;
}
}
}