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 
17 package android.net
18 
19 import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
20 import android.net.InvalidPacketException.ERROR_INVALID_PORT
21 import android.net.NattSocketKeepalive.NATT_PORT
22 import android.os.Build
23 import androidx.test.filters.SmallTest
24 import androidx.test.runner.AndroidJUnit4
25 import com.android.testutils.ConnectivityModuleTest
26 import com.android.testutils.DevSdkIgnoreRule
27 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
28 import com.android.testutils.assertEqualBothWays
29 import com.android.testutils.assertParcelingIsLossless
30 import com.android.testutils.parcelingRoundTrip
31 import java.net.Inet6Address
32 import java.net.InetAddress
33 import kotlin.test.assertFailsWith
34 import org.junit.Assert.assertEquals
35 import org.junit.Assert.assertNotEquals
36 import org.junit.Rule
37 import org.junit.Test
38 import org.junit.runner.RunWith
39 
40 @RunWith(AndroidJUnit4::class)
41 @SmallTest
42 class NattKeepalivePacketDataTest {
43     @Rule @JvmField
44     val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
45 
46     private val TEST_PORT = 4243
47     private val TEST_PORT2 = 4244
48     // ::FFFF:1.2.3.4
49     private val SRC_V4_MAPPED_V6_ADDRESS_BYTES = byteArrayOf(
50         0x00.toByte(),
51         0x00.toByte(),
52         0x00.toByte(),
53         0x00.toByte(),
54         0x00.toByte(),
55         0x00.toByte(),
56         0x00.toByte(),
57         0x00.toByte(),
58         0x00.toByte(),
59         0x00.toByte(),
60         0xff.toByte(),
61         0xff.toByte(),
62         0x01.toByte(),
63         0x02.toByte(),
64         0x03.toByte(),
65         0x04.toByte()
66     )
67     private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
68     private val TEST_DST_ADDRV4 = "198.168.0.1".address()
69     private val TEST_ADDRV6 = "2001:db8::1".address()
70     // This constant requires to be an Inet6Address, but InetAddresses.parseNumericAddress() will
71     // convert v4 mapped v6 address into an Inet4Address. So use Inet6Address.getByAddress() to
72     // create the address.
73     private val TEST_ADDRV4MAPPEDV6 = Inet6Address.getByAddress(null /* host */,
74         SRC_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */)
75     private val TEST_ADDRV4 = "1.2.3.4".address()
76 
addressnull77     private fun String.address() = InetAddresses.parseNumericAddress(this)
78     private fun nattKeepalivePacket(
79         srcAddress: InetAddress? = TEST_SRC_ADDRV4,
80         srcPort: Int = TEST_PORT,
81         dstAddress: InetAddress? = TEST_DST_ADDRV4,
82         dstPort: Int = NATT_PORT
83     ) = NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, dstAddress, dstPort)
84 
85     @Test
86     fun testConstructor() {
87         assertFailsWith<InvalidPacketException>(
88             "Dst port is not NATT port should cause exception") {
89             nattKeepalivePacket(dstPort = TEST_PORT)
90         }.let {
91             assertEquals(it.error, ERROR_INVALID_PORT)
92         }
93 
94         assertFailsWith<InvalidPacketException>("A v6 srcAddress should cause exception") {
95             nattKeepalivePacket(srcAddress = TEST_ADDRV6)
96         }.let {
97             assertEquals(it.error, ERROR_INVALID_IP_ADDRESS)
98         }
99 
100         assertFailsWith<InvalidPacketException>("A v6 dstAddress should cause exception") {
101             nattKeepalivePacket(dstAddress = TEST_ADDRV6)
102         }.let {
103             assertEquals(it.error, ERROR_INVALID_IP_ADDRESS)
104         }
105 
106         assertFailsWith<IllegalArgumentException>("Invalid data should cause exception") {
107             parcelingRoundTrip(
108                 NattKeepalivePacketData(TEST_SRC_ADDRV4, TEST_PORT, TEST_DST_ADDRV4, TEST_PORT,
109                     byteArrayOf(12, 31, 22, 44)))
110         }
111     }
112 
113     @Test @IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
testConstructor_afterRnull114     fun testConstructor_afterR() {
115         // v4 mapped v6 will be translated to a v4 address.
116         assertFailsWith<InvalidPacketException> {
117             nattKeepalivePacket(srcAddress = TEST_ADDRV6, dstAddress = TEST_ADDRV4MAPPEDV6)
118         }
119         assertFailsWith<InvalidPacketException> {
120             nattKeepalivePacket(srcAddress = TEST_ADDRV4MAPPEDV6, dstAddress = TEST_ADDRV6)
121         }
122 
123         // Both src and dst address will be v4 after translation, so it won't cause exception.
124         val packet1 = nattKeepalivePacket(
125             dstAddress = TEST_ADDRV4MAPPEDV6, srcAddress = TEST_ADDRV4MAPPEDV6)
126         assertEquals(TEST_ADDRV4, packet1.srcAddress)
127         assertEquals(TEST_ADDRV4, packet1.dstAddress)
128 
129         // Packet with v6 src and v6 dst address is valid.
130         val packet2 = nattKeepalivePacket(srcAddress = TEST_ADDRV6, dstAddress = TEST_ADDRV6)
131         assertEquals(TEST_ADDRV6, packet2.srcAddress)
132         assertEquals(TEST_ADDRV6, packet2.dstAddress)
133     }
134 
135     @Test
testParcelnull136     fun testParcel() {
137         assertParcelingIsLossless(nattKeepalivePacket())
138     }
139 
140     @Test
testEqualsnull141     fun testEquals() {
142         assertEqualBothWays(nattKeepalivePacket(), nattKeepalivePacket())
143         assertNotEquals(nattKeepalivePacket(dstAddress = TEST_SRC_ADDRV4), nattKeepalivePacket())
144         assertNotEquals(nattKeepalivePacket(srcAddress = TEST_DST_ADDRV4), nattKeepalivePacket())
145         // Test src port only because dst port have to be NATT_PORT
146         assertNotEquals(nattKeepalivePacket(srcPort = TEST_PORT2), nattKeepalivePacket())
147     }
148 
149     @Test
testHashCodenull150     fun testHashCode() {
151         assertEquals(nattKeepalivePacket().hashCode(), nattKeepalivePacket().hashCode())
152     }
153 }
154