1 /* 2 * Copyright (C) 2020 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 package com.android.networkstack.tethering; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertNotEquals; 20 import static org.mockito.Mockito.never; 21 import static org.mockito.Mockito.reset; 22 import static org.mockito.Mockito.spy; 23 import static org.mockito.Mockito.verify; 24 import static org.mockito.Mockito.when; 25 26 import android.content.Context; 27 import android.net.ConnectivityManager; 28 import android.net.InetAddresses; 29 import android.net.IpPrefix; 30 import android.net.LinkAddress; 31 import android.net.LinkProperties; 32 import android.net.Network; 33 import android.net.ip.IpServer; 34 import android.net.util.NetworkConstants; 35 import android.net.util.PrefixUtils; 36 37 import androidx.test.filters.SmallTest; 38 import androidx.test.runner.AndroidJUnit4; 39 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.mockito.Mock; 44 import org.mockito.MockitoAnnotations; 45 46 import java.util.List; 47 48 @RunWith(AndroidJUnit4.class) 49 @SmallTest 50 public final class PrivateAddressCoordinatorTest { 51 private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0"; 52 private static final String TEST_WIFI_IFNAME = "test_wlan0"; 53 54 @Mock private IpServer mHotspotIpServer; 55 @Mock private IpServer mUsbIpServer; 56 @Mock private IpServer mEthernetIpServer; 57 @Mock private Context mContext; 58 @Mock private ConnectivityManager mConnectivityMgr; 59 60 private PrivateAddressCoordinator mPrivateAddressCoordinator; 61 private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24"); 62 private final Network mWifiNetwork = new Network(1); 63 private final Network mMobileNetwork = new Network(2); 64 private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork}; 65 66 @Before setUp()67 public void setUp() throws Exception { 68 MockitoAnnotations.initMocks(this); 69 70 when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr); 71 when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks); 72 mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext)); 73 } 74 75 @Test testDownstreamPrefixRequest()76 public void testDownstreamPrefixRequest() throws Exception { 77 LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( 78 mHotspotIpServer); 79 final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); 80 assertNotEquals(hotspotPrefix, mBluetoothPrefix); 81 82 address = mPrivateAddressCoordinator.requestDownstreamAddress( 83 mHotspotIpServer); 84 final IpPrefix testDupRequest = PrefixUtils.asIpPrefix(address); 85 assertNotEquals(hotspotPrefix, testDupRequest); 86 assertNotEquals(mBluetoothPrefix, testDupRequest); 87 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 88 89 address = mPrivateAddressCoordinator.requestDownstreamAddress( 90 mUsbIpServer); 91 final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); 92 assertNotEquals(usbPrefix, mBluetoothPrefix); 93 assertNotEquals(usbPrefix, hotspotPrefix); 94 mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); 95 } 96 97 @Test testRequestDownstreamAddress()98 public void testRequestDownstreamAddress() throws Exception { 99 LinkAddress expectedAddress = new LinkAddress("192.168.43.42/24"); 100 int fakeSubAddr = 0x2b00; 101 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); 102 LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( 103 mHotspotIpServer); 104 assertEquals(actualAddress, expectedAddress); 105 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 106 107 fakeSubAddr = 0x2b01; 108 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); 109 actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( 110 mHotspotIpServer); 111 assertEquals(actualAddress, expectedAddress); 112 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 113 114 fakeSubAddr = 0x2bff; 115 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); 116 actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( 117 mHotspotIpServer); 118 assertEquals(actualAddress, expectedAddress); 119 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 120 121 expectedAddress = new LinkAddress("192.168.43.5/24"); 122 fakeSubAddr = 0x2b05; 123 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); 124 actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( 125 mHotspotIpServer); 126 assertEquals(actualAddress, expectedAddress); 127 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 128 } 129 130 @Test testReserveBluetoothPrefix()131 public void testReserveBluetoothPrefix() throws Exception { 132 final int fakeSubAddr = 0x2c05; 133 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); 134 LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( 135 mHotspotIpServer); 136 final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); 137 assertNotEquals("Should not get reserved prefix: ", mBluetoothPrefix, hotspotPrefix); 138 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 139 } 140 141 @Test testNoConflictDownstreamPrefix()142 public void testNoConflictDownstreamPrefix() throws Exception { 143 final int fakeHotspotSubAddr = 0x2b05; 144 final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); 145 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); 146 LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( 147 mHotspotIpServer); 148 final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); 149 assertEquals("Wrong wifi perfix: ", predefinedPrefix, hotspotPrefix); 150 when(mHotspotIpServer.getAddress()).thenReturn(address); 151 152 address = mPrivateAddressCoordinator.requestDownstreamAddress( 153 mUsbIpServer); 154 final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); 155 assertNotEquals(predefinedPrefix, usbPrefix); 156 157 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 158 mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); 159 address = mPrivateAddressCoordinator.requestDownstreamAddress( 160 mUsbIpServer); 161 final IpPrefix allowUseFreePrefix = PrefixUtils.asIpPrefix(address); 162 assertEquals("Fail to reselect available perfix: ", predefinedPrefix, allowUseFreePrefix); 163 } 164 buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6, boolean isMobile)165 private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6, 166 boolean isMobile) { 167 final String testIface; 168 final String testIpv4Address; 169 if (isMobile) { 170 testIface = TEST_MOBILE_IFNAME; 171 testIpv4Address = "10.0.0.1"; 172 } else { 173 testIface = TEST_WIFI_IFNAME; 174 testIpv4Address = "192.168.43.5"; 175 } 176 177 final LinkProperties prop = new LinkProperties(); 178 prop.setInterfaceName(testIface); 179 180 if (withIPv4) { 181 prop.addLinkAddress( 182 new LinkAddress(InetAddresses.parseNumericAddress(testIpv4Address), 183 NetworkConstants.IPV4_ADDR_BITS)); 184 } 185 186 if (withIPv6) { 187 prop.addLinkAddress( 188 new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"), 189 NetworkConstants.RFC7421_PREFIX_LENGTH)); 190 } 191 return prop; 192 } 193 194 @Test testNoConflictUpstreamPrefix()195 public void testNoConflictUpstreamPrefix() throws Exception { 196 final int fakeHotspotSubId = 43; 197 final int fakeHotspotSubAddr = 0x2b05; 198 final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); 199 // Force always get subAddress "43.5" for conflict testing. 200 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); 201 // 1. Enable hotspot with prefix 192.168.43.0/24 202 final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( 203 mHotspotIpServer); 204 final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr); 205 assertEquals("Wrong wifi perfix: ", predefinedPrefix, hotspotPrefix); 206 when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); 207 // 2. Update v6 only mobile network, hotspot prefix should not be removed. 208 List<String> testConflicts; 209 final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true); 210 mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp); 211 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 212 mPrivateAddressCoordinator.removeUpstreamPrefix(mMobileNetwork); 213 // 3. Update v4 only mobile network, hotspot prefix should not be removed. 214 final LinkProperties v4OnlyMobileProp = buildUpstreamLinkProperties(true, false, true); 215 mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4OnlyMobileProp); 216 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 217 // 4. Update v4v6 mobile network, hotspot prefix should not be removed. 218 final LinkProperties v4v6MobileProp = buildUpstreamLinkProperties(true, true, true); 219 mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4v6MobileProp); 220 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 221 // 5. Update v6 only wifi network, hotspot prefix should not be removed. 222 final LinkProperties v6OnlyWifiProp = buildUpstreamLinkProperties(false, true, false); 223 mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v6OnlyWifiProp); 224 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 225 mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); 226 // 6. Update v4 only wifi network, it conflict with hotspot prefix. 227 final LinkProperties v4OnlyWifiProp = buildUpstreamLinkProperties(true, false, false); 228 mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); 229 verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 230 reset(mHotspotIpServer); 231 // 7. Restart hotspot again and its prefix is different previous. 232 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 233 final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress( 234 mHotspotIpServer); 235 final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2); 236 assertNotEquals(hotspotPrefix, hotspotPrefix2); 237 when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2); 238 mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); 239 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 240 // 7. Usb tethering can be enabled and its prefix is different with conflict one. 241 final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress( 242 mUsbIpServer); 243 final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr); 244 assertNotEquals(predefinedPrefix, usbPrefix); 245 assertNotEquals(hotspotPrefix2, usbPrefix); 246 when(mUsbIpServer.getAddress()).thenReturn(usbAddr); 247 // 8. Disable wifi upstream, then wifi's prefix can be selected again. 248 mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); 249 final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress( 250 mEthernetIpServer); 251 final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr); 252 assertEquals(predefinedPrefix, ethPrefix); 253 } 254 } 255