1 /* 2 * Copyright (C) 2024 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.util 18 19 import android.content.Context 20 import android.net.TetheringManager 21 import android.system.Os 22 import com.android.dx.mockito.inline.extended.ExtendedMockito 23 import com.android.net.module.util.HexDump 24 import com.android.testutils.DevSdkIgnoreRule 25 import com.android.testutils.DevSdkIgnoreRunner 26 import java.io.FileDescriptor 27 import java.net.NetworkInterface 28 import kotlin.test.assertEquals 29 import kotlin.test.assertFailsWith 30 import org.junit.After 31 import org.junit.Before 32 import org.junit.Rule 33 import org.junit.Test 34 import org.junit.runner.RunWith 35 import org.mockito.ArgumentCaptor 36 import org.mockito.ArgumentMatchers.any 37 import org.mockito.ArgumentMatchers.eq 38 import org.mockito.Mock 39 import org.mockito.Mockito.doAnswer 40 import org.mockito.Mockito.doReturn 41 import org.mockito.Mockito.framework 42 import org.mockito.Mockito.`when` 43 import org.mockito.MockitoSession 44 import org.mockito.quality.Strictness 45 46 @RunWith(DevSdkIgnoreRunner::class) 47 class RawSocketUtilsTest { 48 @get:Rule 49 val ignoreRule = DevSdkIgnoreRule() 50 companion object { 51 private const val TEST_IFINDEX = 123 52 private const val TEST_IFACENAME = "wlan0" 53 private const val TEST_SRC_MAC = "FFFFFFFFFFFF" 54 private const val TEST_DST_MAC = "1234567890AB" 55 private const val TEST_INVALID_PACKET_IN_HEX = "DEADBEEF" 56 private const val TEST_PACKET_TYPE_IN_HEX = "88A4" 57 private const val TEST_VALID_PACKET_IN_HEX = 58 TEST_DST_MAC + TEST_SRC_MAC + TEST_PACKET_TYPE_IN_HEX 59 } 60 @Mock 61 private lateinit var mockContext: Context 62 @Mock 63 private lateinit var mockTetheringManager: TetheringManager 64 @Mock 65 private lateinit var mockNetworkInterface: NetworkInterface 66 67 // For mocking static methods. 68 private lateinit var mockitoSession: MockitoSession 69 70 @Before setupnull71 fun setup() { 72 mockitoSession = ExtendedMockito.mockitoSession() 73 .mockStatic(Os::class.java) 74 .mockStatic(NetworkInterface::class.java) 75 .mockStatic(SocketUtils::class.java) 76 .initMocks(this) 77 .strictness(Strictness.LENIENT) 78 .startMocking() 79 doReturn(mockTetheringManager).`when`(mockContext) 80 .getSystemService(eq(TetheringManager::class.java)) 81 `when`(NetworkInterface.getByName(any())).thenReturn(mockNetworkInterface) 82 doReturn(TEST_IFINDEX).`when`(mockNetworkInterface).index 83 } 84 85 @After teardownnull86 fun teardown() { 87 mockitoSession.finishMocking() 88 // Clear mocks to prevent from stubs holding instances and cause memory leaks. 89 framework().clearInlineMocks() 90 } 91 92 @Test sendRawPacketDownStream_invalidTetheredInterfacenull93 fun sendRawPacketDownStream_invalidTetheredInterface() { 94 doAnswer { 95 val callback = it.arguments[1] as TetheringManager.TetheringEventCallback 96 callback.onTetheredInterfacesChanged(listOf("eth0")) 97 }.`when`(mockTetheringManager).registerTetheringEventCallback(any(), any()) 98 assertFailsWith<SecurityException> { 99 RawSocketUtils.sendRawPacketDownStream( 100 mockContext, 101 TEST_IFACENAME, 102 TEST_INVALID_PACKET_IN_HEX 103 ) 104 } 105 } 106 107 @Test sendRawPacketDownStream_invalidPacketnull108 fun sendRawPacketDownStream_invalidPacket() { 109 doAnswer { 110 val callback = it.arguments[1] as TetheringManager.TetheringEventCallback 111 callback.onTetheredInterfacesChanged(listOf(TEST_IFACENAME)) 112 }.`when`(mockTetheringManager).registerTetheringEventCallback(any(), any()) 113 114 assertFailsWith<ArrayIndexOutOfBoundsException> { 115 RawSocketUtils.sendRawPacketDownStream( 116 mockContext, 117 TEST_IFACENAME, 118 TEST_INVALID_PACKET_IN_HEX 119 ) 120 } 121 } 122 123 @Test sendRawPacketDownStream_validPacketnull124 fun sendRawPacketDownStream_validPacket() { 125 doAnswer { 126 val callback = it.arguments[1] as TetheringManager.TetheringEventCallback 127 callback.onTetheredInterfacesChanged(listOf(TEST_IFACENAME)) 128 }.`when`(mockTetheringManager).registerTetheringEventCallback(any(), any()) 129 130 RawSocketUtils.sendRawPacketDownStream( 131 mockContext, 132 TEST_IFACENAME, 133 TEST_VALID_PACKET_IN_HEX 134 ) 135 136 // Verify interactions with mocked static methods. 137 val fileDescriptorCaptor = ArgumentCaptor.forClass(FileDescriptor::class.java) 138 val packetDataCaptor = ArgumentCaptor.forClass(ByteArray::class.java) 139 val packetDataLengthCaptor = ArgumentCaptor.forClass(Int::class.java) 140 ExtendedMockito.verify { 141 Os.sendto( 142 fileDescriptorCaptor.capture(), 143 packetDataCaptor.capture(), 144 eq(0), 145 packetDataLengthCaptor.capture(), 146 eq(0), 147 any() 148 ) 149 } 150 assertEquals(TEST_VALID_PACKET_IN_HEX, HexDump.toHexString(packetDataCaptor.value)) 151 assertEquals(TEST_VALID_PACKET_IN_HEX.length / 2, packetDataLengthCaptor.value) 152 // TODO: Verify ifindex and packetType once the members of PacketSocketAddress 153 // can be accessed. 154 ExtendedMockito.verify { SocketUtils.closeSocket(eq(fileDescriptorCaptor.value)) } 155 } 156 } 157