1 /* 2 * Copyright (C) 2018 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.TestNetworkManager.TEST_TAP_PREFIX; 20 21 import static com.android.server.ethernet.EthernetTracker.DEFAULT_CAPABILITIES; 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertFalse; 26 import static org.junit.Assert.assertThrows; 27 import static org.junit.Assert.assertTrue; 28 import static org.junit.Assert.fail; 29 import static org.mockito.ArgumentMatchers.anyBoolean; 30 import static org.mockito.ArgumentMatchers.anyString; 31 import static org.mockito.ArgumentMatchers.eq; 32 import static org.mockito.Mockito.doReturn; 33 import static org.mockito.Mockito.verify; 34 35 import android.content.Context; 36 import android.net.INetd; 37 import android.net.InetAddresses; 38 import android.net.IpConfiguration; 39 import android.net.IpConfiguration.IpAssignment; 40 import android.net.IpConfiguration.ProxySettings; 41 import android.net.LinkAddress; 42 import android.net.NetworkCapabilities; 43 import android.net.StaticIpConfiguration; 44 import android.os.Build; 45 import android.os.HandlerThread; 46 import android.os.RemoteException; 47 48 import androidx.test.filters.SmallTest; 49 50 import com.android.server.ethernet.EthernetTracker.EthernetConfigParser; 51 import com.android.testutils.DevSdkIgnoreRule; 52 import com.android.testutils.DevSdkIgnoreRunner; 53 import com.android.testutils.HandlerUtils; 54 55 import org.junit.After; 56 import org.junit.Before; 57 import org.junit.Test; 58 import org.junit.runner.RunWith; 59 import org.mockito.Mock; 60 import org.mockito.MockitoAnnotations; 61 62 import java.net.InetAddress; 63 import java.util.ArrayList; 64 65 @SmallTest 66 @RunWith(DevSdkIgnoreRunner.class) 67 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) 68 public class EthernetTrackerTest { 69 private static final String TEST_IFACE = "test123"; 70 private static final int TIMEOUT_MS = 1_000; 71 private static final String THREAD_NAME = "EthernetServiceThread"; 72 private static final EthernetCallback NULL_CB = new EthernetCallback(null); 73 private EthernetTracker tracker; 74 private HandlerThread mHandlerThread; 75 @Mock private Context mContext; 76 @Mock private EthernetNetworkFactory mFactory; 77 @Mock private INetd mNetd; 78 @Mock private EthernetTracker.Dependencies mDeps; 79 80 @Before setUp()81 public void setUp() throws RemoteException { 82 MockitoAnnotations.initMocks(this); 83 initMockResources(); 84 doReturn(false).when(mFactory).updateInterfaceLinkState(anyString(), anyBoolean()); 85 doReturn(new String[0]).when(mNetd).interfaceGetList(); 86 doReturn(new String[0]).when(mFactory).getAvailableInterfaces(anyBoolean()); 87 mHandlerThread = new HandlerThread(THREAD_NAME); 88 mHandlerThread.start(); 89 tracker = new EthernetTracker(mContext, mHandlerThread.getThreadHandler(), mFactory, mNetd, 90 mDeps); 91 } 92 93 @After cleanUp()94 public void cleanUp() throws InterruptedException { 95 mHandlerThread.quitSafely(); 96 mHandlerThread.join(); 97 } 98 initMockResources()99 private void initMockResources() { 100 doReturn("").when(mDeps).getInterfaceRegexFromResource(eq(mContext)); 101 doReturn(new String[0]).when(mDeps).getInterfaceConfigFromResource(eq(mContext)); 102 } 103 waitForIdle()104 private void waitForIdle() { 105 HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS); 106 } 107 108 /** 109 * Test: Creation of various valid static IP configurations 110 */ 111 @Test createStaticIpConfiguration()112 public void createStaticIpConfiguration() { 113 // Empty gives default StaticIPConfiguration object 114 assertStaticConfiguration(new StaticIpConfiguration(), ""); 115 116 // Setting only the IP address properly cascades and assumes defaults 117 assertStaticConfiguration(new StaticIpConfiguration.Builder() 118 .setIpAddress(new LinkAddress("192.0.2.10/24")).build(), "ip=192.0.2.10/24"); 119 120 final ArrayList<InetAddress> dnsAddresses = new ArrayList<>(); 121 dnsAddresses.add(InetAddresses.parseNumericAddress("4.4.4.4")); 122 dnsAddresses.add(InetAddresses.parseNumericAddress("8.8.8.8")); 123 // Setting other fields properly cascades them 124 assertStaticConfiguration(new StaticIpConfiguration.Builder() 125 .setIpAddress(new LinkAddress("192.0.2.10/24")) 126 .setDnsServers(dnsAddresses) 127 .setGateway(InetAddresses.parseNumericAddress("192.0.2.1")) 128 .setDomains("android").build(), 129 "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android"); 130 131 // Verify order doesn't matter 132 assertStaticConfiguration(new StaticIpConfiguration.Builder() 133 .setIpAddress(new LinkAddress("192.0.2.10/24")) 134 .setDnsServers(dnsAddresses) 135 .setGateway(InetAddresses.parseNumericAddress("192.0.2.1")) 136 .setDomains("android").build(), 137 "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 "); 138 } 139 140 /** 141 * Test: Attempt creation of various bad static IP configurations 142 */ 143 @Test createStaticIpConfiguration_Bad()144 public void createStaticIpConfiguration_Bad() { 145 assertStaticConfigurationFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key 146 assertStaticConfigurationFails("ip=192.0.2.1"); // mask is missing 147 assertStaticConfigurationFails("ip=a.b.c"); // not a valid ip address 148 assertStaticConfigurationFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns 149 assertStaticConfigurationFails("="); // Key and value is empty 150 assertStaticConfigurationFails("ip="); // Value is empty 151 assertStaticConfigurationFails("ip=192.0.2.1/24 gateway="); // Gateway is empty 152 } 153 assertStaticConfigurationFails(String config)154 private void assertStaticConfigurationFails(String config) { 155 try { 156 EthernetTracker.parseStaticIpConfiguration(config); 157 fail("Expected to fail: " + config); 158 } catch (IllegalArgumentException e) { 159 // expected 160 } 161 } 162 assertStaticConfiguration(StaticIpConfiguration expectedStaticIpConfig, String configAsString)163 private void assertStaticConfiguration(StaticIpConfiguration expectedStaticIpConfig, 164 String configAsString) { 165 final IpConfiguration expectedIpConfiguration = new IpConfiguration(); 166 expectedIpConfiguration.setIpAssignment(IpAssignment.STATIC); 167 expectedIpConfiguration.setProxySettings(ProxySettings.NONE); 168 expectedIpConfiguration.setStaticIpConfiguration(expectedStaticIpConfig); 169 170 assertEquals(expectedIpConfiguration, 171 EthernetTracker.parseStaticIpConfiguration(configAsString)); 172 } 173 makeEthernetCapabilitiesBuilder(boolean clearDefaults)174 private NetworkCapabilities.Builder makeEthernetCapabilitiesBuilder(boolean clearDefaults) { 175 final NetworkCapabilities.Builder builder = 176 clearDefaults 177 ? NetworkCapabilities.Builder.withoutDefaultCapabilities() 178 : new NetworkCapabilities.Builder(); 179 return builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 180 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) 181 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); 182 } 183 184 185 @Test testNetworkCapabilityParsing()186 public void testNetworkCapabilityParsing() { 187 final NetworkCapabilities baseNc = NetworkCapabilities.Builder.withoutDefaultCapabilities() 188 .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) 189 .setLinkUpstreamBandwidthKbps(100 * 1000 /* 100 Mbps */) 190 .setLinkDownstreamBandwidthKbps(100 * 1000 /* 100 Mbps */) 191 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 192 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) 193 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 194 .build(); 195 196 // Empty capabilities always default to the baseNc above. 197 EthernetConfigParser p = new EthernetConfigParser("eth0;", false /*isAtLeastB*/); 198 assertThat(p.mCaps).isEqualTo(baseNc); 199 p = new EthernetConfigParser("eth0;", true /*isAtLeastB*/); 200 assertThat(p.mCaps).isEqualTo(baseNc); 201 202 // On Android B+, "*" defaults to using DEFAULT_CAPABILITIES. 203 p = new EthernetConfigParser("eth0;*;;;;;;", true /*isAtLeastB*/); 204 assertThat(p.mCaps).isEqualTo(DEFAULT_CAPABILITIES); 205 206 // But not so before B. 207 p = new EthernetConfigParser("eth0;*", false /*isAtLeastB*/); 208 assertThat(p.mCaps).isEqualTo(baseNc); 209 210 p = new EthernetConfigParser("eth0;12,13,14,15;", false /*isAtLeastB*/); 211 assertThat(p.mCaps.getCapabilities()).asList().containsAtLeast(12, 13, 14, 15); 212 213 p = new EthernetConfigParser("eth0;12,13,500,abc", false /*isAtLeastB*/); 214 // 18, 20, 21 are added by EthernetConfigParser. 215 assertThat(p.mCaps.getCapabilities()).asList().containsExactly(12, 13, 18, 20, 21); 216 217 p = new EthernetConfigParser("eth0;1,2,3;;0", false /*isAtLeastB*/); 218 assertThat(p.mCaps.getCapabilities()).asList().containsAtLeast(1, 2, 3); 219 assertThat(p.mCaps.hasSingleTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue(); 220 221 // TRANSPORT_VPN (4) is not allowed. 222 p = new EthernetConfigParser("eth0;;;4", false /*isAtLeastB*/); 223 assertThat(p.mCaps.hasSingleTransport(NetworkCapabilities.TRANSPORT_ETHERNET)).isTrue(); 224 p = new EthernetConfigParser("eth0;*;;4", true /*isAtLeastB*/); 225 assertThat(p.mCaps.hasSingleTransport(NetworkCapabilities.TRANSPORT_ETHERNET)).isTrue(); 226 227 // invalid capability and transport type 228 p = new EthernetConfigParser("eth0;-1,a,1000,,;;-1", false /*isAtLeastB*/); 229 assertThat(p.mCaps).isEqualTo(baseNc); 230 231 p = new EthernetConfigParser("eth0;*;;0", false /*isAtLeastB*/); 232 assertThat(p.mCaps.hasSingleTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue(); 233 p = new EthernetConfigParser("eth0;*;;0", true /*isAtLeastB*/); 234 assertThat(p.mCaps.hasSingleTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue(); 235 236 NetworkCapabilities nc = new NetworkCapabilities.Builder(DEFAULT_CAPABILITIES) 237 .removeTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) 238 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 239 .build(); 240 p = new EthernetConfigParser("eth0;*;;0", true /*isAtLeastB*/); 241 assertThat(p.mCaps).isEqualTo(nc); 242 } 243 244 @Test testInterfaceNameParsing()245 public void testInterfaceNameParsing() { 246 EthernetConfigParser p = new EthernetConfigParser("eth12", false /*isAtLeastB*/); 247 assertThat(p.mIface).isEqualTo("eth12"); 248 249 p = new EthernetConfigParser("", true /*isAtLeastB*/); 250 assertThat(p.mIface).isEqualTo(""); 251 252 p = new EthernetConfigParser("eth0;12;", true /*isAtLeastB*/); 253 assertThat(p.mIface).isEqualTo("eth0"); 254 } 255 256 @Test testIpConfigParsing()257 public void testIpConfigParsing() { 258 // Note that EthernetConfigParser doesn't actually parse the IpConfig (yet). 259 final EthernetConfigParser p = new EthernetConfigParser( 260 "eth0;1,2,3;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8;1", 261 false /*isAtLeastB*/); 262 assertThat(p.mIpConfig) 263 .isEqualTo("ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8"); 264 } 265 266 @Test testCreateEthernetConfigParserThrowsNpeWithNullInput()267 public void testCreateEthernetConfigParserThrowsNpeWithNullInput() { 268 assertThrows(NullPointerException.class, () -> new EthernetConfigParser(null, false)); 269 } 270 271 @Test testUpdateConfiguration()272 public void testUpdateConfiguration() { 273 final NetworkCapabilities capabilities = new NetworkCapabilities.Builder().build(); 274 final LinkAddress linkAddr = new LinkAddress("192.0.2.2/25"); 275 final StaticIpConfiguration staticIpConfig = 276 new StaticIpConfiguration.Builder().setIpAddress(linkAddr).build(); 277 final IpConfiguration ipConfig = 278 new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); 279 final EthernetCallback listener = new EthernetCallback(null); 280 281 tracker.updateConfiguration(TEST_IFACE, ipConfig, capabilities, listener); 282 waitForIdle(); 283 284 verify(mFactory).updateInterface( 285 eq(TEST_IFACE), eq(ipConfig), eq(capabilities)); 286 } 287 288 @Test testIsValidTestInterfaceIsFalseWhenTestInterfacesAreNotIncluded()289 public void testIsValidTestInterfaceIsFalseWhenTestInterfacesAreNotIncluded() { 290 final String validIfaceName = TEST_TAP_PREFIX + "123"; 291 tracker.setIncludeTestInterfaces(false); 292 waitForIdle(); 293 294 final boolean isValidTestInterface = tracker.isValidTestInterface(validIfaceName); 295 296 assertFalse(isValidTestInterface); 297 } 298 299 @Test testIsValidTestInterfaceIsFalseWhenTestInterfaceNameIsInvalid()300 public void testIsValidTestInterfaceIsFalseWhenTestInterfaceNameIsInvalid() { 301 final String invalidIfaceName = "123" + TEST_TAP_PREFIX; 302 tracker.setIncludeTestInterfaces(true); 303 waitForIdle(); 304 305 final boolean isValidTestInterface = tracker.isValidTestInterface(invalidIfaceName); 306 307 assertFalse(isValidTestInterface); 308 } 309 310 @Test testIsValidTestInterfaceIsTrueWhenTestInterfacesIncludedAndValidName()311 public void testIsValidTestInterfaceIsTrueWhenTestInterfacesIncludedAndValidName() { 312 final String validIfaceName = TEST_TAP_PREFIX + "123"; 313 tracker.setIncludeTestInterfaces(true); 314 waitForIdle(); 315 316 final boolean isValidTestInterface = tracker.isValidTestInterface(validIfaceName); 317 318 assertTrue(isValidTestInterface); 319 } 320 } 321