blob: 86a0acbd8042e21024fb191e16106d06abb3a4ae [file] [log] [blame]
Junyu Lai626045a2023-08-28 18:49:44 +08001/*
2 * Copyright (C) 2023 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
17package android.net
18
Junyu Laie0031522023-08-29 18:32:57 +080019import android.net.BpfNetMapsConstants.DOZABLE_MATCH
20import android.net.BpfNetMapsConstants.STANDBY_MATCH
Junyu Lai626045a2023-08-28 18:49:44 +080021import android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY
22import android.net.BpfNetMapsUtils.getMatchByFirewallChain
Junyu Laie0031522023-08-29 18:32:57 +080023import android.os.Build.VERSION_CODES
Junyu Lai626045a2023-08-28 18:49:44 +080024import com.android.net.module.util.IBpfMap
25import com.android.net.module.util.Struct.S32
26import com.android.net.module.util.Struct.U32
27import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
28import com.android.testutils.DevSdkIgnoreRunner
29import com.android.testutils.TestBpfMap
Junyu Laie0031522023-08-29 18:32:57 +080030import java.lang.reflect.Modifier
31import kotlin.test.assertEquals
Junyu Lai626045a2023-08-28 18:49:44 +080032import kotlin.test.assertFalse
33import kotlin.test.assertTrue
34import org.junit.Test
35import org.junit.runner.RunWith
36
Junyu Laie0031522023-08-29 18:32:57 +080037private const val TEST_UID1 = 1234
38private const val TEST_UID2 = TEST_UID1 + 1
39private const val NO_IIF = 0
40
Junyu Lai626045a2023-08-28 18:49:44 +080041// pre-T devices does not support Bpf.
42@RunWith(DevSdkIgnoreRunner::class)
Junyu Laie0031522023-08-29 18:32:57 +080043@IgnoreUpTo(VERSION_CODES.S_V2)
Junyu Lai626045a2023-08-28 18:49:44 +080044class BpfNetMapsReaderTest {
45 private val testConfigurationMap: IBpfMap<S32, U32> = TestBpfMap()
46 private val testUidOwnerMap: IBpfMap<S32, UidOwnerValue> = TestBpfMap()
47 private val bpfNetMapsReader = BpfNetMapsReader(
48 TestDependencies(testConfigurationMap, testUidOwnerMap))
49
50 class TestDependencies(
51 private val configMap: IBpfMap<S32, U32>,
52 private val uidOwnerMap: IBpfMap<S32, UidOwnerValue>
53 ) : BpfNetMapsReader.Dependencies() {
54 override fun getConfigurationMap() = configMap
55 override fun getUidOwnerMap() = uidOwnerMap
56 }
57
58 private fun doTestIsChainEnabled(chain: Int) {
59 testConfigurationMap.updateEntry(
60 UID_RULES_CONFIGURATION_KEY,
61 U32(getMatchByFirewallChain(chain))
62 )
63 assertTrue(bpfNetMapsReader.isChainEnabled(chain))
64 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
65 assertFalse(bpfNetMapsReader.isChainEnabled(chain))
66 }
67
68 @Test
69 @Throws(Exception::class)
70 fun testIsChainEnabled() {
71 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE)
72 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY)
73 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_POWERSAVE)
74 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_RESTRICTED)
75 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY)
76 }
Junyu Laie0031522023-08-29 18:32:57 +080077
78 @Test
79 fun testFirewallChainList() {
80 // Verify that when a firewall chain constant is added, it should also be included in
81 // firewall chain list.
82 val declaredChains = ConnectivityManager::class.java.declaredFields.filter {
83 Modifier.isStatic(it.modifiers) && it.name.startsWith("FIREWALL_CHAIN_")
84 }
85 // Verify the size matches, this also verifies no common item in allow and deny chains.
86 assertEquals(BpfNetMapsConstants.ALLOW_CHAINS.size +
87 BpfNetMapsConstants.DENY_CHAINS.size, declaredChains.size)
88 declaredChains.forEach {
89 assertTrue(BpfNetMapsConstants.ALLOW_CHAINS.contains(it.get(null)) ||
90 BpfNetMapsConstants.DENY_CHAINS.contains(it.get(null)))
91 }
92 }
93
94 private fun mockChainEnabled(chain: Int, enabled: Boolean) {
95 val config = testConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).`val`
96 val newConfig = if (enabled) {
97 config or getMatchByFirewallChain(chain)
98 } else {
99 config and getMatchByFirewallChain(chain).inv()
100 }
101 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(newConfig))
102 }
103
104 @Test
105 fun testIsUidNetworkingBlockedByFirewallChains_allowChain() {
106 // With everything disabled by default, verify the return value is false.
107 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
108 assertFalse(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID1))
109
110 // Enable dozable chain but does not provide allowed list. Verify the network is blocked
111 // for all uids.
112 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE, true)
113 assertTrue(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID1))
114 assertTrue(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID2))
115
116 // Add uid1 to dozable allowed list. Verify the network is not blocked for uid1, while
117 // uid2 is blocked.
118 testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, DOZABLE_MATCH))
119 assertFalse(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID1))
120 assertTrue(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID2))
121 }
122
123 @Test
124 fun testIsUidNetworkingBlockedByFirewallChains_denyChain() {
125 // Enable standby chain but does not provide denied list. Verify the network is allowed
126 // for all uids.
127 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
128 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY, true)
129 assertFalse(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID1))
130 assertFalse(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID2))
131
132 // Add uid1 to standby allowed list. Verify the network is blocked for uid1, while
133 // uid2 is not blocked.
134 testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, STANDBY_MATCH))
135 assertTrue(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID1))
136 assertFalse(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID2))
137 }
138
139 @Test
140 fun testIsUidNetworkingBlockedByFirewallChains_blockedWithAllowed() {
141 // Uids blocked by powersave chain but allowed by standby chain, verify the blocking
142 // takes higher priority.
143 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
144 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_POWERSAVE, true)
145 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY, true)
146 assertTrue(bpfNetMapsReader.isUidBlockedByFirewallChains(TEST_UID1))
147 }
Junyu Lai626045a2023-08-28 18:49:44 +0800148}