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 getBluetoothSubAddress()130 private int getBluetoothSubAddress() { 131 final byte[] rawAddress = mBluetoothPrefix.getRawAddress(); 132 int bluetoothSubNet = rawAddress[2] & 0xff; 133 return (bluetoothSubNet << 8) + 0x5; 134 } 135 136 @Test testReserveBluetoothPrefix()137 public void testReserveBluetoothPrefix() throws Exception { 138 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(getBluetoothSubAddress()); 139 LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( 140 mHotspotIpServer); 141 final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); 142 assertNotEquals("Should not get reserved prefix: ", mBluetoothPrefix, hotspotPrefix); 143 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 144 } 145 146 @Test testNoConflictDownstreamPrefix()147 public void testNoConflictDownstreamPrefix() throws Exception { 148 final int fakeHotspotSubAddr = 0x2b05; 149 final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); 150 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); 151 LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( 152 mHotspotIpServer); 153 final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); 154 assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); 155 when(mHotspotIpServer.getAddress()).thenReturn(address); 156 157 address = mPrivateAddressCoordinator.requestDownstreamAddress( 158 mUsbIpServer); 159 final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); 160 assertNotEquals(predefinedPrefix, usbPrefix); 161 162 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 163 mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); 164 address = mPrivateAddressCoordinator.requestDownstreamAddress( 165 mUsbIpServer); 166 final IpPrefix allowUseFreePrefix = PrefixUtils.asIpPrefix(address); 167 assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix); 168 } 169 buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6, boolean isMobile)170 private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6, 171 boolean isMobile) { 172 final String testIface; 173 final String testIpv4Address; 174 if (isMobile) { 175 testIface = TEST_MOBILE_IFNAME; 176 testIpv4Address = "10.0.0.1"; 177 } else { 178 testIface = TEST_WIFI_IFNAME; 179 testIpv4Address = "192.168.43.5"; 180 } 181 182 final LinkProperties prop = new LinkProperties(); 183 prop.setInterfaceName(testIface); 184 185 if (withIPv4) { 186 prop.addLinkAddress( 187 new LinkAddress(InetAddresses.parseNumericAddress(testIpv4Address), 188 NetworkConstants.IPV4_ADDR_BITS)); 189 } 190 191 if (withIPv6) { 192 prop.addLinkAddress( 193 new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"), 194 NetworkConstants.RFC7421_PREFIX_LENGTH)); 195 } 196 return prop; 197 } 198 199 @Test testNoConflictUpstreamPrefix()200 public void testNoConflictUpstreamPrefix() throws Exception { 201 final int fakeHotspotSubId = 43; 202 final int fakeHotspotSubAddr = 0x2b05; 203 final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); 204 // Force always get subAddress "43.5" for conflict testing. 205 when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); 206 // 1. Enable hotspot with prefix 192.168.43.0/24 207 final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( 208 mHotspotIpServer); 209 final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr); 210 assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); 211 when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); 212 // 2. Update v6 only mobile network, hotspot prefix should not be removed. 213 List<String> testConflicts; 214 final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true); 215 mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp); 216 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 217 mPrivateAddressCoordinator.removeUpstreamPrefix(mMobileNetwork); 218 // 3. Update v4 only mobile network, hotspot prefix should not be removed. 219 final LinkProperties v4OnlyMobileProp = buildUpstreamLinkProperties(true, false, true); 220 mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4OnlyMobileProp); 221 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 222 // 4. Update v4v6 mobile network, hotspot prefix should not be removed. 223 final LinkProperties v4v6MobileProp = buildUpstreamLinkProperties(true, true, true); 224 mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4v6MobileProp); 225 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 226 // 5. Update v6 only wifi network, hotspot prefix should not be removed. 227 final LinkProperties v6OnlyWifiProp = buildUpstreamLinkProperties(false, true, false); 228 mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v6OnlyWifiProp); 229 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 230 mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); 231 // 6. Update v4 only wifi network, it conflict with hotspot prefix. 232 final LinkProperties v4OnlyWifiProp = buildUpstreamLinkProperties(true, false, false); 233 mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); 234 verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 235 reset(mHotspotIpServer); 236 // 7. Restart hotspot again and its prefix is different previous. 237 mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); 238 final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress( 239 mHotspotIpServer); 240 final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2); 241 assertNotEquals(hotspotPrefix, hotspotPrefix2); 242 when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2); 243 mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); 244 verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 245 // 7. Usb tethering can be enabled and its prefix is different with conflict one. 246 final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress( 247 mUsbIpServer); 248 final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr); 249 assertNotEquals(predefinedPrefix, usbPrefix); 250 assertNotEquals(hotspotPrefix2, usbPrefix); 251 when(mUsbIpServer.getAddress()).thenReturn(usbAddr); 252 // 8. Disable wifi upstream, then wifi's prefix can be selected again. 253 mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); 254 final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress( 255 mEthernetIpServer); 256 final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr); 257 assertEquals(predefinedPrefix, ethPrefix); 258 } 259 } 260