1 /* 2 * Copyright (C) 2017 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 android.net; 18 19 import static android.system.OsConstants.AF_INET; 20 import static android.system.OsConstants.IPPROTO_UDP; 21 import static android.system.OsConstants.SOCK_DGRAM; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.fail; 26 import static org.mockito.Matchers.anyInt; 27 import static org.mockito.Matchers.anyObject; 28 import static org.mockito.Matchers.anyString; 29 import static org.mockito.Matchers.eq; 30 import static org.mockito.Mockito.mock; 31 import static org.mockito.Mockito.verify; 32 import static org.mockito.Mockito.when; 33 34 import android.os.Build; 35 import android.system.Os; 36 import android.test.mock.MockContext; 37 38 import androidx.test.filters.SmallTest; 39 40 import com.android.server.IpSecService; 41 import com.android.testutils.DevSdkIgnoreRule; 42 import com.android.testutils.DevSdkIgnoreRunner; 43 44 import org.junit.Before; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 48 import java.net.InetAddress; 49 import java.net.Socket; 50 import java.net.UnknownHostException; 51 52 /** Unit tests for {@link IpSecManager}. */ 53 @SmallTest 54 @RunWith(DevSdkIgnoreRunner.class) 55 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) 56 public class IpSecManagerTest { 57 58 private static final int TEST_UDP_ENCAP_PORT = 34567; 59 private static final int DROID_SPI = 0xD1201D; 60 private static final int DUMMY_RESOURCE_ID = 0x1234; 61 62 private static final InetAddress GOOGLE_DNS_4; 63 private static final String VTI_INTF_NAME = "ipsec_test"; 64 private static final InetAddress VTI_LOCAL_ADDRESS; 65 private static final LinkAddress VTI_INNER_ADDRESS = new LinkAddress("10.0.1.1/24"); 66 67 static { 68 try { 69 // Google Public DNS Addresses; 70 GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8"); 71 VTI_LOCAL_ADDRESS = InetAddress.getByName("8.8.4.4"); 72 } catch (UnknownHostException e) { 73 throw new RuntimeException("Could not resolve DNS Addresses", e); 74 } 75 } 76 77 private IpSecService mMockIpSecService; 78 private IpSecManager mIpSecManager; 79 private MockContext mMockContext = new MockContext() { 80 @Override 81 public String getOpPackageName() { 82 return "fooPackage"; 83 } 84 }; 85 86 @Before setUp()87 public void setUp() throws Exception { 88 mMockIpSecService = mock(IpSecService.class); 89 mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService); 90 } 91 92 /* 93 * Allocate a specific SPI 94 * Close SPIs 95 */ 96 @Test testAllocSpi()97 public void testAllocSpi() throws Exception { 98 IpSecSpiResponse spiResp = 99 new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI); 100 when(mMockIpSecService.allocateSecurityParameterIndex( 101 eq(GOOGLE_DNS_4.getHostAddress()), 102 eq(DROID_SPI), 103 anyObject())) 104 .thenReturn(spiResp); 105 106 IpSecManager.SecurityParameterIndex droidSpi = 107 mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, DROID_SPI); 108 assertEquals(DROID_SPI, droidSpi.getSpi()); 109 110 droidSpi.close(); 111 112 verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID); 113 } 114 115 @Test testAllocRandomSpi()116 public void testAllocRandomSpi() throws Exception { 117 IpSecSpiResponse spiResp = 118 new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI); 119 when(mMockIpSecService.allocateSecurityParameterIndex( 120 eq(GOOGLE_DNS_4.getHostAddress()), 121 eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX), 122 anyObject())) 123 .thenReturn(spiResp); 124 125 IpSecManager.SecurityParameterIndex randomSpi = 126 mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4); 127 128 assertEquals(DROID_SPI, randomSpi.getSpi()); 129 130 randomSpi.close(); 131 132 verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID); 133 } 134 135 /* 136 * Throws resource unavailable exception 137 */ 138 @Test testAllocSpiResUnavailableException()139 public void testAllocSpiResUnavailableException() throws Exception { 140 IpSecSpiResponse spiResp = 141 new IpSecSpiResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE, 0, 0); 142 when(mMockIpSecService.allocateSecurityParameterIndex( 143 anyString(), anyInt(), anyObject())) 144 .thenReturn(spiResp); 145 146 try { 147 mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4); 148 fail("ResourceUnavailableException was not thrown"); 149 } catch (IpSecManager.ResourceUnavailableException e) { 150 } 151 } 152 153 /* 154 * Throws spi unavailable exception 155 */ 156 @Test testAllocSpiSpiUnavailableException()157 public void testAllocSpiSpiUnavailableException() throws Exception { 158 IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.SPI_UNAVAILABLE, 0, 0); 159 when(mMockIpSecService.allocateSecurityParameterIndex( 160 anyString(), anyInt(), anyObject())) 161 .thenReturn(spiResp); 162 163 try { 164 mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4); 165 fail("ResourceUnavailableException was not thrown"); 166 } catch (IpSecManager.ResourceUnavailableException e) { 167 } 168 } 169 170 /* 171 * Should throw exception when request spi 0 in IpSecManager 172 */ 173 @Test testRequestAllocInvalidSpi()174 public void testRequestAllocInvalidSpi() throws Exception { 175 try { 176 mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, 0); 177 fail("Able to allocate invalid spi"); 178 } catch (IllegalArgumentException e) { 179 } 180 } 181 182 @Test testOpenEncapsulationSocket()183 public void testOpenEncapsulationSocket() throws Exception { 184 IpSecUdpEncapResponse udpEncapResp = 185 new IpSecUdpEncapResponse( 186 IpSecManager.Status.OK, 187 DUMMY_RESOURCE_ID, 188 TEST_UDP_ENCAP_PORT, 189 Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)); 190 when(mMockIpSecService.openUdpEncapsulationSocket(eq(TEST_UDP_ENCAP_PORT), anyObject())) 191 .thenReturn(udpEncapResp); 192 193 IpSecManager.UdpEncapsulationSocket encapSocket = 194 mIpSecManager.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT); 195 assertNotNull(encapSocket.getFileDescriptor()); 196 assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort()); 197 198 encapSocket.close(); 199 200 verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID); 201 } 202 203 @Test testApplyTransportModeTransformEnsuresSocketCreation()204 public void testApplyTransportModeTransformEnsuresSocketCreation() throws Exception { 205 Socket socket = new Socket(); 206 IpSecConfig dummyConfig = new IpSecConfig(); 207 IpSecTransform dummyTransform = new IpSecTransform(null, dummyConfig); 208 209 // Even if underlying SocketImpl is not initalized, this should force the init, and 210 // thereby succeed. 211 mIpSecManager.applyTransportModeTransform( 212 socket, IpSecManager.DIRECTION_IN, dummyTransform); 213 214 // Check to make sure the FileDescriptor is non-null 215 assertNotNull(socket.getFileDescriptor$()); 216 } 217 218 @Test testRemoveTransportModeTransformsForcesSocketCreation()219 public void testRemoveTransportModeTransformsForcesSocketCreation() throws Exception { 220 Socket socket = new Socket(); 221 222 // Even if underlying SocketImpl is not initalized, this should force the init, and 223 // thereby succeed. 224 mIpSecManager.removeTransportModeTransforms(socket); 225 226 // Check to make sure the FileDescriptor is non-null 227 assertNotNull(socket.getFileDescriptor$()); 228 } 229 230 @Test testOpenEncapsulationSocketOnRandomPort()231 public void testOpenEncapsulationSocketOnRandomPort() throws Exception { 232 IpSecUdpEncapResponse udpEncapResp = 233 new IpSecUdpEncapResponse( 234 IpSecManager.Status.OK, 235 DUMMY_RESOURCE_ID, 236 TEST_UDP_ENCAP_PORT, 237 Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)); 238 239 when(mMockIpSecService.openUdpEncapsulationSocket(eq(0), anyObject())) 240 .thenReturn(udpEncapResp); 241 242 IpSecManager.UdpEncapsulationSocket encapSocket = 243 mIpSecManager.openUdpEncapsulationSocket(); 244 245 assertNotNull(encapSocket.getFileDescriptor()); 246 assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort()); 247 248 encapSocket.close(); 249 250 verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID); 251 } 252 253 @Test testOpenEncapsulationSocketWithInvalidPort()254 public void testOpenEncapsulationSocketWithInvalidPort() throws Exception { 255 try { 256 mIpSecManager.openUdpEncapsulationSocket(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); 257 fail("IllegalArgumentException was not thrown"); 258 } catch (IllegalArgumentException e) { 259 } 260 } 261 262 // TODO: add test when applicable transform builder interface is available 263 createAndValidateVti(int resourceId, String intfName)264 private IpSecManager.IpSecTunnelInterface createAndValidateVti(int resourceId, String intfName) 265 throws Exception { 266 IpSecTunnelInterfaceResponse dummyResponse = 267 new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName); 268 when(mMockIpSecService.createTunnelInterface( 269 eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()), 270 anyObject(), anyObject(), anyString())) 271 .thenReturn(dummyResponse); 272 273 IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface( 274 VTI_LOCAL_ADDRESS, GOOGLE_DNS_4, mock(Network.class)); 275 276 assertNotNull(tunnelIntf); 277 return tunnelIntf; 278 } 279 280 @Test testCreateVti()281 public void testCreateVti() throws Exception { 282 IpSecManager.IpSecTunnelInterface tunnelIntf = 283 createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME); 284 285 assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName()); 286 287 tunnelIntf.close(); 288 verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString()); 289 } 290 291 @Test testAddRemoveAddressesFromVti()292 public void testAddRemoveAddressesFromVti() throws Exception { 293 IpSecManager.IpSecTunnelInterface tunnelIntf = 294 createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME); 295 296 tunnelIntf.addAddress(VTI_INNER_ADDRESS.getAddress(), 297 VTI_INNER_ADDRESS.getPrefixLength()); 298 verify(mMockIpSecService) 299 .addAddressToTunnelInterface( 300 eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString()); 301 302 tunnelIntf.removeAddress(VTI_INNER_ADDRESS.getAddress(), 303 VTI_INNER_ADDRESS.getPrefixLength()); 304 verify(mMockIpSecService) 305 .addAddressToTunnelInterface( 306 eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString()); 307 } 308 } 309