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