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