blob: 2cae2509026cb95d16be3ef761c14b8f42f5de51 [file] [log] [blame]
Robin Lee4d03abc2016-05-09 12:32:27 +01001/*
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
17package com.android.server.connectivity;
18
19import static android.content.pm.UserInfo.FLAG_ADMIN;
20import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
21import static android.content.pm.UserInfo.FLAG_PRIMARY;
22import static android.content.pm.UserInfo.FLAG_RESTRICTED;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060023import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
24import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +090025import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060026import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
27import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
28import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
29import static android.net.NetworkCapabilities.TRANSPORT_VPN;
30import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
Rubin Xuc63e48d2019-02-19 16:56:47 +000031import static android.net.RouteInfo.RTN_UNREACHABLE;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060032
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090033import static org.junit.Assert.assertEquals;
34import static org.junit.Assert.assertFalse;
35import static org.junit.Assert.assertTrue;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060036import static org.mockito.AdditionalMatchers.aryEq;
37import static org.mockito.ArgumentMatchers.any;
38import static org.mockito.ArgumentMatchers.anyBoolean;
39import static org.mockito.ArgumentMatchers.anyInt;
40import static org.mockito.ArgumentMatchers.anyString;
41import static org.mockito.ArgumentMatchers.eq;
42import static org.mockito.Mockito.atLeastOnce;
43import static org.mockito.Mockito.doAnswer;
44import static org.mockito.Mockito.doNothing;
45import static org.mockito.Mockito.inOrder;
46import static org.mockito.Mockito.times;
47import static org.mockito.Mockito.verify;
48import static org.mockito.Mockito.when;
Robin Lee4d03abc2016-05-09 12:32:27 +010049
50import android.annotation.UserIdInt;
Robin Lee17e61832016-05-09 13:46:28 +010051import android.app.AppOpsManager;
Tony Makde7f7d12016-06-30 11:19:20 +010052import android.app.NotificationManager;
Robin Lee4d03abc2016-05-09 12:32:27 +010053import android.content.Context;
Robin Leeb8c2a2b2017-03-10 16:17:06 +000054import android.content.pm.ApplicationInfo;
Robin Lee4d03abc2016-05-09 12:32:27 +010055import android.content.pm.PackageManager;
Charles Hea0a87e82017-05-15 17:07:18 +010056import android.content.pm.ResolveInfo;
57import android.content.pm.ServiceInfo;
Robin Lee4d03abc2016-05-09 12:32:27 +010058import android.content.pm.UserInfo;
Charles Hec17f50f2017-08-16 13:14:13 +010059import android.content.res.Resources;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060060import android.net.ConnectivityManager;
Chalard Jeanadbf1d02018-02-26 11:52:46 +090061import android.net.IpPrefix;
62import android.net.LinkProperties;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060063import android.net.Network;
64import android.net.NetworkCapabilities;
Tony Makde7f7d12016-06-30 11:19:20 +010065import android.net.NetworkInfo.DetailedState;
Chalard Jeanadbf1d02018-02-26 11:52:46 +090066import android.net.RouteInfo;
Robin Lee4d03abc2016-05-09 12:32:27 +010067import android.net.UidRange;
Charles Hea0a87e82017-05-15 17:07:18 +010068import android.net.VpnService;
69import android.os.Build.VERSION_CODES;
70import android.os.Bundle;
Robin Lee4d03abc2016-05-09 12:32:27 +010071import android.os.INetworkManagementService;
72import android.os.Looper;
Chalard Jeane0d26f62018-03-29 14:10:44 +090073import android.os.SystemClock;
Robin Lee4d03abc2016-05-09 12:32:27 +010074import android.os.UserHandle;
75import android.os.UserManager;
Robin Lee4d03abc2016-05-09 12:32:27 +010076import android.util.ArrayMap;
77import android.util.ArraySet;
78
Brett Chabot1ae2aa62019-03-04 14:14:56 -080079import androidx.test.filters.SmallTest;
80import androidx.test.runner.AndroidJUnit4;
81
Charles Hec17f50f2017-08-16 13:14:13 +010082import com.android.internal.R;
Robin Leec3736bc2017-03-10 16:19:54 +000083import com.android.internal.net.VpnConfig;
84
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090085import org.junit.Before;
86import org.junit.Test;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060087import org.junit.runner.RunWith;
Robin Leeb8c2a2b2017-03-10 16:17:06 +000088import org.mockito.Answers;
Tony Makde7f7d12016-06-30 11:19:20 +010089import org.mockito.InOrder;
Robin Lee4d03abc2016-05-09 12:32:27 +010090import org.mockito.Mock;
91import org.mockito.MockitoAnnotations;
92
Chalard Jeane0d26f62018-03-29 14:10:44 +090093import java.net.Inet4Address;
Rubin Xuc63e48d2019-02-19 16:56:47 +000094import java.net.Inet6Address;
Chalard Jeane0d26f62018-03-29 14:10:44 +090095import java.net.UnknownHostException;
Charles Hea0a87e82017-05-15 17:07:18 +010096import java.util.ArrayList;
97import java.util.Arrays;
98import java.util.Collections;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060099import java.util.HashMap;
Charles Hea0a87e82017-05-15 17:07:18 +0100100import java.util.Map;
101import java.util.Set;
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900102import java.util.stream.Stream;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900103
Robin Lee4d03abc2016-05-09 12:32:27 +0100104/**
105 * Tests for {@link Vpn}.
106 *
107 * Build, install and run with:
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900108 * runtest frameworks-net -c com.android.server.connectivity.VpnTest
Robin Lee4d03abc2016-05-09 12:32:27 +0100109 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900110@RunWith(AndroidJUnit4.class)
111@SmallTest
112public class VpnTest {
Robin Lee4d03abc2016-05-09 12:32:27 +0100113 private static final String TAG = "VpnTest";
114
115 // Mock users
116 static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
117 static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
118 static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
119 static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
120 static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
121 static {
122 restrictedProfileA.restrictedProfileParentId = primaryUser.id;
123 restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
124 managedProfileA.profileGroupId = primaryUser.id;
125 }
126
Robin Lee17e61832016-05-09 13:46:28 +0100127 /**
128 * Names and UIDs for some fake packages. Important points:
129 * - UID is ordered increasing.
130 * - One pair of packages have consecutive UIDs.
131 */
132 static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
133 static final int[] PKG_UIDS = {66, 77, 78, 400};
134
135 // Mock packages
136 static final Map<String, Integer> mPackages = new ArrayMap<>();
137 static {
138 for (int i = 0; i < PKGS.length; i++) {
139 mPackages.put(PKGS[i], PKG_UIDS[i]);
140 }
141 }
142
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000143 @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
Robin Lee4d03abc2016-05-09 12:32:27 +0100144 @Mock private UserManager mUserManager;
145 @Mock private PackageManager mPackageManager;
146 @Mock private INetworkManagementService mNetService;
Robin Lee17e61832016-05-09 13:46:28 +0100147 @Mock private AppOpsManager mAppOps;
Tony Makde7f7d12016-06-30 11:19:20 +0100148 @Mock private NotificationManager mNotificationManager;
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000149 @Mock private Vpn.SystemServices mSystemServices;
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600150 @Mock private ConnectivityManager mConnectivityManager;
Robin Lee4d03abc2016-05-09 12:32:27 +0100151
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900152 @Before
Robin Lee4d03abc2016-05-09 12:32:27 +0100153 public void setUp() throws Exception {
154 MockitoAnnotations.initMocks(this);
Robin Leec3736bc2017-03-10 16:19:54 +0000155
Robin Lee4d03abc2016-05-09 12:32:27 +0100156 when(mContext.getPackageManager()).thenReturn(mPackageManager);
Robin Lee17e61832016-05-09 13:46:28 +0100157 setMockedPackages(mPackages);
Robin Leec3736bc2017-03-10 16:19:54 +0000158
Tony Makde7f7d12016-06-30 11:19:20 +0100159 when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
Robin Lee4d03abc2016-05-09 12:32:27 +0100160 when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
Robin Lee17e61832016-05-09 13:46:28 +0100161 when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
Tony Makde7f7d12016-06-30 11:19:20 +0100162 when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
163 .thenReturn(mNotificationManager);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600164 when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
165 .thenReturn(mConnectivityManager);
Charles Hec17f50f2017-08-16 13:14:13 +0100166 when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
167 .thenReturn(Resources.getSystem().getString(
168 R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000169
170 // Used by {@link Notification.Builder}
171 ApplicationInfo applicationInfo = new ApplicationInfo();
Charles Hea0a87e82017-05-15 17:07:18 +0100172 applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000173 when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
Varun Anand1215f092019-01-14 11:45:33 -0800174 when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
175 .thenReturn(applicationInfo);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000176
Robin Lee4d03abc2016-05-09 12:32:27 +0100177 doNothing().when(mNetService).registerObserver(any());
178 }
179
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900180 @Test
Robin Lee4d03abc2016-05-09 12:32:27 +0100181 public void testRestrictedProfilesAreAddedToVpn() {
182 setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
183
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000184 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee4d03abc2016-05-09 12:32:27 +0100185 final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
186 null, null);
187
188 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
189 UidRange.createForUser(primaryUser.id),
190 UidRange.createForUser(restrictedProfileA.id)
191 })), ranges);
192 }
193
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900194 @Test
Robin Lee4d03abc2016-05-09 12:32:27 +0100195 public void testManagedProfilesAreNotAddedToVpn() {
196 setMockedUsers(primaryUser, managedProfileA);
197
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000198 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee4d03abc2016-05-09 12:32:27 +0100199 final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
200 null, null);
201
202 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
203 UidRange.createForUser(primaryUser.id)
204 })), ranges);
205 }
206
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900207 @Test
Robin Lee4d03abc2016-05-09 12:32:27 +0100208 public void testAddUserToVpnOnlyAddsOneUser() {
209 setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
210
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000211 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee4d03abc2016-05-09 12:32:27 +0100212 final Set<UidRange> ranges = new ArraySet<>();
213 vpn.addUserToRanges(ranges, primaryUser.id, null, null);
214
215 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
216 UidRange.createForUser(primaryUser.id)
217 })), ranges);
218 }
219
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900220 @Test
Robin Lee4d03abc2016-05-09 12:32:27 +0100221 public void testUidWhiteAndBlacklist() throws Exception {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000222 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee4d03abc2016-05-09 12:32:27 +0100223 final UidRange user = UidRange.createForUser(primaryUser.id);
Robin Lee17e61832016-05-09 13:46:28 +0100224 final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
Robin Lee4d03abc2016-05-09 12:32:27 +0100225
226 // Whitelist
227 final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
Robin Lee17e61832016-05-09 13:46:28 +0100228 Arrays.asList(packages), null);
Robin Lee4d03abc2016-05-09 12:32:27 +0100229 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
Robin Lee17e61832016-05-09 13:46:28 +0100230 new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
231 new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
Robin Lee4d03abc2016-05-09 12:32:27 +0100232 })), allow);
233
234 // Blacklist
235 final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
Robin Lee17e61832016-05-09 13:46:28 +0100236 null, Arrays.asList(packages));
Robin Lee4d03abc2016-05-09 12:32:27 +0100237 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
Robin Lee17e61832016-05-09 13:46:28 +0100238 new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
239 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
240 /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
241 new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
Robin Lee4d03abc2016-05-09 12:32:27 +0100242 })), disallow);
243 }
244
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900245 @Test
Pavel Grafovcb3b8952018-12-14 13:51:07 +0000246 public void testGetAlwaysAndOnGetLockDown() throws Exception {
247 final Vpn vpn = createVpn(primaryUser.id);
248
249 // Default state.
250 assertFalse(vpn.getAlwaysOn());
251 assertFalse(vpn.getLockdown());
252
253 // Set always-on without lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000254 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
Pavel Grafovcb3b8952018-12-14 13:51:07 +0000255 assertTrue(vpn.getAlwaysOn());
256 assertFalse(vpn.getLockdown());
257
258 // Set always-on with lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000259 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
Pavel Grafovcb3b8952018-12-14 13:51:07 +0000260 assertTrue(vpn.getAlwaysOn());
261 assertTrue(vpn.getLockdown());
262
263 // Remove always-on configuration.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000264 assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
Pavel Grafovcb3b8952018-12-14 13:51:07 +0000265 assertFalse(vpn.getAlwaysOn());
266 assertFalse(vpn.getLockdown());
267 }
268
269 @Test
Robin Lee17e61832016-05-09 13:46:28 +0100270 public void testLockdownChangingPackage() throws Exception {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000271 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee17e61832016-05-09 13:46:28 +0100272 final UidRange user = UidRange.createForUser(primaryUser.id);
273
274 // Default state.
Tony Makde7f7d12016-06-30 11:19:20 +0100275 assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
Robin Lee17e61832016-05-09 13:46:28 +0100276
277 // Set always-on without lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000278 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
Tony Makde7f7d12016-06-30 11:19:20 +0100279 assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
Robin Lee17e61832016-05-09 13:46:28 +0100280
281 // Set always-on with lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000282 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
Robin Lee17e61832016-05-09 13:46:28 +0100283 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
284 new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
285 new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
286 }));
Tony Makde7f7d12016-06-30 11:19:20 +0100287 assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
288 assertUnblocked(vpn, user.start + PKG_UIDS[1]);
Robin Lee17e61832016-05-09 13:46:28 +0100289
290 // Switch to another app.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000291 assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
Robin Lee17e61832016-05-09 13:46:28 +0100292 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
293 new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
294 new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
295 }));
296 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
297 new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
298 new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
299 }));
Tony Makde7f7d12016-06-30 11:19:20 +0100300 assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
301 assertUnblocked(vpn, user.start + PKG_UIDS[3]);
Robin Lee17e61832016-05-09 13:46:28 +0100302 }
303
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900304 @Test
Pavel Grafova462bcb2019-01-25 08:50:06 +0000305 public void testLockdownWhitelist() throws Exception {
306 final Vpn vpn = createVpn(primaryUser.id);
307 final UidRange user = UidRange.createForUser(primaryUser.id);
308
309 // Set always-on with lockdown and whitelist app PKGS[2] from lockdown.
310 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2])));
311 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
312 new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
313 new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
314 }));
315 assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
316 assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
317
318 // Change whitelisted app to PKGS[3].
319 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3])));
320 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
321 new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
322 }));
323 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
324 new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
325 new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
326 }));
327 assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
328 assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
329
330 // Change the VPN app.
331 assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3])));
332 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
333 new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
334 new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
335 }));
336 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
337 new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
338 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
339 }));
340 assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
341 assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
342
343 // Remove the whitelist.
344 assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
345 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
346 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
347 new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
348 }));
349 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
350 new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
351 }));
352 assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
353 user.start + PKG_UIDS[3]);
354 assertUnblocked(vpn, user.start + PKG_UIDS[0]);
355
356 // Add the whitelist.
357 assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1])));
358 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
359 new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
360 }));
361 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
362 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
363 new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
364 }));
365 assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
366 assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
367
368 // Try whitelisting a package with a comma, should be rejected.
369 assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d")));
370
371 // Pass a non-existent packages in the whitelist, they (and only they) should be ignored.
372 // Whitelisted package should change from PGKS[1] to PKGS[2].
373 assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true,
374 Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
375 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
376 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
377 new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
378 }));
379 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
380 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
381 new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
382 }));
383 }
384
385 @Test
Robin Lee17e61832016-05-09 13:46:28 +0100386 public void testLockdownAddingAProfile() throws Exception {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000387 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee17e61832016-05-09 13:46:28 +0100388 setMockedUsers(primaryUser);
389
390 // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
391 final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name,
392 restrictedProfileA.flags);
393 tempProfile.restrictedProfileParentId = primaryUser.id;
394
395 final UidRange user = UidRange.createForUser(primaryUser.id);
396 final UidRange profile = UidRange.createForUser(tempProfile.id);
397
398 // Set lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000399 assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
Robin Lee17e61832016-05-09 13:46:28 +0100400 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
401 new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
402 new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
403 }));
404
405 // Verify restricted user isn't affected at first.
Tony Makde7f7d12016-06-30 11:19:20 +0100406 assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
Robin Lee17e61832016-05-09 13:46:28 +0100407
408 // Add the restricted user.
409 setMockedUsers(primaryUser, tempProfile);
410 vpn.onUserAdded(tempProfile.id);
411 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
412 new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
413 new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
414 }));
415
416 // Remove the restricted user.
417 tempProfile.partial = true;
418 vpn.onUserRemoved(tempProfile.id);
419 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
420 new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
421 new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
422 }));
423 }
424
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900425 @Test
Robin Leec3736bc2017-03-10 16:19:54 +0000426 public void testLockdownRuleRepeatability() throws Exception {
427 final Vpn vpn = createVpn(primaryUser.id);
428
429 // Given legacy lockdown is already enabled,
430 vpn.setLockdown(true);
431 verify(mNetService, times(1)).setAllowOnlyVpnForUids(
432 eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
433
434 // Enabling legacy lockdown twice should do nothing.
435 vpn.setLockdown(true);
436 verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
437
438 // And disabling should remove the rules exactly once.
439 vpn.setLockdown(false);
440 verify(mNetService, times(1)).setAllowOnlyVpnForUids(
441 eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
442
443 // Removing the lockdown again should have no effect.
444 vpn.setLockdown(false);
445 verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
446 }
447
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900448 @Test
Robin Leec3736bc2017-03-10 16:19:54 +0000449 public void testLockdownRuleReversibility() throws Exception {
450 final Vpn vpn = createVpn(primaryUser.id);
451
452 final UidRange[] entireUser = {
453 UidRange.createForUser(primaryUser.id)
454 };
455 final UidRange[] exceptPkg0 = {
456 new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
457 new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
458 };
459
460 final InOrder order = inOrder(mNetService);
461
462 // Given lockdown is enabled with no package (legacy VPN),
463 vpn.setLockdown(true);
464 order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
465
466 // When a new VPN package is set the rules should change to cover that package.
467 vpn.prepare(null, PKGS[0]);
468 order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
469 order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
470
471 // When that VPN package is unset, everything should be undone again in reverse.
472 vpn.prepare(null, VpnConfig.LEGACY_VPN);
473 order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
474 order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
475 }
476
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900477 @Test
Charles Hea0a87e82017-05-15 17:07:18 +0100478 public void testIsAlwaysOnPackageSupported() throws Exception {
479 final Vpn vpn = createVpn(primaryUser.id);
480
481 ApplicationInfo appInfo = new ApplicationInfo();
482 when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(primaryUser.id)))
483 .thenReturn(appInfo);
484
485 ServiceInfo svcInfo = new ServiceInfo();
486 ResolveInfo resInfo = new ResolveInfo();
487 resInfo.serviceInfo = svcInfo;
488 when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
489 eq(primaryUser.id)))
490 .thenReturn(Collections.singletonList(resInfo));
491
492 // null package name should return false
493 assertFalse(vpn.isAlwaysOnPackageSupported(null));
494
495 // Pre-N apps are not supported
496 appInfo.targetSdkVersion = VERSION_CODES.M;
497 assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
498
499 // N+ apps are supported by default
500 appInfo.targetSdkVersion = VERSION_CODES.N;
501 assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
502
503 // Apps that opt out explicitly are not supported
504 appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
505 Bundle metaData = new Bundle();
Charles He5da5ae32017-08-15 15:30:22 +0100506 metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
Charles Hea0a87e82017-05-15 17:07:18 +0100507 svcInfo.metaData = metaData;
508 assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
509 }
510
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900511 @Test
Tony Makde7f7d12016-06-30 11:19:20 +0100512 public void testNotificationShownForAlwaysOnApp() {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000513 final UserHandle userHandle = UserHandle.of(primaryUser.id);
514 final Vpn vpn = createVpn(primaryUser.id);
Tony Makde7f7d12016-06-30 11:19:20 +0100515 setMockedUsers(primaryUser);
516
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000517 final InOrder order = inOrder(mNotificationManager);
518
Tony Makde7f7d12016-06-30 11:19:20 +0100519 // Don't show a notification for regular disconnected states.
520 vpn.updateState(DetailedState.DISCONNECTED, TAG);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000521 order.verify(mNotificationManager, atLeastOnce())
522 .cancelAsUser(anyString(), anyInt(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100523
524 // Start showing a notification for disconnected once always-on.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000525 vpn.setAlwaysOnPackage(PKGS[0], false, null);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000526 order.verify(mNotificationManager)
527 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100528
529 // Stop showing the notification once connected.
530 vpn.updateState(DetailedState.CONNECTED, TAG);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000531 order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100532
533 // Show the notification if we disconnect again.
534 vpn.updateState(DetailedState.DISCONNECTED, TAG);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000535 order.verify(mNotificationManager)
536 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100537
538 // Notification should be cleared after unsetting always-on package.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000539 vpn.setAlwaysOnPackage(null, false, null);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000540 order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100541 }
542
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600543 @Test
544 public void testCapabilities() {
545 final Vpn vpn = createVpn(primaryUser.id);
546 setMockedUsers(primaryUser);
547
548 final Network mobile = new Network(1);
549 final Network wifi = new Network(2);
550
551 final Map<Network, NetworkCapabilities> networks = new HashMap<>();
Varun Anand1215f092019-01-14 11:45:33 -0800552 networks.put(
553 mobile,
554 new NetworkCapabilities()
555 .addTransportType(TRANSPORT_CELLULAR)
556 .addCapability(NET_CAPABILITY_INTERNET)
557 .addCapability(NET_CAPABILITY_NOT_CONGESTED)
558 .setLinkDownstreamBandwidthKbps(10));
559 networks.put(
560 wifi,
561 new NetworkCapabilities()
562 .addTransportType(TRANSPORT_WIFI)
563 .addCapability(NET_CAPABILITY_INTERNET)
564 .addCapability(NET_CAPABILITY_NOT_METERED)
565 .addCapability(NET_CAPABILITY_NOT_ROAMING)
566 .addCapability(NET_CAPABILITY_NOT_CONGESTED)
567 .setLinkUpstreamBandwidthKbps(20));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600568 setMockedNetworks(networks);
569
570 final NetworkCapabilities caps = new NetworkCapabilities();
571
Varun Anand4fa80e82019-02-06 10:13:38 -0800572 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800573 mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600574 assertTrue(caps.hasTransport(TRANSPORT_VPN));
575 assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
576 assertFalse(caps.hasTransport(TRANSPORT_WIFI));
577 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
578 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
579 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
580 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900581 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600582
Varun Anand4fa80e82019-02-06 10:13:38 -0800583 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800584 mConnectivityManager,
585 new Network[] {mobile},
586 caps,
587 false /* isAlwaysMetered */);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600588 assertTrue(caps.hasTransport(TRANSPORT_VPN));
589 assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
590 assertFalse(caps.hasTransport(TRANSPORT_WIFI));
591 assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
592 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
Varun Anand1215f092019-01-14 11:45:33 -0800593 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600594 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900595 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600596
Varun Anand4fa80e82019-02-06 10:13:38 -0800597 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800598 mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
599 assertTrue(caps.hasTransport(TRANSPORT_VPN));
600 assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
601 assertTrue(caps.hasTransport(TRANSPORT_WIFI));
602 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
603 assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
604 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
605 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
606 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
607
Varun Anand4fa80e82019-02-06 10:13:38 -0800608 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800609 mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600610 assertTrue(caps.hasTransport(TRANSPORT_VPN));
611 assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
612 assertTrue(caps.hasTransport(TRANSPORT_WIFI));
613 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
614 assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
615 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
616 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900617 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600618
Varun Anand4fa80e82019-02-06 10:13:38 -0800619 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800620 mConnectivityManager,
621 new Network[] {mobile, wifi},
622 caps,
623 false /* isAlwaysMetered */);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600624 assertTrue(caps.hasTransport(TRANSPORT_VPN));
625 assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
626 assertTrue(caps.hasTransport(TRANSPORT_WIFI));
627 assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
628 assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
629 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
630 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900631 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600632 }
633
Robin Lee4d03abc2016-05-09 12:32:27 +0100634 /**
Tony Makde7f7d12016-06-30 11:19:20 +0100635 * Mock some methods of vpn object.
Robin Lee4d03abc2016-05-09 12:32:27 +0100636 */
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000637 private Vpn createVpn(@UserIdInt int userId) {
638 return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices);
Tony Makde7f7d12016-06-30 11:19:20 +0100639 }
Robin Lee17e61832016-05-09 13:46:28 +0100640
Tony Makde7f7d12016-06-30 11:19:20 +0100641 private static void assertBlocked(Vpn vpn, int... uids) {
642 for (int uid : uids) {
junyulai8ed89152018-10-25 10:56:17 +0800643 final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid);
644 assertTrue("Uid " + uid + " should be blocked", blocked);
Tony Makde7f7d12016-06-30 11:19:20 +0100645 }
646 }
647
648 private static void assertUnblocked(Vpn vpn, int... uids) {
649 for (int uid : uids) {
junyulai8ed89152018-10-25 10:56:17 +0800650 final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid);
651 assertFalse("Uid " + uid + " should not be blocked", blocked);
Robin Lee17e61832016-05-09 13:46:28 +0100652 }
Robin Lee4d03abc2016-05-09 12:32:27 +0100653 }
654
655 /**
656 * Populate {@link #mUserManager} with a list of fake users.
657 */
658 private void setMockedUsers(UserInfo... users) {
659 final Map<Integer, UserInfo> userMap = new ArrayMap<>();
660 for (UserInfo user : users) {
661 userMap.put(user.id, user);
662 }
663
Robin Lee17e61832016-05-09 13:46:28 +0100664 /**
665 * @see UserManagerService#getUsers(boolean)
666 */
Robin Lee4d03abc2016-05-09 12:32:27 +0100667 doAnswer(invocation -> {
Robin Lee17e61832016-05-09 13:46:28 +0100668 final boolean excludeDying = (boolean) invocation.getArguments()[0];
669 final ArrayList<UserInfo> result = new ArrayList<>(users.length);
670 for (UserInfo ui : users) {
671 if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
672 result.add(ui);
673 }
674 }
675 return result;
676 }).when(mUserManager).getUsers(anyBoolean());
Robin Lee4d03abc2016-05-09 12:32:27 +0100677
678 doAnswer(invocation -> {
679 final int id = (int) invocation.getArguments()[0];
680 return userMap.get(id);
681 }).when(mUserManager).getUserInfo(anyInt());
682
683 doAnswer(invocation -> {
684 final int id = (int) invocation.getArguments()[0];
685 return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
686 }).when(mUserManager).canHaveRestrictedProfile(anyInt());
687 }
688
689 /**
690 * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
691 */
692 private void setMockedPackages(final Map<String, Integer> packages) {
693 try {
694 doAnswer(invocation -> {
695 final String appName = (String) invocation.getArguments()[0];
696 final int userId = (int) invocation.getArguments()[1];
Pavel Grafova462bcb2019-01-25 08:50:06 +0000697 Integer appId = packages.get(appName);
698 if (appId == null) throw new PackageManager.NameNotFoundException(appName);
699 return UserHandle.getUid(userId, appId);
Robin Lee4d03abc2016-05-09 12:32:27 +0100700 }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
701 } catch (Exception e) {
702 }
703 }
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600704
705 private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
706 doAnswer(invocation -> {
707 final Network network = (Network) invocation.getArguments()[0];
708 return networks.get(network);
709 }).when(mConnectivityManager).getNetworkCapabilities(any());
710 }
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900711
712 // Need multiple copies of this, but Java's Stream objects can't be reused or
713 // duplicated.
714 private Stream<String> publicIpV4Routes() {
715 return Stream.of(
716 "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4",
717 "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6",
718 "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
719 "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11",
720 "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
721 "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
722 "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
723 }
724
725 private Stream<String> publicIpV6Routes() {
726 return Stream.of(
727 "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
728 "fe00::/8", "2605:ef80:e:af1d::/64");
729 }
730
731 @Test
732 public void testProvidesRoutesToMostDestinations() {
733 final LinkProperties lp = new LinkProperties();
734
735 // Default route provides routes to all IPv4 destinations.
736 lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
737 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
738
739 // Empty LP provides routes to no destination
740 lp.clear();
741 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
742
743 // All IPv4 routes except for local networks. This is the case most relevant
744 // to this function. It provides routes to almost the entire space.
745 // (clone the stream so that we can reuse it later)
746 publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
747 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
748
749 // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to
750 // provide routes to "most" destinations.
751 lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
752 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
753
754 // Remove the /2 route, which represent a quarter of the available routing space.
755 // This LP does not provides routes to "most" destinations any more.
756 lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
757 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
758
759 lp.clear();
760 publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
761 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
762
763 lp.removeRoute(new RouteInfo(new IpPrefix("::/1")));
764 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
765
766 // V6 does not provide sufficient coverage but v4 does
767 publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
768 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
769
770 // V4 still does
771 lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
772 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
773
774 // V4 does not any more
775 lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
776 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
777
778 // V4 does not, but V6 has sufficient coverage again
779 lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
780 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
Rubin Xuc63e48d2019-02-19 16:56:47 +0000781
782 lp.clear();
783 // V4-unreachable route should not be treated as sufficient coverage
784 lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
785 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
786
787 lp.clear();
788 // V6-unreachable route should not be treated as sufficient coverage
789 lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
790 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900791 }
Chalard Jeane0d26f62018-03-29 14:10:44 +0900792
793 @Test
794 public void testDoesNotLockUpWithTooManyRoutes() {
795 final LinkProperties lp = new LinkProperties();
796 final byte[] ad = new byte[4];
797 // Actually evaluating this many routes under 1500ms is impossible on
798 // current hardware and for some time, as the algorithm is O(n²).
799 // Make sure the system has a safeguard against this and does not
800 // lock up.
801 final int MAX_ROUTES = 4000;
802 final long MAX_ALLOWED_TIME_MS = 1500;
803 for (int i = 0; i < MAX_ROUTES; ++i) {
804 ad[0] = (byte)((i >> 24) & 0xFF);
805 ad[1] = (byte)((i >> 16) & 0xFF);
806 ad[2] = (byte)((i >> 8) & 0xFF);
807 ad[3] = (byte)(i & 0xFF);
808 try {
809 lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
810 } catch (UnknownHostException e) {
811 // UnknownHostException is only thrown for an address of illegal length,
812 // which can't happen in the case above.
813 }
814 }
815 final long start = SystemClock.currentThreadTimeMillis();
816 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
817 final long end = SystemClock.currentThreadTimeMillis();
818 assertTrue(end - start < MAX_ALLOWED_TIME_MS);
819 }
Robin Lee4d03abc2016-05-09 12:32:27 +0100820}