1 /* 2 * Copyright (C) 2016 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.cts.deviceandprofileowner; 18 19 import static com.android.cts.deviceandprofileowner.vpn.VpnTestHelper.TEST_ADDRESS; 20 import static com.android.cts.deviceandprofileowner.vpn.VpnTestHelper.VPN_PACKAGE; 21 22 import android.os.Bundle; 23 import android.os.UserManager; 24 import android.util.Log; 25 26 import com.android.compatibility.common.util.BlockingBroadcastReceiver; 27 import com.android.cts.deviceandprofileowner.vpn.VpnTestHelper; 28 29 import java.io.IOException; 30 import java.net.Socket; 31 32 /** 33 * Validates that a device owner or profile owner can set an always-on VPN without user action. 34 * 35 * A trivial VPN app is installed which reflects ping packets back to the sender. One ping packet is 36 * sent, received after its round-trip, and compared to the original packet to make sure nothing 37 * strange happened on the way through the VPN. 38 * 39 * All of the addresses in this test are fictional and any resemblance to real addresses is the 40 * result of a misconfigured network. 41 */ 42 public class AlwaysOnVpnTest extends BaseDeviceAdminTest { 43 private static final String TAG = "AlwaysOnVpnTest"; 44 45 /** @see com.android.cts.vpnfirewall.ReflectorVpnService */ 46 private static final String RESTRICTION_ALLOWED = "vpn.allowed"; 47 private static final String RESTRICTION_DISALLOWED = "vpn.disallowed"; 48 private static final String RESTRICTION_DONT_ESTABLISH = "vpn.dont_establish"; 49 private static final String CONNECTIVITY_CHECK_HOST = "connectivitycheck.gstatic.com"; 50 private static final int VPN_ON_START_TIMEOUT_MS = 5_000; 51 private static final long CONNECTIVITY_WAIT_TIME_NS = 30_000_000_000L; 52 53 private String mPackageName; 54 55 @Override setUp()56 public void setUp() throws Exception { 57 super.setUp(); 58 // Always-on is null by default. 59 assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT)); 60 mPackageName = mContext.getPackageName(); 61 } 62 63 @Override tearDown()64 public void tearDown() throws Exception { 65 mDevicePolicyManager.setAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT, null, false); 66 mDevicePolicyManager.setApplicationRestrictions(ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE, 67 /* restrictions */ null); 68 super.tearDown(); 69 } 70 testAlwaysOnVpn()71 public void testAlwaysOnVpn() throws Exception { 72 // test always-on is null by default 73 assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT)); 74 75 VpnTestHelper.waitForVpn(mContext, VPN_PACKAGE, 76 /* usable */ true, /* lockdown */ true, /* allowlist */ false); 77 78 VpnTestHelper.checkPing(TEST_ADDRESS); 79 } 80 testDisallowConfigVpn()81 public void testDisallowConfigVpn() throws Exception { 82 mDevicePolicyManager.addUserRestriction( 83 ADMIN_RECEIVER_COMPONENT, UserManager.DISALLOW_CONFIG_VPN); 84 try { 85 testAlwaysOnVpn(); 86 } finally { 87 // clear the user restriction 88 mDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT, 89 UserManager.DISALLOW_CONFIG_VPN); 90 } 91 } 92 testAllowedApps()93 public void testAllowedApps() throws Exception { 94 final Bundle restrictions = new Bundle(); 95 restrictions.putStringArray(RESTRICTION_ALLOWED, new String[] {mPackageName}); 96 mDevicePolicyManager.setApplicationRestrictions(ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE, 97 restrictions); 98 VpnTestHelper.waitForVpn(mContext, VPN_PACKAGE, 99 /* usable */ true, /* lockdown */ true, /* allowlist */ false); 100 assertTrue(VpnTestHelper.isNetworkVpn(mContext)); 101 } 102 testDisallowedApps()103 public void testDisallowedApps() throws Exception { 104 final Bundle restrictions = new Bundle(); 105 restrictions.putStringArray(RESTRICTION_DISALLOWED, new String[] {mPackageName}); 106 mDevicePolicyManager.setApplicationRestrictions(ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE, 107 restrictions); 108 VpnTestHelper.waitForVpn(mContext, VPN_PACKAGE, 109 /* usable */ false, /* lockdown */ true, /* allowlist */ false); 110 assertFalse(VpnTestHelper.isNetworkVpn(mContext)); 111 } 112 113 // Tests that changes to lockdown allowlist are applied correctly. testVpnLockdownUpdateAllowlist()114 public void testVpnLockdownUpdateAllowlist() throws Exception { 115 waitForConnectivity("VPN is off"); 116 117 // VPN won't start. 118 final Bundle restrictions = new Bundle(); 119 restrictions.putBoolean(RESTRICTION_DONT_ESTABLISH, true); 120 mDevicePolicyManager.setApplicationRestrictions( 121 ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE, restrictions); 122 123 // VPN service is started asynchronously, we need to wait for it to avoid stale service 124 // instance interfering with the next test. 125 final BlockingBroadcastReceiver receiver = VpnTestHelper.registerOnStartReceiver(mContext); 126 127 VpnTestHelper.setAlwaysOnVpn( 128 mContext, VPN_PACKAGE, /* lockdown */ false, /* allowlist */ false); 129 waitForConnectivity("VPN service not started, no lockdown"); 130 assertNotNull(receiver.awaitForBroadcast(VPN_ON_START_TIMEOUT_MS)); 131 132 VpnTestHelper.setAlwaysOnVpn( 133 mContext, VPN_PACKAGE, /* lockdown */ true, /* allowlist */ false); 134 // Wait for loss of connectivity instead of assertConnectivity(false) 135 // to mitigate flakiness due to asynchronicity. 136 waitForNoConnectivity("VPN in lockdown, service not started"); 137 assertNotNull(receiver.awaitForBroadcast(VPN_ON_START_TIMEOUT_MS)); 138 139 VpnTestHelper.setAlwaysOnVpn( 140 mContext, VPN_PACKAGE, /* lockdown */ true, /* allowlist */ true); 141 waitForConnectivity("VPN in lockdown, service not started, app allowlisted"); 142 assertNotNull(receiver.awaitForBroadcast(VPN_ON_START_TIMEOUT_MS)); 143 144 VpnTestHelper.setAlwaysOnVpn( 145 mContext, VPN_PACKAGE, /* lockdown */ true, /* allowlist */ false); 146 // Wait for loss of connectivity instead of assertConnectivity(false) 147 // to mitigate flakiness due to asynchronicity. 148 waitForNoConnectivity("VPN in lockdown, service not started"); 149 assertNotNull(receiver.awaitForBroadcast(VPN_ON_START_TIMEOUT_MS)); 150 151 receiver.unregisterQuietly(); 152 } 153 154 // Tests that when VPN comes up, allowlisted app switches over to it. testVpnLockdownAllowlistVpnComesUp()155 public void testVpnLockdownAllowlistVpnComesUp() throws Exception { 156 waitForConnectivity("VPN is off"); 157 158 // VPN won't start initially. 159 final Bundle restrictions = new Bundle(); 160 restrictions.putBoolean(RESTRICTION_DONT_ESTABLISH, true); 161 mDevicePolicyManager.setApplicationRestrictions( 162 ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE, restrictions); 163 164 // VPN service is started asynchronously, we need to wait for it to avoid stale service 165 // instance interfering with the next test. 166 final BlockingBroadcastReceiver receiver = VpnTestHelper.registerOnStartReceiver(mContext); 167 168 VpnTestHelper.setAlwaysOnVpn( 169 mContext, VPN_PACKAGE, /* lockdown */ true, /* allowlist */ true); 170 waitForConnectivity("VPN in lockdown, service not started, app allowlisted"); 171 assertNotNull(receiver.awaitForBroadcast(VPN_ON_START_TIMEOUT_MS)); 172 173 // Make VPN workable again and restart. 174 mDevicePolicyManager.setApplicationRestrictions( 175 ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE, null); 176 VpnTestHelper.waitForVpn(mContext, VPN_PACKAGE, 177 /* usable */ true, /* lockdown */ true, /* allowlist */ true); 178 179 // Now we should be on VPN. 180 VpnTestHelper.checkPing(TEST_ADDRESS); 181 182 receiver.unregisterQuietly(); 183 } 184 testSetNonVpnAlwaysOn()185 public void testSetNonVpnAlwaysOn() throws Exception { 186 // Treat this CTS DPC as an non-vpn app, since it doesn't register 187 // android.net.VpnService intent filter in AndroidManifest.xml. 188 try { 189 mDevicePolicyManager.setAlwaysOnVpnPackage( 190 ADMIN_RECEIVER_COMPONENT, mPackageName, true); 191 fail("setAlwaysOnVpnPackage should not accept non-vpn package"); 192 } catch (UnsupportedOperationException e) { 193 // success 194 } 195 assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT)); 196 } 197 waitForConnectivity(String message)198 private void waitForConnectivity(String message) throws InterruptedException { 199 long deadline = System.nanoTime() + CONNECTIVITY_WAIT_TIME_NS; 200 while (System.nanoTime() < deadline) { 201 try { 202 new Socket(CONNECTIVITY_CHECK_HOST, 80); 203 // Domain resolved, we have connectivity. 204 return; 205 } catch (IOException e) { 206 // Log.e(String, String, Throwable) will swallow UnknownHostException, 207 // so manually print it out here. 208 Log.e(TAG, "No connectivity yet: " + e.toString()); 209 Thread.sleep(2000); 210 } 211 } 212 fail("Connectivity isn't available: " + message); 213 } 214 waitForNoConnectivity(String message)215 private void waitForNoConnectivity(String message) throws Exception { 216 long deadline = System.nanoTime() + CONNECTIVITY_WAIT_TIME_NS; 217 while (System.nanoTime() < deadline) { 218 try { 219 new Socket(CONNECTIVITY_CHECK_HOST, 80); 220 // Domain resolved, we have connectivity. 221 } catch (IOException e) { 222 // No connectivity 223 return; 224 } 225 Thread.sleep(2000); 226 } 227 fail("Connectivity still available after deadline: " + message); 228 } 229 assertConnectivity(boolean shouldHaveConnectivity, String message)230 private void assertConnectivity(boolean shouldHaveConnectivity, String message) { 231 try { 232 new Socket(CONNECTIVITY_CHECK_HOST, 80); 233 if (!shouldHaveConnectivity) { 234 fail("Connectivity available while not expected: " + message); 235 } 236 } catch (IOException e) { 237 if (shouldHaveConnectivity) { 238 Log.e(TAG, "Connectivity check failed", e); 239 fail("Connectivity isn't available while expected: " + message); 240 } 241 } 242 } 243 } 244