blob: 258e4224f45a4ec962539cc01a57b1c5877f2430 [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
Junyu Laic3dc5b62023-09-06 19:10:02 +080020import android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH
21import android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH
Junyu Laie0031522023-08-29 18:32:57 +080022import android.net.BpfNetMapsConstants.STANDBY_MATCH
Junyu Lai626045a2023-08-28 18:49:44 +080023import android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY
24import android.net.BpfNetMapsUtils.getMatchByFirewallChain
Junyu Laie0031522023-08-29 18:32:57 +080025import android.os.Build.VERSION_CODES
Junyu Lai626045a2023-08-28 18:49:44 +080026import com.android.net.module.util.IBpfMap
27import com.android.net.module.util.Struct.S32
28import com.android.net.module.util.Struct.U32
29import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
30import com.android.testutils.DevSdkIgnoreRunner
31import com.android.testutils.TestBpfMap
Junyu Laie0031522023-08-29 18:32:57 +080032import java.lang.reflect.Modifier
33import kotlin.test.assertEquals
Junyu Lai626045a2023-08-28 18:49:44 +080034import kotlin.test.assertFalse
35import kotlin.test.assertTrue
36import org.junit.Test
37import org.junit.runner.RunWith
38
Junyu Laie0031522023-08-29 18:32:57 +080039private const val TEST_UID1 = 1234
40private const val TEST_UID2 = TEST_UID1 + 1
Junyu Laic3dc5b62023-09-06 19:10:02 +080041private const val TEST_UID3 = TEST_UID2 + 1
Junyu Laie0031522023-08-29 18:32:57 +080042private const val NO_IIF = 0
43
Junyu Lai626045a2023-08-28 18:49:44 +080044// pre-T devices does not support Bpf.
45@RunWith(DevSdkIgnoreRunner::class)
Junyu Laie0031522023-08-29 18:32:57 +080046@IgnoreUpTo(VERSION_CODES.S_V2)
Junyu Lai626045a2023-08-28 18:49:44 +080047class BpfNetMapsReaderTest {
48 private val testConfigurationMap: IBpfMap<S32, U32> = TestBpfMap()
49 private val testUidOwnerMap: IBpfMap<S32, UidOwnerValue> = TestBpfMap()
50 private val bpfNetMapsReader = BpfNetMapsReader(
51 TestDependencies(testConfigurationMap, testUidOwnerMap))
52
53 class TestDependencies(
54 private val configMap: IBpfMap<S32, U32>,
55 private val uidOwnerMap: IBpfMap<S32, UidOwnerValue>
56 ) : BpfNetMapsReader.Dependencies() {
57 override fun getConfigurationMap() = configMap
58 override fun getUidOwnerMap() = uidOwnerMap
59 }
60
61 private fun doTestIsChainEnabled(chain: Int) {
62 testConfigurationMap.updateEntry(
63 UID_RULES_CONFIGURATION_KEY,
64 U32(getMatchByFirewallChain(chain))
65 )
66 assertTrue(bpfNetMapsReader.isChainEnabled(chain))
67 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
68 assertFalse(bpfNetMapsReader.isChainEnabled(chain))
69 }
70
71 @Test
72 @Throws(Exception::class)
73 fun testIsChainEnabled() {
74 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE)
75 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY)
76 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_POWERSAVE)
77 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_RESTRICTED)
78 doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY)
79 }
Junyu Laie0031522023-08-29 18:32:57 +080080
81 @Test
82 fun testFirewallChainList() {
83 // Verify that when a firewall chain constant is added, it should also be included in
84 // firewall chain list.
85 val declaredChains = ConnectivityManager::class.java.declaredFields.filter {
86 Modifier.isStatic(it.modifiers) && it.name.startsWith("FIREWALL_CHAIN_")
87 }
88 // Verify the size matches, this also verifies no common item in allow and deny chains.
89 assertEquals(BpfNetMapsConstants.ALLOW_CHAINS.size +
90 BpfNetMapsConstants.DENY_CHAINS.size, declaredChains.size)
91 declaredChains.forEach {
92 assertTrue(BpfNetMapsConstants.ALLOW_CHAINS.contains(it.get(null)) ||
93 BpfNetMapsConstants.DENY_CHAINS.contains(it.get(null)))
94 }
95 }
96
97 private fun mockChainEnabled(chain: Int, enabled: Boolean) {
98 val config = testConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).`val`
99 val newConfig = if (enabled) {
100 config or getMatchByFirewallChain(chain)
101 } else {
102 config and getMatchByFirewallChain(chain).inv()
103 }
104 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(newConfig))
105 }
106
Junyu Laic3dc5b62023-09-06 19:10:02 +0800107 fun isUidNetworkingBlocked(uid: Int, metered: Boolean = false, dataSaver: Boolean = false) =
108 bpfNetMapsReader.isUidNetworkingBlocked(uid, metered, dataSaver)
109
Junyu Laie0031522023-08-29 18:32:57 +0800110 @Test
111 fun testIsUidNetworkingBlockedByFirewallChains_allowChain() {
112 // With everything disabled by default, verify the return value is false.
113 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
Junyu Laic3dc5b62023-09-06 19:10:02 +0800114 assertFalse(isUidNetworkingBlocked(TEST_UID1))
Junyu Laie0031522023-08-29 18:32:57 +0800115
116 // Enable dozable chain but does not provide allowed list. Verify the network is blocked
117 // for all uids.
118 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE, true)
Junyu Laic3dc5b62023-09-06 19:10:02 +0800119 assertTrue(isUidNetworkingBlocked(TEST_UID1))
120 assertTrue(isUidNetworkingBlocked(TEST_UID2))
Junyu Laie0031522023-08-29 18:32:57 +0800121
122 // Add uid1 to dozable allowed list. Verify the network is not blocked for uid1, while
123 // uid2 is blocked.
124 testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, DOZABLE_MATCH))
Junyu Laic3dc5b62023-09-06 19:10:02 +0800125 assertFalse(isUidNetworkingBlocked(TEST_UID1))
126 assertTrue(isUidNetworkingBlocked(TEST_UID2))
Junyu Laie0031522023-08-29 18:32:57 +0800127 }
128
129 @Test
130 fun testIsUidNetworkingBlockedByFirewallChains_denyChain() {
131 // Enable standby chain but does not provide denied list. Verify the network is allowed
132 // for all uids.
133 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
134 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY, true)
Junyu Laic3dc5b62023-09-06 19:10:02 +0800135 assertFalse(isUidNetworkingBlocked(TEST_UID1))
136 assertFalse(isUidNetworkingBlocked(TEST_UID2))
Junyu Laie0031522023-08-29 18:32:57 +0800137
138 // Add uid1 to standby allowed list. Verify the network is blocked for uid1, while
139 // uid2 is not blocked.
140 testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, STANDBY_MATCH))
Junyu Laic3dc5b62023-09-06 19:10:02 +0800141 assertTrue(isUidNetworkingBlocked(TEST_UID1))
142 assertFalse(isUidNetworkingBlocked(TEST_UID2))
Junyu Laie0031522023-08-29 18:32:57 +0800143 }
144
145 @Test
146 fun testIsUidNetworkingBlockedByFirewallChains_blockedWithAllowed() {
147 // Uids blocked by powersave chain but allowed by standby chain, verify the blocking
148 // takes higher priority.
149 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
150 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_POWERSAVE, true)
151 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY, true)
Junyu Laic3dc5b62023-09-06 19:10:02 +0800152 assertTrue(isUidNetworkingBlocked(TEST_UID1))
153 }
154
155 @IgnoreUpTo(VERSION_CODES.S_V2)
156 @Test
157 fun testIsUidNetworkingBlockedByDataSaver() {
158 // With everything disabled by default, verify the return value is false.
159 testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
160 assertFalse(isUidNetworkingBlocked(TEST_UID1, metered = true))
161
162 // Add uid1 to penalty box, verify the network is blocked for uid1, while uid2 is not
163 // affected.
164 testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH))
165 assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
166 assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true))
167
168 // Enable data saver, verify the network is blocked for uid1, uid2, but uid3 in happy box
169 // is not affected.
170 testUidOwnerMap.updateEntry(S32(TEST_UID3), UidOwnerValue(NO_IIF, HAPPY_BOX_MATCH))
171 assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true, dataSaver = true))
172 assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true, dataSaver = true))
173 assertFalse(isUidNetworkingBlocked(TEST_UID3, metered = true, dataSaver = true))
174
175 // Add uid1 to happy box as well, verify nothing is changed because penalty box has higher
176 // priority.
177 testUidOwnerMap.updateEntry(
178 S32(TEST_UID1),
179 UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH or HAPPY_BOX_MATCH)
180 )
181 assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true, dataSaver = true))
182 assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true, dataSaver = true))
183 assertFalse(isUidNetworkingBlocked(TEST_UID3, metered = true, dataSaver = true))
184
185 // Enable doze mode, verify uid3 is blocked even if it is in happy box.
186 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE, true)
187 assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true, dataSaver = true))
188 assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true, dataSaver = true))
189 assertTrue(isUidNetworkingBlocked(TEST_UID3, metered = true, dataSaver = true))
190
191 // Disable doze mode and data saver, only uid1 which is in penalty box is blocked.
192 mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE, false)
193 assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
194 assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true))
195 assertFalse(isUidNetworkingBlocked(TEST_UID3, metered = true))
196
197 // Make the network non-metered, nothing is blocked.
198 assertFalse(isUidNetworkingBlocked(TEST_UID1))
199 assertFalse(isUidNetworkingBlocked(TEST_UID2))
200 assertFalse(isUidNetworkingBlocked(TEST_UID3))
Junyu Laie0031522023-08-29 18:32:57 +0800201 }
Junyu Lai626045a2023-08-28 18:49:44 +0800202}