• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server
18 
19 import android.content.Intent
20 import android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED
21 import android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED
22 import android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED
23 import android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED
24 import android.net.InetAddresses
25 import android.net.LinkProperties
26 import android.os.Build
27 import android.os.Build.VERSION_CODES
28 import androidx.test.filters.SmallTest
29 import com.android.testutils.DevSdkIgnoreRule
30 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
31 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
32 import com.android.testutils.DevSdkIgnoreRunner
33 import com.android.testutils.visibleOnHandlerThread
34 import org.junit.Rule
35 import org.junit.Test
36 import org.junit.runner.RunWith
37 import org.mockito.ArgumentMatchers.anyBoolean
38 import org.mockito.ArgumentMatchers.anyInt
39 import org.mockito.ArgumentMatchers.eq
40 import org.mockito.Mockito.atLeastOnce
41 import org.mockito.Mockito.doReturn
42 import org.mockito.Mockito.inOrder
43 import org.mockito.Mockito.never
44 import org.mockito.Mockito.verify
45 
46 internal val LOCAL_DNS = InetAddresses.parseNumericAddress("224.0.1.2")
47 internal val NON_LOCAL_DNS = InetAddresses.parseNumericAddress("76.76.75.75")
48 
49 private const val IFNAME_1 = "wlan1"
50 private const val IFNAME_2 = "wlan2"
51 private const val PORT_53 = 53
52 private const val PROTOCOL_TCP = 6
53 private const val PROTOCOL_UDP = 17
54 
<lambda>null55 private val lpWithNoLocalDns = LinkProperties().apply {
56     addDnsServer(NON_LOCAL_DNS)
57     interfaceName = IFNAME_1
58 }
59 
<lambda>null60 private val lpWithLocalDns = LinkProperties().apply {
61     addDnsServer(LOCAL_DNS)
62     interfaceName = IFNAME_2
63 }
64 
65 @DevSdkIgnoreRunner.MonitorThreadLeak
66 @RunWith(DevSdkIgnoreRunner::class)
67 @SmallTest
68 @IgnoreUpTo(Build.VERSION_CODES.S_V2) // Bpf only supports in T+.
69 class CSBpfNetMapsTest : CSTest() {
70     @get:Rule
71     val ignoreRule = DevSdkIgnoreRule()
72 
73     @IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
74     @Test
testCSTrackDataSaverBeforeVnull75     fun testCSTrackDataSaverBeforeV() {
76         val inOrder = inOrder(bpfNetMaps)
77         mockDataSaverStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED)
78         inOrder.verify(bpfNetMaps).setDataSaverEnabled(true)
79         mockDataSaverStatus(RESTRICT_BACKGROUND_STATUS_DISABLED)
80         inOrder.verify(bpfNetMaps).setDataSaverEnabled(false)
81         mockDataSaverStatus(RESTRICT_BACKGROUND_STATUS_ENABLED)
82         inOrder.verify(bpfNetMaps).setDataSaverEnabled(true)
83     }
84 
85     // Data Saver Status is updated from platform code in V+.
86     @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
87     @Test
testCSTrackDataSaverAboveUnull88     fun testCSTrackDataSaverAboveU() {
89         listOf(RESTRICT_BACKGROUND_STATUS_WHITELISTED, RESTRICT_BACKGROUND_STATUS_ENABLED,
90             RESTRICT_BACKGROUND_STATUS_DISABLED).forEach {
91             mockDataSaverStatus(it)
92             verify(bpfNetMaps, never()).setDataSaverEnabled(anyBoolean())
93         }
94     }
95 
96     @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
97     @Test
testLocalPrefixesUpdatedInBpfMapnull98     fun testLocalPrefixesUpdatedInBpfMap() {
99         // Connect Wi-Fi network with non-local dns.
100         val wifiAgent = Agent(nc = defaultNc(), lp = lpWithNoLocalDns)
101         wifiAgent.connect()
102 
103         // Verify that block rule is added to BpfMap for local prefixes.
104         verify(bpfNetMaps, atLeastOnce()).addLocalNetAccess(any(), eq(IFNAME_1),
105             any(), eq(0), eq(0), eq(false))
106 
107         wifiAgent.disconnect()
108         val cellAgent = Agent(nc = defaultNc(), lp = lpWithLocalDns)
109         cellAgent.connect()
110 
111         // Verify that block rule is removed from BpfMap for local prefixes.
112         verify(bpfNetMaps, atLeastOnce()).removeLocalNetAccess(any(), eq(IFNAME_1),
113             any(), eq(0), eq(0))
114 
115         cellAgent.disconnect()
116     }
117 
118     @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
119     @Test
testLocalDnsNotUpdatedInBpfMapnull120     fun testLocalDnsNotUpdatedInBpfMap() {
121         // Connect Wi-Fi network with non-local dns.
122         val wifiAgent = Agent(nc = defaultNc(), lp = lpWithNoLocalDns)
123         wifiAgent.connect()
124 
125         // Verify that No allow rule is added to BpfMap since there is no local dns.
126         verify(bpfNetMaps, never()).addLocalNetAccess(any(), any(), any(), any(), any(),
127             eq(true))
128 
129         wifiAgent.disconnect()
130         val cellAgent = Agent(nc = defaultNc(), lp = lpWithLocalDns)
131         cellAgent.connect()
132 
133         // Verify that No allow rule from port 53 is removed on network change
134         // because no dns was added
135         verify(bpfNetMaps, never()).removeLocalNetAccess(eq(192), eq(IFNAME_1),
136             eq(NON_LOCAL_DNS), any(), eq(PORT_53))
137 
138         cellAgent.disconnect()
139     }
140 
141     @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
142     @Test
testLocalDnsUpdatedInBpfMapnull143     fun testLocalDnsUpdatedInBpfMap() {
144         // Connect Wi-Fi network with one local Dns.
145         val wifiAgent = Agent(nc = defaultNc(), lp = lpWithLocalDns)
146         wifiAgent.connect()
147 
148         // Verify that allow rule is added to BpfMap for local dns at port 53,
149         // for TCP(=6) protocol
150         verify(bpfNetMaps, atLeastOnce()).addLocalNetAccess(eq(192), eq(IFNAME_2),
151             eq(LOCAL_DNS), eq(PROTOCOL_TCP), eq(PORT_53), eq(true))
152         // And for UDP(=17) protocol
153         verify(bpfNetMaps, atLeastOnce()).addLocalNetAccess(eq(192), eq(IFNAME_2),
154             eq(LOCAL_DNS), eq(PROTOCOL_UDP), eq(PORT_53), eq(true))
155 
156         wifiAgent.disconnect()
157         val cellAgent = Agent(nc = defaultNc(), lp = lpWithNoLocalDns)
158         cellAgent.connect()
159 
160         // Verify that allow rule is removed for local dns on network change,
161         // for TCP(=6) protocol
162         verify(bpfNetMaps, atLeastOnce()).removeLocalNetAccess(eq(192), eq(IFNAME_2),
163             eq(LOCAL_DNS), eq(PROTOCOL_TCP), eq(PORT_53))
164         // And for UDP(=17) protocol
165         verify(bpfNetMaps, atLeastOnce()).removeLocalNetAccess(eq(192), eq(IFNAME_2),
166             eq(LOCAL_DNS), eq(PROTOCOL_UDP), eq(PORT_53))
167 
168         cellAgent.disconnect()
169     }
170 
mockDataSaverStatusnull171     private fun mockDataSaverStatus(status: Int) {
172         doReturn(status).`when`(context.networkPolicyManager).getRestrictBackgroundStatus(anyInt())
173         // While the production code dispatches the intent on the handler thread,
174         // The test would dispatch the intent in the caller thread. Make it dispatch
175         // on the handler thread to match production behavior.
176         visibleOnHandlerThread(csHandler) {
177             context.sendBroadcast(Intent(ACTION_RESTRICT_BACKGROUND_CHANGED))
178         }
179         waitForIdle()
180     }
181 }
182