1 /*
2  * Copyright (C) 2021 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.server.ethernet;
18 
19 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
20 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
21 
22 import static org.junit.Assert.assertThrows;
23 import static org.junit.Assert.fail;
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.ArgumentMatchers.isNull;
28 import static org.mockito.Mockito.doReturn;
29 import static org.mockito.Mockito.doThrow;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.reset;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35 
36 import android.Manifest;
37 import android.annotation.NonNull;
38 import android.content.Context;
39 import android.content.pm.PackageManager;
40 import android.net.EthernetNetworkSpecifier;
41 import android.net.EthernetNetworkUpdateRequest;
42 import android.net.INetworkInterfaceOutcomeReceiver;
43 import android.net.IpConfiguration;
44 import android.net.NetworkCapabilities;
45 import android.net.StringNetworkSpecifier;
46 import android.os.Build;
47 import android.os.Handler;
48 
49 import androidx.test.filters.SmallTest;
50 
51 import com.android.testutils.DevSdkIgnoreRule;
52 import com.android.testutils.DevSdkIgnoreRunner;
53 
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 
58 @SmallTest
59 @RunWith(DevSdkIgnoreRunner.class)
60 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
61 public class EthernetServiceImplTest {
62     private static final String TEST_IFACE = "test123";
63     private static final NetworkCapabilities DEFAULT_CAPS = new NetworkCapabilities.Builder()
64             .addTransportType(TRANSPORT_ETHERNET)
65             .setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE))
66             .build();
67     private static final EthernetNetworkUpdateRequest UPDATE_REQUEST =
68             new EthernetNetworkUpdateRequest.Builder()
69                     .setIpConfiguration(new IpConfiguration())
70                     .setNetworkCapabilities(DEFAULT_CAPS)
71                     .build();
72     private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_CAPABILITIES =
73             new EthernetNetworkUpdateRequest.Builder()
74                     .setIpConfiguration(new IpConfiguration())
75                     .build();
76     private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_IP_CONFIG =
77             new EthernetNetworkUpdateRequest.Builder()
78                     .setNetworkCapabilities(DEFAULT_CAPS)
79                     .build();
80     private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
81     private EthernetServiceImpl mEthernetServiceImpl;
82     private Context mContext;
83     private Handler mHandler;
84     private EthernetTracker mEthernetTracker;
85     private PackageManager mPackageManager;
86 
87     @Before
setup()88     public void setup() {
89         mContext = mock(Context.class);
90         mHandler = mock(Handler.class);
91         mEthernetTracker = mock(EthernetTracker.class);
92         mPackageManager = mock(PackageManager.class);
93         doReturn(mPackageManager).when(mContext).getPackageManager();
94         mEthernetServiceImpl = new EthernetServiceImpl(mContext, mHandler, mEthernetTracker);
95         mEthernetServiceImpl.mStarted.set(true);
96         toggleAutomotiveFeature(true);
97         shouldTrackIface(TEST_IFACE, true);
98     }
99 
toggleAutomotiveFeature(final boolean isEnabled)100     private void toggleAutomotiveFeature(final boolean isEnabled) {
101         doReturn(isEnabled)
102                 .when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
103     }
104 
shouldTrackIface(@onNull final String iface, final boolean shouldTrack)105     private void shouldTrackIface(@NonNull final String iface, final boolean shouldTrack) {
106         doReturn(shouldTrack).when(mEthernetTracker).isTrackingInterface(iface);
107     }
108 
109     @Test
testSetConfigurationRejectsWhenEthNotStarted()110     public void testSetConfigurationRejectsWhenEthNotStarted() {
111         mEthernetServiceImpl.mStarted.set(false);
112         assertThrows(IllegalStateException.class, () -> {
113             mEthernetServiceImpl.setConfiguration("" /* iface */, new IpConfiguration());
114         });
115     }
116 
117     @Test
testUpdateConfigurationRejectsWhenEthNotStarted()118     public void testUpdateConfigurationRejectsWhenEthNotStarted() {
119         mEthernetServiceImpl.mStarted.set(false);
120         assertThrows(IllegalStateException.class, () -> {
121             mEthernetServiceImpl.updateConfiguration(
122                     "" /* iface */, UPDATE_REQUEST, null /* listener */);
123         });
124     }
125 
126     @Test
testEnableInterfaceRejectsWhenEthNotStarted()127     public void testEnableInterfaceRejectsWhenEthNotStarted() {
128         mEthernetServiceImpl.mStarted.set(false);
129         assertThrows(IllegalStateException.class, () -> {
130             mEthernetServiceImpl.enableInterface("" /* iface */, null /* listener */);
131         });
132     }
133 
134     @Test
testDisableInterfaceRejectsWhenEthNotStarted()135     public void testDisableInterfaceRejectsWhenEthNotStarted() {
136         mEthernetServiceImpl.mStarted.set(false);
137         assertThrows(IllegalStateException.class, () -> {
138             mEthernetServiceImpl.disableInterface("" /* iface */, null /* listener */);
139         });
140     }
141 
142     @Test
testUpdateConfigurationRejectsNullIface()143     public void testUpdateConfigurationRejectsNullIface() {
144         assertThrows(NullPointerException.class, () -> {
145             mEthernetServiceImpl.updateConfiguration(null, UPDATE_REQUEST, NULL_LISTENER);
146         });
147     }
148 
149     @Test
testEnableInterfaceRejectsNullIface()150     public void testEnableInterfaceRejectsNullIface() {
151         assertThrows(NullPointerException.class, () -> {
152             mEthernetServiceImpl.enableInterface(null /* iface */, NULL_LISTENER);
153         });
154     }
155 
156     @Test
testDisableInterfaceRejectsNullIface()157     public void testDisableInterfaceRejectsNullIface() {
158         assertThrows(NullPointerException.class, () -> {
159             mEthernetServiceImpl.disableInterface(null /* iface */, NULL_LISTENER);
160         });
161     }
162 
163     @Test
testUpdateConfigurationWithCapabilitiesRejectsWithoutAutomotiveFeature()164     public void testUpdateConfigurationWithCapabilitiesRejectsWithoutAutomotiveFeature() {
165         toggleAutomotiveFeature(false);
166         assertThrows(UnsupportedOperationException.class, () -> {
167             mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
168         });
169     }
170 
171     @Test
testUpdateConfigurationRejectsWithInvalidSpecifierType()172     public void testUpdateConfigurationRejectsWithInvalidSpecifierType() {
173         final StringNetworkSpecifier invalidSpecifierType = new StringNetworkSpecifier("123");
174         final EthernetNetworkUpdateRequest request =
175                 new EthernetNetworkUpdateRequest.Builder()
176                         .setNetworkCapabilities(
177                                 new NetworkCapabilities.Builder()
178                                         .addTransportType(TRANSPORT_ETHERNET)
179                                         .setNetworkSpecifier(invalidSpecifierType)
180                                         .build()
181                         ).build();
182         assertThrows(IllegalArgumentException.class, () -> {
183             mEthernetServiceImpl.updateConfiguration(
184                     "" /* iface */, request, null /* listener */);
185         });
186     }
187 
188     @Test
testUpdateConfigurationRejectsWithInvalidSpecifierName()189     public void testUpdateConfigurationRejectsWithInvalidSpecifierName() {
190         final String ifaceToUpdate = "eth0";
191         final String ifaceOnSpecifier = "wlan0";
192         EthernetNetworkUpdateRequest request =
193                 new EthernetNetworkUpdateRequest.Builder()
194                         .setNetworkCapabilities(
195                                 new NetworkCapabilities.Builder()
196                                         .addTransportType(TRANSPORT_ETHERNET)
197                                         .setNetworkSpecifier(
198                                                 new EthernetNetworkSpecifier(ifaceOnSpecifier))
199                                         .build()
200                         ).build();
201         assertThrows(IllegalArgumentException.class, () -> {
202             mEthernetServiceImpl.updateConfiguration(ifaceToUpdate, request, null /* listener */);
203         });
204     }
205 
206     @Test
testUpdateConfigurationWithCapabilitiesWithAutomotiveFeature()207     public void testUpdateConfigurationWithCapabilitiesWithAutomotiveFeature() {
208         toggleAutomotiveFeature(false);
209         mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_CAPABILITIES,
210                 NULL_LISTENER);
211         verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
212                 eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getIpConfiguration()),
213                 eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getNetworkCapabilities()),
214                 any(EthernetCallback.class));
215     }
216 
denyManageEthPermission()217     private void denyManageEthPermission() {
218         doThrow(new SecurityException("")).when(mContext)
219                 .enforceCallingOrSelfPermission(
220                         eq(Manifest.permission.MANAGE_ETHERNET_NETWORKS), anyString());
221     }
222 
denyManageTestNetworksPermission()223     private void denyManageTestNetworksPermission() {
224         doThrow(new SecurityException("")).when(mContext)
225                 .enforceCallingOrSelfPermission(
226                         eq(Manifest.permission.MANAGE_TEST_NETWORKS), anyString());
227     }
228 
229     @Test
testUpdateConfigurationRejectsWithoutManageEthPermission()230     public void testUpdateConfigurationRejectsWithoutManageEthPermission() {
231         denyManageEthPermission();
232         assertThrows(SecurityException.class, () -> {
233             mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
234         });
235     }
236 
237     @Test
testEnableInterfaceRejectsWithoutManageEthPermission()238     public void testEnableInterfaceRejectsWithoutManageEthPermission() {
239         denyManageEthPermission();
240         assertThrows(SecurityException.class, () -> {
241             mEthernetServiceImpl.enableInterface(TEST_IFACE, NULL_LISTENER);
242         });
243     }
244 
245     @Test
testDisableInterfaceRejectsWithoutManageEthPermission()246     public void testDisableInterfaceRejectsWithoutManageEthPermission() {
247         denyManageEthPermission();
248         assertThrows(SecurityException.class, () -> {
249             mEthernetServiceImpl.disableInterface(TEST_IFACE, NULL_LISTENER);
250         });
251     }
252 
enableTestInterface()253     private void enableTestInterface() {
254         when(mEthernetTracker.isValidTestInterface(eq(TEST_IFACE))).thenReturn(true);
255     }
256 
257     @Test
testUpdateConfigurationRejectsTestRequestWithoutTestPermission()258     public void testUpdateConfigurationRejectsTestRequestWithoutTestPermission() {
259         enableTestInterface();
260         denyManageTestNetworksPermission();
261         assertThrows(SecurityException.class, () -> {
262             mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
263         });
264     }
265 
266     @Test
testEnableInterfaceRejectsTestRequestWithoutTestPermission()267     public void testEnableInterfaceRejectsTestRequestWithoutTestPermission() {
268         enableTestInterface();
269         denyManageTestNetworksPermission();
270         assertThrows(SecurityException.class, () -> {
271             mEthernetServiceImpl.enableInterface(TEST_IFACE, NULL_LISTENER);
272         });
273     }
274 
275     @Test
testDisableInterfaceRejectsTestRequestWithoutTestPermission()276     public void testDisableInterfaceRejectsTestRequestWithoutTestPermission() {
277         enableTestInterface();
278         denyManageTestNetworksPermission();
279         assertThrows(SecurityException.class, () -> {
280             mEthernetServiceImpl.disableInterface(TEST_IFACE, NULL_LISTENER);
281         });
282     }
283 
284     @Test
testUpdateConfiguration()285     public void testUpdateConfiguration() {
286         mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
287         verify(mEthernetTracker).updateConfiguration(
288                 eq(TEST_IFACE),
289                 eq(UPDATE_REQUEST.getIpConfiguration()),
290                 eq(UPDATE_REQUEST.getNetworkCapabilities()),
291                 any(EthernetCallback.class));
292     }
293 
294     @Test
testUpdateConfigurationAddsSpecifierWhenNotSet()295     public void testUpdateConfigurationAddsSpecifierWhenNotSet() {
296         final NetworkCapabilities nc = new NetworkCapabilities.Builder()
297                 .addTransportType(TRANSPORT_ETHERNET).build();
298         final EthernetNetworkUpdateRequest requestSansSpecifier =
299                 new EthernetNetworkUpdateRequest.Builder()
300                         .setNetworkCapabilities(nc)
301                         .build();
302         final NetworkCapabilities ncWithSpecifier = new NetworkCapabilities(nc)
303                 .setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE));
304 
305         mEthernetServiceImpl.updateConfiguration(TEST_IFACE, requestSansSpecifier, NULL_LISTENER);
306         verify(mEthernetTracker).updateConfiguration(
307                 eq(TEST_IFACE),
308                 isNull(),
309                 eq(ncWithSpecifier), any(EthernetCallback.class));
310     }
311 
312     @Test
testEnableInterface()313     public void testEnableInterface() {
314         mEthernetServiceImpl.enableInterface(TEST_IFACE, NULL_LISTENER);
315         verify(mEthernetTracker).setInterfaceEnabled(eq(TEST_IFACE), eq(true),
316                 any(EthernetCallback.class));
317     }
318 
319     @Test
testDisableInterface()320     public void testDisableInterface() {
321         mEthernetServiceImpl.disableInterface(TEST_IFACE, NULL_LISTENER);
322         verify(mEthernetTracker).setInterfaceEnabled(eq(TEST_IFACE), eq(false),
323                 any(EthernetCallback.class));
324     }
325 
326     @Test
testUpdateConfigurationAcceptsTestRequestWithNullCapabilities()327     public void testUpdateConfigurationAcceptsTestRequestWithNullCapabilities() {
328         enableTestInterface();
329         final EthernetNetworkUpdateRequest request =
330                 new EthernetNetworkUpdateRequest
331                         .Builder()
332                         .setIpConfiguration(new IpConfiguration()).build();
333         mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER);
334         verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
335                 eq(request.getIpConfiguration()),
336                 eq(request.getNetworkCapabilities()), any(EthernetCallback.class));
337     }
338 
339     @Test
testUpdateConfigurationAcceptsRequestWithNullIpConfiguration()340     public void testUpdateConfigurationAcceptsRequestWithNullIpConfiguration() {
341         mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_IP_CONFIG,
342                 NULL_LISTENER);
343         verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
344                 eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getIpConfiguration()),
345                 eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getNetworkCapabilities()),
346                 any(EthernetCallback.class));
347     }
348 
349     @Test
testUpdateConfigurationRejectsInvalidTestRequest()350     public void testUpdateConfigurationRejectsInvalidTestRequest() {
351         enableTestInterface();
352         assertThrows(IllegalArgumentException.class, () -> {
353             mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
354         });
355     }
356 
createTestNetworkUpdateRequest()357     private EthernetNetworkUpdateRequest createTestNetworkUpdateRequest() {
358         final NetworkCapabilities nc =  new NetworkCapabilities
359                 .Builder(UPDATE_REQUEST.getNetworkCapabilities())
360                 .addTransportType(TRANSPORT_TEST).build();
361 
362         return new EthernetNetworkUpdateRequest
363                 .Builder(UPDATE_REQUEST)
364                 .setNetworkCapabilities(nc).build();
365     }
366 
367     @Test
testUpdateConfigurationForTestRequestDoesNotRequireAutoOrEthernetPermission()368     public void testUpdateConfigurationForTestRequestDoesNotRequireAutoOrEthernetPermission() {
369         enableTestInterface();
370         toggleAutomotiveFeature(false);
371         denyManageEthPermission();
372         final EthernetNetworkUpdateRequest request = createTestNetworkUpdateRequest();
373 
374         mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER);
375         verify(mEthernetTracker).updateConfiguration(
376                 eq(TEST_IFACE),
377                 eq(request.getIpConfiguration()),
378                 eq(request.getNetworkCapabilities()), any(EthernetCallback.class));
379     }
380 
381     @Test
testEnableInterfaceForTestRequestDoesNotRequireNetPermission()382     public void testEnableInterfaceForTestRequestDoesNotRequireNetPermission() {
383         enableTestInterface();
384         toggleAutomotiveFeature(false);
385         denyManageEthPermission();
386 
387         mEthernetServiceImpl.enableInterface(TEST_IFACE, NULL_LISTENER);
388         verify(mEthernetTracker).setInterfaceEnabled(eq(TEST_IFACE), eq(true),
389                 any(EthernetCallback.class));
390     }
391 
392     @Test
testDisableInterfaceForTestRequestDoesNotRequireAutoOrNetPermission()393     public void testDisableInterfaceForTestRequestDoesNotRequireAutoOrNetPermission() {
394         enableTestInterface();
395         toggleAutomotiveFeature(false);
396         denyManageEthPermission();
397 
398         mEthernetServiceImpl.disableInterface(TEST_IFACE, NULL_LISTENER);
399         verify(mEthernetTracker).setInterfaceEnabled(eq(TEST_IFACE), eq(false),
400                 any(EthernetCallback.class));
401     }
402 
denyPermissions(String... permissions)403     private void denyPermissions(String... permissions) {
404         for (String permission: permissions) {
405             doReturn(PackageManager.PERMISSION_DENIED).when(mContext)
406                     .checkCallingOrSelfPermission(eq(permission));
407         }
408     }
409 
410     @Test
testSetEthernetEnabled()411     public void testSetEthernetEnabled() {
412         denyPermissions(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
413         mEthernetServiceImpl.setEthernetEnabled(true);
414         verify(mEthernetTracker).setEthernetEnabled(true);
415         reset(mEthernetTracker);
416 
417         denyPermissions(Manifest.permission.NETWORK_STACK);
418         mEthernetServiceImpl.setEthernetEnabled(false);
419         verify(mEthernetTracker).setEthernetEnabled(false);
420         reset(mEthernetTracker);
421 
422         denyPermissions(Manifest.permission.NETWORK_SETTINGS);
423         try {
424             mEthernetServiceImpl.setEthernetEnabled(true);
425             fail("Should get SecurityException");
426         } catch (SecurityException e) { }
427         verify(mEthernetTracker, never()).setEthernetEnabled(false);
428     }
429 }
430