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