Merge "Private DNS connectivity check"
This commit is contained in:
committed by
Android (Google) Code Review
commit
2eb3473d0d
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
64
core/java/android/net/PrivateDnsConnectivityChecker.java
Normal file
64
core/java/android/net/PrivateDnsConnectivityChecker.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user