• 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.net.InetAddresses
20 import android.net.LinkAddress
21 import android.net.LinkProperties
22 import android.net.NetworkCapabilities
23 import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
24 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
25 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
26 import android.net.NetworkCapabilities.TRANSPORT_VPN
27 import android.net.NetworkCapabilities.TRANSPORT_WIFI
28 import android.net.NetworkRequest
29 import android.net.VpnManager.TYPE_VPN_OEM
30 import android.net.VpnManager.TYPE_VPN_SERVICE
31 import android.net.VpnManager.TYPE_VPN_LEGACY
32 import android.net.VpnTransportInfo
33 import android.os.Build
34 import androidx.test.filters.SmallTest
35 import com.android.server.connectivity.ConnectivityFlags
36 import com.android.testutils.DevSdkIgnoreRule
37 import com.android.testutils.DevSdkIgnoreRunner
38 import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
39 import com.android.testutils.TestableNetworkCallback
40 import org.junit.Test
41 import org.junit.runner.RunWith
42 import org.mockito.InOrder
43 import org.mockito.Mockito.inOrder
44 import org.mockito.Mockito.never
45 import org.mockito.Mockito.timeout
46 import org.mockito.Mockito.verify
47 
48 private const val VPN_IFNAME = "tun10041"
49 private const val VPN_IFNAME2 = "tun10042"
50 private const val WIFI_IFNAME = "wlan0"
51 private const val TIMEOUT_MS = 1_000L
52 private const val LONG_TIMEOUT_MS = 5_000
53 
<lambda>null54 private fun vpnNc(vpnType: Int = TYPE_VPN_SERVICE) = NetworkCapabilities.Builder().apply {
55     addTransportType(TRANSPORT_VPN)
56     removeCapability(NET_CAPABILITY_NOT_VPN)
57     addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
58     setTransportInfo(
59             VpnTransportInfo(
60                     vpnType,
61                     "MySession12345",
62                     false /* bypassable */,
63                     false /* longLivedTcpConnectionsExpensive */
64             )
65     )
66 }.build()
67 
wifiNcnull68 private fun wifiNc() = NetworkCapabilities.Builder()
69         .addTransportType(TRANSPORT_WIFI)
70         .addCapability(NET_CAPABILITY_INTERNET)
71         .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
72         .build()
73 
74 private fun nr(transport: Int) = NetworkRequest.Builder()
75         .clearCapabilities()
76         .addTransportType(transport).apply {
77             if (transport != TRANSPORT_VPN) {
78                 addCapability(NET_CAPABILITY_NOT_VPN)
79             }
80         }.build()
81 
<lambda>null82 private fun lp(iface: String, vararg linkAddresses: LinkAddress) = LinkProperties().apply {
83     interfaceName = iface
84     for (linkAddress in linkAddresses) {
85         addLinkAddress(linkAddress)
86     }
87 }
88 
89 @RunWith(DevSdkIgnoreRunner::class)
90 @SmallTest
91 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
92 class CSIngressDiscardRuleTests : CSTest() {
93     private val IPV6_ADDRESS = InetAddresses.parseNumericAddress("2001:db8:1::1")
94     private val IPV6_LINK_ADDRESS = LinkAddress(IPV6_ADDRESS, 64)
95     private val IPV6_ADDRESS2 = InetAddresses.parseNumericAddress("2001:db8:1::2")
96     private val IPV6_LINK_ADDRESS2 = LinkAddress(IPV6_ADDRESS2, 64)
97     private val IPV6_ADDRESS3 = InetAddresses.parseNumericAddress("2001:db8:1::3")
98     private val IPV6_LINK_ADDRESS3 = LinkAddress(IPV6_ADDRESS3, 64)
99     private val LOCAL_IPV6_ADDRRESS = InetAddresses.parseNumericAddress("fe80::1234")
100     private val LOCAL_IPV6_LINK_ADDRRESS = LinkAddress(LOCAL_IPV6_ADDRRESS, 64)
101 
verifyNoMoreIngressDiscardRuleChangenull102     fun verifyNoMoreIngressDiscardRuleChange(inorder: InOrder) {
103         inorder.verify(bpfNetMaps, never()).setIngressDiscardRule(any(), any())
104         inorder.verify(bpfNetMaps, never()).removeIngressDiscardRule(any())
105     }
106 
107     @Test
testVpnIngressDiscardRule_UpdateVpnAddressnull108     fun testVpnIngressDiscardRule_UpdateVpnAddress() {
109         // non-VPN network whose address will be not duplicated with VPN address
110         val wifiNc = wifiNc()
111         val wifiLp = lp(WIFI_IFNAME, IPV6_LINK_ADDRESS3)
112         val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
113         wifiAgent.connect()
114 
115         val nr = nr(TRANSPORT_VPN)
116         val cb = TestableNetworkCallback()
117         cm.registerNetworkCallback(nr, cb)
118         val nc = vpnNc()
119         val lp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
120         val agent = Agent(nc = nc, lp = lp)
121         agent.connect()
122         cb.expectAvailableCallbacks(agent.network, validated = false)
123 
124         // IngressDiscardRule is added to the VPN address
125         verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
126         verify(bpfNetMaps, never()).setIngressDiscardRule(LOCAL_IPV6_ADDRRESS, VPN_IFNAME)
127 
128         // The VPN address is changed
129         val newLp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS2, LOCAL_IPV6_LINK_ADDRRESS)
130         agent.sendLinkProperties(newLp)
131         cb.expect<LinkPropertiesChanged>(agent.network)
132 
133         // IngressDiscardRule is removed from the old VPN address and added to the new VPN address
134         verify(bpfNetMaps).removeIngressDiscardRule(IPV6_ADDRESS)
135         verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS2, VPN_IFNAME)
136         verify(bpfNetMaps, never()).setIngressDiscardRule(LOCAL_IPV6_ADDRRESS, VPN_IFNAME)
137 
138         agent.disconnect()
139         verify(bpfNetMaps, timeout(TIMEOUT_MS)).removeIngressDiscardRule(IPV6_ADDRESS2)
140 
141         cm.unregisterNetworkCallback(cb)
142     }
143 
144     @Test
testVpnIngressDiscardRule_UpdateInterfaceNamenull145     fun testVpnIngressDiscardRule_UpdateInterfaceName() {
146         val inorder = inOrder(bpfNetMaps)
147 
148         val nr = nr(TRANSPORT_VPN)
149         val cb = TestableNetworkCallback()
150         cm.registerNetworkCallback(nr, cb)
151         val nc = vpnNc()
152         val lp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
153         val agent = Agent(nc = nc, lp = lp)
154         agent.connect()
155         cb.expectAvailableCallbacks(agent.network, validated = false)
156 
157         // IngressDiscardRule is added to the VPN address
158         inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
159         verifyNoMoreIngressDiscardRuleChange(inorder)
160 
161         // The VPN interface name is changed
162         val newlp = lp(VPN_IFNAME2, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
163         agent.sendLinkProperties(newlp)
164         cb.expect<LinkPropertiesChanged>(agent.network)
165 
166         // IngressDiscardRule is updated with the new interface name
167         inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME2)
168         verifyNoMoreIngressDiscardRuleChange(inorder)
169 
170         agent.disconnect()
171         inorder.verify(bpfNetMaps, timeout(TIMEOUT_MS)).removeIngressDiscardRule(IPV6_ADDRESS)
172 
173         cm.unregisterNetworkCallback(cb)
174     }
175 
176     @Test
testVpnIngressDiscardRule_DuplicatedIpAddress_UpdateVpnAddressnull177     fun testVpnIngressDiscardRule_DuplicatedIpAddress_UpdateVpnAddress() {
178         val inorder = inOrder(bpfNetMaps)
179 
180         val wifiNc = wifiNc()
181         val wifiLp = lp(WIFI_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
182         val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
183         wifiAgent.connect()
184 
185         // IngressDiscardRule is not added to non-VPN interfaces
186         inorder.verify(bpfNetMaps, never()).setIngressDiscardRule(any(), any())
187 
188         val nr = nr(TRANSPORT_VPN)
189         val cb = TestableNetworkCallback()
190         cm.requestNetwork(nr, cb)
191         val vpnNc = vpnNc()
192         val vpnLp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
193         val vpnAgent = Agent(nc = vpnNc, lp = vpnLp)
194         vpnAgent.connect()
195         cb.expectAvailableCallbacks(vpnAgent.network, validated = false)
196 
197         // IngressDiscardRule is not added since the VPN address is duplicated with the Wi-Fi
198         // address
199         inorder.verify(bpfNetMaps, never()).setIngressDiscardRule(any(), any())
200 
201         // The VPN address is changed to a different address from the Wi-Fi interface
202         val newVpnlp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS2, LOCAL_IPV6_LINK_ADDRRESS)
203         vpnAgent.sendLinkProperties(newVpnlp)
204 
205         // IngressDiscardRule is added to the VPN address since the VPN address is not duplicated
206         // with the Wi-Fi address
207         cb.expect<LinkPropertiesChanged>(vpnAgent.network)
208         inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS2, VPN_IFNAME)
209 
210         // The VPN address is changed back to the same address as the Wi-Fi interface
211         vpnAgent.sendLinkProperties(vpnLp)
212         cb.expect<LinkPropertiesChanged>(vpnAgent.network)
213 
214         // IngressDiscardRule for IPV6_ADDRESS2 is removed but IngressDiscardRule for
215         // IPV6_LINK_ADDRESS is not added since Wi-Fi also uses IPV6_LINK_ADDRESS
216         inorder.verify(bpfNetMaps).removeIngressDiscardRule(IPV6_ADDRESS2)
217         verifyNoMoreIngressDiscardRuleChange(inorder)
218 
219         vpnAgent.disconnect()
220         verifyNoMoreIngressDiscardRuleChange(inorder)
221 
222         cm.unregisterNetworkCallback(cb)
223     }
224 
225     @Test
testVpnIngressDiscardRule_DuplicatedIpAddress_UpdateNonVpnAddressnull226     fun testVpnIngressDiscardRule_DuplicatedIpAddress_UpdateNonVpnAddress() {
227         val inorder = inOrder(bpfNetMaps)
228 
229         val vpnNc = vpnNc()
230         val vpnLp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
231         val vpnAgent = Agent(nc = vpnNc, lp = vpnLp)
232         vpnAgent.connect()
233 
234         // IngressDiscardRule is added to the VPN address
235         inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
236         verifyNoMoreIngressDiscardRuleChange(inorder)
237 
238         val nr = nr(TRANSPORT_WIFI)
239         val cb = TestableNetworkCallback()
240         cm.requestNetwork(nr, cb)
241         val wifiNc = wifiNc()
242         val wifiLp = lp(WIFI_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
243         val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
244         wifiAgent.connect()
245         cb.expectAvailableCallbacks(wifiAgent.network, validated = false)
246 
247         // IngressDiscardRule is removed since the VPN address is duplicated with the Wi-Fi address
248         inorder.verify(bpfNetMaps).removeIngressDiscardRule(IPV6_ADDRESS)
249 
250         // The Wi-Fi address is changed to a different address from the VPN interface
251         val newWifilp = lp(WIFI_IFNAME, IPV6_LINK_ADDRESS2, LOCAL_IPV6_LINK_ADDRRESS)
252         wifiAgent.sendLinkProperties(newWifilp)
253         cb.expect<LinkPropertiesChanged>(wifiAgent.network)
254 
255         // IngressDiscardRule is added to the VPN address since the VPN address is not duplicated
256         // with the Wi-Fi address
257         inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
258         verifyNoMoreIngressDiscardRuleChange(inorder)
259 
260         // The Wi-Fi address is changed back to the same address as the VPN interface
261         wifiAgent.sendLinkProperties(wifiLp)
262         cb.expect<LinkPropertiesChanged>(wifiAgent.network)
263 
264         // IngressDiscardRule is removed since the VPN address is duplicated with the Wi-Fi address
265         inorder.verify(bpfNetMaps).removeIngressDiscardRule(IPV6_ADDRESS)
266 
267         // IngressDiscardRule is added to the VPN address since Wi-Fi is disconnected
268         wifiAgent.disconnect()
269         inorder.verify(bpfNetMaps, timeout(TIMEOUT_MS))
270                 .setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
271 
272         vpnAgent.disconnect()
273         inorder.verify(bpfNetMaps, timeout(TIMEOUT_MS)).removeIngressDiscardRule(IPV6_ADDRESS)
274 
275         cm.unregisterNetworkCallback(cb)
276     }
277 
278     @Test
testVpnIngressDiscardRule_UnregisterAfterReplacementnull279     fun testVpnIngressDiscardRule_UnregisterAfterReplacement() {
280         val wifiNc = wifiNc()
281         val wifiLp = lp(WIFI_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
282         val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
283         wifiAgent.connect()
284         wifiAgent.unregisterAfterReplacement(LONG_TIMEOUT_MS)
285         waitForIdle()
286 
287         val vpnNc = vpnNc()
288         val vpnLp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
289         val vpnAgent = Agent(nc = vpnNc, lp = vpnLp)
290         vpnAgent.connect()
291 
292         // IngressDiscardRule is added since the Wi-Fi network is destroyed
293         verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
294 
295         // IngressDiscardRule is removed since the VPN network is destroyed
296         vpnAgent.unregisterAfterReplacement(LONG_TIMEOUT_MS)
297         waitForIdle()
298         verify(bpfNetMaps).removeIngressDiscardRule(IPV6_ADDRESS)
299     }
300 
301     @Test @FeatureFlags([Flag(ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING, false)])
testVpnIngressDiscardRule_FeatureDisablednull302     fun testVpnIngressDiscardRule_FeatureDisabled() {
303         val nr = nr(TRANSPORT_VPN)
304         val cb = TestableNetworkCallback()
305         cm.registerNetworkCallback(nr, cb)
306         val nc = vpnNc()
307         val lp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
308         val agent = Agent(nc = nc, lp = lp)
309         agent.connect()
310         cb.expectAvailableCallbacks(agent.network, validated = false)
311 
312         // IngressDiscardRule should not be added since feature is disabled
313         verify(bpfNetMaps, never()).setIngressDiscardRule(any(), any())
314     }
315 
doTestVpnIngressDiscardRule_VpnTypenull316     fun doTestVpnIngressDiscardRule_VpnType(vpnType: Int, expectAddRule: Boolean) {
317         val nr = nr(TRANSPORT_VPN)
318         val cb = TestableNetworkCallback()
319         cm.registerNetworkCallback(nr, cb)
320         val nc = vpnNc(vpnType)
321         val lp = lp(VPN_IFNAME, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
322         val agent = Agent(nc = nc, lp = lp)
323         agent.connect()
324         cb.expectAvailableCallbacks(agent.network, validated = false)
325 
326         if (expectAddRule) {
327             verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
328         } else {
329             verify(bpfNetMaps, never()).setIngressDiscardRule(any(), any())
330         }
331     }
332 
333     @Test
testVpnIngressDiscardRule_ServiceVpnnull334     fun testVpnIngressDiscardRule_ServiceVpn() {
335         doTestVpnIngressDiscardRule_VpnType(TYPE_VPN_SERVICE, expectAddRule = true)
336     }
337 
338     @Test
testVpnIngressDiscardRule_LegacyVpnnull339     fun testVpnIngressDiscardRule_LegacyVpn() {
340         // IngressDiscardRule should not be added to Legacy VPN
341         doTestVpnIngressDiscardRule_VpnType(TYPE_VPN_LEGACY, expectAddRule = false)
342     }
343 
344     @Test
testVpnIngressDiscardRule_OemVpnnull345     fun testVpnIngressDiscardRule_OemVpn() {
346         // IngressDiscardRule should not be added to OEM VPN
347         doTestVpnIngressDiscardRule_VpnType(TYPE_VPN_OEM, expectAddRule = false)
348     }
349 }
350