1 /*
<lambda>null2  * 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 com.android.server
18 
19 import android.net.BpfNetMapsConstants.METERED_ALLOW_CHAINS
20 import android.net.BpfNetMapsConstants.METERED_DENY_CHAINS
21 import android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND
22 import android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW
23 import android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER
24 import android.net.ConnectivityManager.FIREWALL_RULE_ALLOW
25 import android.net.ConnectivityManager.FIREWALL_RULE_DEFAULT
26 import android.net.ConnectivityManager.FIREWALL_RULE_DENY
27 import android.os.Build
28 import androidx.test.filters.SmallTest
29 import com.android.server.connectivity.ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN
30 import com.android.testutils.DevSdkIgnoreRule
31 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
32 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
33 import com.android.testutils.DevSdkIgnoreRunner
34 import com.android.testutils.assertThrows
35 import org.junit.Rule
36 import org.junit.Test
37 import org.junit.runner.RunWith
38 import org.mockito.ArgumentMatchers.anyBoolean
39 import org.mockito.ArgumentMatchers.anyInt
40 import org.mockito.Mockito.any
41 import org.mockito.Mockito.clearInvocations
42 import org.mockito.Mockito.never
43 import org.mockito.Mockito.verify
44 
45 @RunWith(DevSdkIgnoreRunner::class)
46 @SmallTest
47 @IgnoreUpTo(Build.VERSION_CODES.S_V2)
48 class CSFirewallChainTest : CSTest() {
49     @get:Rule
50     val ignoreRule = DevSdkIgnoreRule()
51 
52     // Tests for setFirewallChainEnabled on FIREWALL_CHAIN_BACKGROUND
53     @Test
54     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, false)])
55     fun setFirewallChainEnabled_backgroundChainDisabled() {
56         verifySetFirewallChainEnabledOnBackgroundDoesNothing()
57     }
58 
59     @Test
60     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, true)])
61     @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
62     fun setFirewallChainEnabled_backgroundChainEnabled_afterU() {
63         cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true)
64         verify(bpfNetMaps).setChildChain(FIREWALL_CHAIN_BACKGROUND, true)
65 
66         clearInvocations(bpfNetMaps)
67 
68         cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, false)
69         verify(bpfNetMaps).setChildChain(FIREWALL_CHAIN_BACKGROUND, false)
70     }
71 
72     @Test
73     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, true)])
74     @IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
75     fun setFirewallChainEnabled_backgroundChainEnabled_uptoU() {
76         verifySetFirewallChainEnabledOnBackgroundDoesNothing()
77     }
78 
79     private fun verifySetFirewallChainEnabledOnBackgroundDoesNothing() {
80         cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true)
81         verify(bpfNetMaps, never()).setChildChain(anyInt(), anyBoolean())
82 
83         cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, false)
84         verify(bpfNetMaps, never()).setChildChain(anyInt(), anyBoolean())
85     }
86 
87     // Tests for replaceFirewallChain on FIREWALL_CHAIN_BACKGROUND
88     @Test
89     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, false)])
90     fun replaceFirewallChain_backgroundChainDisabled() {
91         verifyReplaceFirewallChainOnBackgroundDoesNothing()
92     }
93 
94     @Test
95     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, true)])
96     @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
97     fun replaceFirewallChain_backgroundChainEnabled_afterU() {
98         val uids = intArrayOf(53, 42, 79)
99         cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, uids)
100         verify(bpfNetMaps).replaceUidChain(FIREWALL_CHAIN_BACKGROUND, uids)
101     }
102 
103     @Test
104     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, true)])
105     @IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
106     fun replaceFirewallChain_backgroundChainEnabled_uptoU() {
107         verifyReplaceFirewallChainOnBackgroundDoesNothing()
108     }
109 
110     private fun verifyReplaceFirewallChainOnBackgroundDoesNothing() {
111         val uids = intArrayOf(53, 42, 79)
112         cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, uids)
113         verify(bpfNetMaps, never()).replaceUidChain(anyInt(), any(IntArray::class.java))
114     }
115 
116     // Tests for setUidFirewallRule on FIREWALL_CHAIN_BACKGROUND
117     @Test
118     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, false)])
119     fun setUidFirewallRule_backgroundChainDisabled() {
120         verifySetUidFirewallRuleOnBackgroundDoesNothing()
121     }
122 
123     @Test
124     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, true)])
125     @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
126     fun setUidFirewallRule_backgroundChainEnabled_afterU() {
127         val uid = 2345
128 
129         cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DEFAULT)
130         verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY)
131 
132         clearInvocations(bpfNetMaps)
133 
134         cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY)
135         verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY)
136 
137         clearInvocations(bpfNetMaps)
138 
139         cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_ALLOW)
140         verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_ALLOW)
141     }
142 
143     @Test
144     @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, true)])
145     @IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
146     fun setUidFirewallRule_backgroundChainEnabled_uptoU() {
147         verifySetUidFirewallRuleOnBackgroundDoesNothing()
148     }
149 
150     private fun verifySetUidFirewallRuleOnBackgroundDoesNothing() {
151         val uid = 2345
152 
153         listOf(FIREWALL_RULE_DEFAULT, FIREWALL_RULE_ALLOW, FIREWALL_RULE_DENY).forEach { rule ->
154             cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, rule)
155             verify(bpfNetMaps, never()).setUidRule(anyInt(), anyInt(), anyInt())
156         }
157     }
158 
159     @Test
160     fun testSetFirewallChainEnabled_meteredChain() {
161         (METERED_ALLOW_CHAINS + METERED_DENY_CHAINS).forEach {
162             assertThrows(UnsupportedOperationException::class.java) {
163                 cm.setFirewallChainEnabled(it, true)
164             }
165             assertThrows(UnsupportedOperationException::class.java) {
166                 cm.setFirewallChainEnabled(it, false)
167             }
168         }
169     }
170 
171     @Test
172     fun testAddUidToMeteredNetworkAllowList() {
173         val uid = 1001
174         cm.addUidToMeteredNetworkAllowList(uid)
175         verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_ALLOW)
176     }
177 
178     @Test
179     fun testRemoveUidFromMeteredNetworkAllowList() {
180         val uid = 1001
181         cm.removeUidFromMeteredNetworkAllowList(uid)
182         verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_DENY)
183     }
184 
185     @Test
186     fun testAddUidToMeteredNetworkDenyList() {
187         val uid = 1001
188         cm.addUidToMeteredNetworkDenyList(uid)
189         verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DENY)
190     }
191 
192     @Test
193     fun testRemoveUidFromMeteredNetworkDenyList() {
194         val uid = 1001
195         cm.removeUidFromMeteredNetworkDenyList(uid)
196         verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_ALLOW)
197     }
198 }
199