• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 android.net.vcn.cts;
18 
19 import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
20 
21 import android.annotation.NonNull;
22 import android.content.Context;
23 import android.ipsec.ike.cts.IkeTunUtils;
24 import android.net.ConnectivityManager;
25 import android.net.IpPrefix;
26 import android.net.LinkAddress;
27 import android.net.LinkProperties;
28 import android.net.Network;
29 import android.net.NetworkAgent;
30 import android.net.NetworkAgentConfig;
31 import android.net.NetworkCapabilities;
32 import android.net.NetworkProvider;
33 import android.net.NetworkRequest;
34 import android.net.RouteInfo;
35 import android.net.TestNetworkInterface;
36 import android.net.TestNetworkManager;
37 import android.net.TestNetworkSpecifier;
38 import android.net.vcn.VcnManager;
39 import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener;
40 import android.net.vcn.VcnNetworkPolicyResult;
41 import android.os.Looper;
42 import android.os.ParcelFileDescriptor;
43 import android.util.CloseGuard;
44 import android.util.Log;
45 
46 import com.android.net.module.util.NetworkStackConstants;
47 
48 import java.net.Inet4Address;
49 import java.net.Inet6Address;
50 import java.net.InetAddress;
51 import java.net.InterfaceAddress;
52 import java.net.NetworkInterface;
53 import java.util.Arrays;
54 import java.util.Objects;
55 import java.util.Set;
56 import java.util.concurrent.BlockingQueue;
57 import java.util.concurrent.CompletableFuture;
58 import java.util.concurrent.Executor;
59 import java.util.concurrent.LinkedBlockingQueue;
60 import java.util.concurrent.TimeUnit;
61 
62 /** Utility class for cleanly creating and tearing down Test Networks. */
63 // TODO(b/188462344): compine with IKEv2's TestNetworkContext
64 public class TestNetworkWrapper implements AutoCloseable {
65     private static final String TAG = TestNetworkWrapper.class.getSimpleName();
66     private static final String NETWORK_AGENT_TAG = TestNetworkAgent.class.getSimpleName();
67     private static final String POLICY_LISTENER_TAG =
68             TestNetworkAgent.TestVcnNetworkPolicyChangeListener.class.getSimpleName();
69 
70     private static final int POLICY_CHANGE_TIMEOUT_MS = 500;
71     public static final int NETWORK_CB_TIMEOUT_MS = 5000;
72 
73     private static final int IP4_PREFIX_LEN = 32;
74     private static final int IP6_PREFIX_LEN = 64;
75 
76     // This NetworkRequest is expected to only match with Test Networks. To do so, remove all
77     // default Capabilities and specify TRANSPORT_TEST.
78     private static final NetworkRequest TEST_NETWORK_REQUEST =
79             new NetworkRequest.Builder()
80                     .clearCapabilities()
81                     .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
82                     .build();
83 
84     private static final String NETWORK_PROVIDER_NAME = "TestNetworkProvider";
85     private static final int TEST_NETWORK_SCORE = 1; // Use a low, non-zero score.
86     private static final Executor INLINE_EXECUTOR = Runnable::run;
87 
88     private final CloseGuard mCloseGuard = new CloseGuard();
89 
90     private final ConnectivityManager mConnectivityManager;
91     private final VcnManager mVcnManager;
92     private final TestNetworkManager mTestNetworkManager;
93 
94     private final TestNetworkAgent mTestNetworkAgent;
95 
96     public final VcnTestNetworkCallback vcnNetworkCallback;
97     public final ParcelFileDescriptor tunFd;
98     public final IkeTunUtils ikeTunUtils;
99     public final Network tunNetwork;
100 
TestNetworkWrapper( @onNull Context context, int mtu, @NonNull Set<Integer> capabilities, @NonNull Set<Integer> subIds, @NonNull InetAddress localAddress)101     public TestNetworkWrapper(
102             @NonNull Context context,
103             int mtu,
104             @NonNull Set<Integer> capabilities,
105             @NonNull Set<Integer> subIds,
106             @NonNull InetAddress localAddress)
107             throws Exception {
108         mConnectivityManager = context.getSystemService(ConnectivityManager.class);
109         mVcnManager = context.getSystemService(VcnManager.class);
110         mTestNetworkManager = context.getSystemService(TestNetworkManager.class);
111 
112         try {
113             final LinkAddress linkAddress =
114                     new LinkAddress(
115                             localAddress,
116                             localAddress instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN);
117             final TestNetworkInterface tni =
118                     mTestNetworkManager.createTunInterface(Arrays.asList(linkAddress));
119             tunFd = tni.getFileDescriptor();
120             final String iface = tni.getInterfaceName();
121 
122             final NetworkRequest nr =
123                     new NetworkRequest.Builder(TEST_NETWORK_REQUEST)
124                             .setNetworkSpecifier(iface)
125                             .build();
126             vcnNetworkCallback = new VcnTestNetworkCallback();
127             mConnectivityManager.requestNetwork(nr, vcnNetworkCallback);
128 
129             // Build TestNetworkAgent
130             final NetworkCapabilities nc =
131                     createNetworkCapabilitiesForIface(iface, capabilities, subIds);
132             final LinkProperties lp = createLinkPropertiesForIface(iface, mtu);
133 
134             final VcnNetworkPolicyResult policy = mVcnManager.applyVcnNetworkPolicy(nc, lp);
135             if (policy.isTeardownRequested()) {
136                 throw new IllegalStateException("Restart requested in bringup");
137             }
138 
139             mTestNetworkAgent =
140                     new TestNetworkAgent(
141                             context, Looper.getMainLooper(), policy.getNetworkCapabilities(), lp);
142             mTestNetworkAgent.register();
143             mTestNetworkAgent.markConnected();
144 
145             tunNetwork = vcnNetworkCallback.waitForAvailable();
146             ikeTunUtils = new IkeTunUtils(tunFd);
147             mCloseGuard.open(TAG);
148         } catch (Exception e) {
149             Log.e(TAG, "Failed to bring up TestNetworkWrapper", e);
150             close();
151             throw e;
152         }
153     }
154 
createNetworkCapabilitiesForIface( @onNull String iface, Set<Integer> capabilities, Set<Integer> subIds)155     private static NetworkCapabilities createNetworkCapabilitiesForIface(
156             @NonNull String iface, Set<Integer> capabilities, Set<Integer> subIds) {
157         NetworkCapabilities.Builder builder =
158                 NetworkCapabilities.Builder.withoutDefaultCapabilities()
159                         .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
160                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
161                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
162                         .setNetworkSpecifier(new TestNetworkSpecifier(iface))
163                         .setSubscriptionIds(subIds);
164         for (int cap : capabilities) {
165             builder.addCapability(cap);
166         }
167 
168         return builder.build();
169     }
170 
createLinkPropertiesForIface(@onNull String iface, int mtu)171     private static LinkProperties createLinkPropertiesForIface(@NonNull String iface, int mtu)
172             throws Exception {
173         final LinkProperties lp = new LinkProperties();
174         lp.setInterfaceName(iface);
175         lp.setMtu(mtu);
176 
177         // Find the currently assigned addresses, and add them to LinkProperties
178         boolean allowIPv4 = false;
179         boolean allowIPv6 = false;
180         NetworkInterface netIntf = NetworkInterface.getByName(iface);
181         Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf);
182 
183         for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) {
184             lp.addLinkAddress(
185                     new LinkAddress(intfAddr.getAddress(), intfAddr.getNetworkPrefixLength()));
186 
187             if (intfAddr.getAddress() instanceof Inet6Address) {
188                 allowIPv6 |= !intfAddr.getAddress().isLinkLocalAddress();
189             } else if (intfAddr.getAddress() instanceof Inet4Address) {
190                 allowIPv4 = true;
191             }
192         }
193 
194         // Add global routes (but as non-default, non-internet providing network). Use prefix
195         // lengths of 0 to match all IP addresses.
196         if (allowIPv4) {
197             lp.addRoute(
198                     new RouteInfo(
199                             new IpPrefix(NetworkStackConstants.IPV4_ADDR_ANY, 0 /* prefixLength */),
200                             null /* gateway */,
201                             iface,
202                             RouteInfo.RTN_UNICAST));
203         }
204         if (allowIPv6) {
205             lp.addRoute(
206                     new RouteInfo(
207                             new IpPrefix(NetworkStackConstants.IPV6_ADDR_ANY, 0 /* prefixLength */),
208                             null /* gateway */,
209                             iface,
210                             RouteInfo.RTN_UNICAST));
211         }
212 
213         return lp;
214     }
215 
216     @Override
close()217     public void close() {
218         mCloseGuard.close();
219 
220         if (vcnNetworkCallback != null) {
221             try {
222                 mConnectivityManager.unregisterNetworkCallback(vcnNetworkCallback);
223             } catch (Exception e) {
224                 Log.e(TAG, "Failed to unregister Network CB", e);
225             }
226         }
227 
228         if (mTestNetworkAgent != null) {
229             synchronized (mTestNetworkAgent) {
230                 try {
231                     mTestNetworkAgent.teardown();
232                 } catch (Exception e) {
233                     Log.e(TAG, "Failed to unregister TestNetworkAgent", e);
234                 }
235             }
236         }
237 
238         if (tunNetwork != null) {
239             try {
240                 mTestNetworkManager.teardownTestNetwork(tunNetwork);
241             } catch (Exception e) {
242                 Log.e(TAG, "Failed to tear down Test Network", e);
243             }
244         }
245 
246         if (tunFd != null) {
247             try {
248                 tunFd.close();
249             } catch (Exception e) {
250                 Log.e(TAG, "Failed to close Test Network FD", e);
251             }
252         }
253     }
254 
255     @Override
finalize()256     public void finalize() {
257         mCloseGuard.warnIfOpen();
258         close();
259     }
260 
awaitVcnNetworkPolicyChange()261     public VcnNetworkPolicyResult awaitVcnNetworkPolicyChange() throws Exception {
262         return mTestNetworkAgent.mPolicyListener.awaitPolicyChange();
263     }
264 
265     /**
266      * Test-only NetworkAgent to be used for instrumented TUN Networks.
267      *
268      * <p>TestNetworkAgent is NOT THREAD SAFE - all accesses should be synchronized.
269      */
270     private class TestNetworkAgent extends NetworkAgent {
271         private final CloseGuard mCloseGuard = new CloseGuard();
272         private final TestVcnNetworkPolicyChangeListener mPolicyListener =
273                 new TestVcnNetworkPolicyChangeListener();
274 
275         private final LinkProperties mLinkProperties;
276 
277         private NetworkCapabilities mNetworkCapabilities;
278 
TestNetworkAgent( @onNull Context context, @NonNull Looper looper, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp)279         private TestNetworkAgent(
280                 @NonNull Context context,
281                 @NonNull Looper looper,
282                 @NonNull NetworkCapabilities nc,
283                 @NonNull LinkProperties lp) {
284             super(
285                     context,
286                     looper,
287                     NETWORK_AGENT_TAG,
288                     nc,
289                     lp,
290                     TEST_NETWORK_SCORE,
291                     new NetworkAgentConfig.Builder().build(),
292                     new NetworkProvider(context, looper, NETWORK_PROVIDER_NAME));
293 
294             mNetworkCapabilities = nc;
295             mLinkProperties = lp;
296 
297             mVcnManager.addVcnNetworkPolicyChangeListener(INLINE_EXECUTOR, mPolicyListener);
298 
299             mCloseGuard.open(NETWORK_AGENT_TAG);
300         }
301 
302         @Override
finalize()303         public void finalize() {
304             mCloseGuard.warnIfOpen();
305             teardown();
306         }
307 
308         @Override
onNetworkUnwanted()309         public void onNetworkUnwanted() {
310             // Not guaranteed to be called from the same thread, so synchronize on this.
311             synchronized (this) {
312                 teardown();
313             }
314         }
315 
teardown()316         private void teardown() {
317             mCloseGuard.close();
318             unregister();
319             mVcnManager.removeVcnNetworkPolicyChangeListener(mPolicyListener);
320         }
321 
getNetworkCapabilities()322         private NetworkCapabilities getNetworkCapabilities() {
323             return mNetworkCapabilities;
324         }
325 
updateNetworkCapabilities(@onNull NetworkCapabilities nc)326         private void updateNetworkCapabilities(@NonNull NetworkCapabilities nc) {
327             Objects.requireNonNull(nc, "nc must be non-null");
328 
329             mNetworkCapabilities = nc;
330             sendNetworkCapabilities(mNetworkCapabilities);
331         }
332 
getLinkProperties()333         private LinkProperties getLinkProperties() {
334             return mLinkProperties;
335         }
336 
337         public class TestVcnNetworkPolicyChangeListener implements VcnNetworkPolicyChangeListener {
338             private final CompletableFuture<VcnNetworkPolicyResult> mFutureOnPolicyChanged =
339                     new CompletableFuture<>();
340 
341             @Override
onPolicyChanged()342             public void onPolicyChanged() {
343                 synchronized (TestNetworkAgent.this) {
344                     final VcnNetworkPolicyResult policy =
345                             mVcnManager.applyVcnNetworkPolicy(
346                                     mTestNetworkAgent.getNetworkCapabilities(),
347                                     mTestNetworkAgent.getLinkProperties());
348 
349                     mFutureOnPolicyChanged.complete(policy);
350                     if (policy.isTeardownRequested()) {
351                         Log.w(POLICY_LISTENER_TAG, "network teardown requested on policy change");
352                         teardown();
353                         return;
354                     }
355 
356                     updateNetworkCapabilities(policy.getNetworkCapabilities());
357                 }
358             }
359 
awaitPolicyChange()360             public VcnNetworkPolicyResult awaitPolicyChange() throws Exception {
361                 return mFutureOnPolicyChanged.get(POLICY_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
362             }
363         }
364     }
365 
366     /** NetworkCallback to used for tracking test network events. */
367     // TODO(b/187231331): remove once TestNetworkCallback supports tracking NetworkCapabilities
368     public static class VcnTestNetworkCallback extends TestNetworkCallback {
369         private final BlockingQueue<Network> mAvailableHistory = new LinkedBlockingQueue<>();
370         private final BlockingQueue<Network> mLostHistory = new LinkedBlockingQueue<>();
371         private final BlockingQueue<CapabilitiesChangedEvent> mCapabilitiesChangedHistory =
372                 new LinkedBlockingQueue<>();
373 
374         @Override
waitForAvailable()375         public Network waitForAvailable() throws InterruptedException {
376             return mAvailableHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS);
377         }
378 
379         @Override
waitForLost()380         public Network waitForLost() throws InterruptedException {
381             return mLostHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS);
382         }
383 
waitForOnCapabilitiesChanged()384         public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception {
385             return waitForOnCapabilitiesChanged(NETWORK_CB_TIMEOUT_MS);
386         }
387 
waitForOnCapabilitiesChanged(long timeoutMillis)388         public CapabilitiesChangedEvent waitForOnCapabilitiesChanged(long timeoutMillis)
389                 throws Exception {
390             return mCapabilitiesChangedHistory.poll(timeoutMillis, TimeUnit.MILLISECONDS);
391         }
392 
393         @Override
onAvailable(@onNull Network network)394         public void onAvailable(@NonNull Network network) {
395             mAvailableHistory.offer(network);
396         }
397 
398         @Override
onLost(@onNull Network network)399         public void onLost(@NonNull Network network) {
400             mLostHistory.offer(network);
401         }
402 
403         @Override
onCapabilitiesChanged( @onNull Network network, @NonNull NetworkCapabilities nc)404         public void onCapabilitiesChanged(
405                 @NonNull Network network, @NonNull NetworkCapabilities nc) {
406             mCapabilitiesChangedHistory.offer(new CapabilitiesChangedEvent(network, nc));
407         }
408 
409         public class CapabilitiesChangedEvent {
410             public final Network network;
411             public final NetworkCapabilities networkCapabilities;
412 
CapabilitiesChangedEvent( @onNull Network network, @NonNull NetworkCapabilities networkCapabilities)413             public CapabilitiesChangedEvent(
414                     @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
415                 this.network = network;
416                 this.networkCapabilities = networkCapabilities;
417             }
418         }
419     }
420 }
421