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.Executor; 58 import java.util.concurrent.LinkedBlockingQueue; 59 import java.util.concurrent.TimeUnit; 60 61 /** Utility class for cleanly creating and tearing down Test Networks. */ 62 // TODO(b/188462344): compine with IKEv2's TestNetworkContext 63 public class TestNetworkWrapper implements AutoCloseable { 64 private static final String TAG = TestNetworkWrapper.class.getSimpleName(); 65 private static final String NETWORK_AGENT_TAG = TestNetworkAgent.class.getSimpleName(); 66 private static final String POLICY_LISTENER_TAG = 67 TestNetworkAgent.TestVcnNetworkPolicyChangeListener.class.getSimpleName(); 68 69 public static final int NETWORK_CB_TIMEOUT_MS = 5000; 70 71 private static final int IP4_PREFIX_LEN = 32; 72 private static final int IP6_PREFIX_LEN = 64; 73 74 // This NetworkRequest is expected to only match with Test Networks. To do so, remove all 75 // default Capabilities and specify TRANSPORT_TEST. 76 private static final NetworkRequest TEST_NETWORK_REQUEST = 77 new NetworkRequest.Builder() 78 .clearCapabilities() 79 .addTransportType(NetworkCapabilities.TRANSPORT_TEST) 80 .build(); 81 82 private static final String NETWORK_PROVIDER_NAME = "TestNetworkProvider"; 83 private static final int TEST_NETWORK_SCORE = 1; // Use a low, non-zero score. 84 private static final Executor INLINE_EXECUTOR = Runnable::run; 85 86 private final CloseGuard mCloseGuard = new CloseGuard(); 87 88 private final ConnectivityManager mConnectivityManager; 89 private final VcnManager mVcnManager; 90 private final TestNetworkManager mTestNetworkManager; 91 92 private final TestNetworkAgent mTestNetworkAgent; 93 94 public final VcnTestNetworkCallback vcnNetworkCallback; 95 public final ParcelFileDescriptor tunFd; 96 public final IkeTunUtils ikeTunUtils; 97 public final Network tunNetwork; 98 TestNetworkWrapper( @onNull Context context, int mtu, boolean isMetered, @NonNull Set<Integer> subIds, @NonNull InetAddress localAddress)99 public TestNetworkWrapper( 100 @NonNull Context context, 101 int mtu, 102 boolean isMetered, 103 @NonNull Set<Integer> subIds, 104 @NonNull InetAddress localAddress) 105 throws Exception { 106 mConnectivityManager = context.getSystemService(ConnectivityManager.class); 107 mVcnManager = context.getSystemService(VcnManager.class); 108 mTestNetworkManager = context.getSystemService(TestNetworkManager.class); 109 110 try { 111 final LinkAddress linkAddress = 112 new LinkAddress( 113 localAddress, 114 localAddress instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN); 115 final TestNetworkInterface tni = 116 mTestNetworkManager.createTunInterface(Arrays.asList(linkAddress)); 117 tunFd = tni.getFileDescriptor(); 118 final String iface = tni.getInterfaceName(); 119 120 final NetworkRequest nr = 121 new NetworkRequest.Builder(TEST_NETWORK_REQUEST) 122 .setNetworkSpecifier(iface) 123 .build(); 124 vcnNetworkCallback = new VcnTestNetworkCallback(); 125 mConnectivityManager.requestNetwork(nr, vcnNetworkCallback); 126 127 final NetworkCapabilities nc = 128 createNetworkCapabilitiesForIface(iface, isMetered, subIds); 129 final LinkProperties lp = createLinkPropertiesForIface(iface, mtu); 130 131 final VcnNetworkPolicyResult policy = mVcnManager.applyVcnNetworkPolicy(nc, lp); 132 if (policy.isTeardownRequested()) { 133 throw new IllegalStateException("Restart requested in bringup"); 134 } 135 136 mTestNetworkAgent = 137 new TestNetworkAgent( 138 context, Looper.getMainLooper(), policy.getNetworkCapabilities(), lp); 139 mTestNetworkAgent.register(); 140 mTestNetworkAgent.markConnected(); 141 142 tunNetwork = vcnNetworkCallback.waitForAvailable(); 143 ikeTunUtils = new IkeTunUtils(tunFd); 144 mCloseGuard.open(TAG); 145 } catch (Exception e) { 146 Log.e(TAG, "Failed to bring up TestNetworkWrapper", e); 147 close(); 148 throw e; 149 } 150 } 151 createNetworkCapabilitiesForIface( @onNull String iface, boolean isMetered, Set<Integer> subIds)152 private static NetworkCapabilities createNetworkCapabilitiesForIface( 153 @NonNull String iface, boolean isMetered, Set<Integer> subIds) { 154 NetworkCapabilities.Builder builder = 155 NetworkCapabilities.Builder.withoutDefaultCapabilities() 156 .addTransportType(NetworkCapabilities.TRANSPORT_TEST) 157 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 158 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 159 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) 160 .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) 161 .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) 162 .addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA) 163 .setNetworkSpecifier(new TestNetworkSpecifier(iface)) 164 .setSubscriptionIds(subIds); 165 if (!isMetered) { 166 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); 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 261 /** 262 * Test-only NetworkAgent to be used for instrumented TUN Networks. 263 * 264 * <p>TestNetworkAgent is NOT THREAD SAFE - all accesses should be synchronized. 265 */ 266 private class TestNetworkAgent extends NetworkAgent { 267 private final CloseGuard mCloseGuard = new CloseGuard(); 268 private final VcnNetworkPolicyChangeListener mPolicyListener = 269 new TestVcnNetworkPolicyChangeListener(); 270 271 private final LinkProperties mLinkProperties; 272 273 private NetworkCapabilities mNetworkCapabilities; 274 TestNetworkAgent( @onNull Context context, @NonNull Looper looper, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp)275 private TestNetworkAgent( 276 @NonNull Context context, 277 @NonNull Looper looper, 278 @NonNull NetworkCapabilities nc, 279 @NonNull LinkProperties lp) { 280 super( 281 context, 282 looper, 283 NETWORK_AGENT_TAG, 284 nc, 285 lp, 286 TEST_NETWORK_SCORE, 287 new NetworkAgentConfig.Builder().build(), 288 new NetworkProvider(context, looper, NETWORK_PROVIDER_NAME)); 289 290 mNetworkCapabilities = nc; 291 mLinkProperties = lp; 292 293 mVcnManager.addVcnNetworkPolicyChangeListener(INLINE_EXECUTOR, mPolicyListener); 294 295 mCloseGuard.open(NETWORK_AGENT_TAG); 296 } 297 298 @Override finalize()299 public void finalize() { 300 mCloseGuard.warnIfOpen(); 301 teardown(); 302 } 303 304 @Override onNetworkUnwanted()305 public void onNetworkUnwanted() { 306 // Not guaranteed to be called from the same thread, so synchronize on this. 307 synchronized (this) { 308 teardown(); 309 } 310 } 311 teardown()312 private void teardown() { 313 mCloseGuard.close(); 314 unregister(); 315 mVcnManager.removeVcnNetworkPolicyChangeListener(mPolicyListener); 316 } 317 getNetworkCapabilities()318 private NetworkCapabilities getNetworkCapabilities() { 319 return mNetworkCapabilities; 320 } 321 updateNetworkCapabilities(@onNull NetworkCapabilities nc)322 private void updateNetworkCapabilities(@NonNull NetworkCapabilities nc) { 323 Objects.requireNonNull(nc, "nc must be non-null"); 324 325 mNetworkCapabilities = nc; 326 sendNetworkCapabilities(mNetworkCapabilities); 327 } 328 getLinkProperties()329 private LinkProperties getLinkProperties() { 330 return mLinkProperties; 331 } 332 333 private class TestVcnNetworkPolicyChangeListener implements VcnNetworkPolicyChangeListener { 334 @Override onPolicyChanged()335 public void onPolicyChanged() { 336 synchronized (TestNetworkAgent.this) { 337 final VcnNetworkPolicyResult policy = 338 mVcnManager.applyVcnNetworkPolicy( 339 mTestNetworkAgent.getNetworkCapabilities(), 340 mTestNetworkAgent.getLinkProperties()); 341 if (policy.isTeardownRequested()) { 342 Log.w(POLICY_LISTENER_TAG, "network teardown requested on policy change"); 343 teardown(); 344 return; 345 } 346 347 updateNetworkCapabilities(policy.getNetworkCapabilities()); 348 } 349 } 350 } 351 } 352 353 /** NetworkCallback to used for tracking test network events. */ 354 // TODO(b/187231331): remove once TestNetworkCallback supports tracking NetworkCapabilities 355 public static class VcnTestNetworkCallback extends TestNetworkCallback { 356 private final BlockingQueue<Network> mAvailableHistory = new LinkedBlockingQueue<>(); 357 private final BlockingQueue<Network> mLostHistory = new LinkedBlockingQueue<>(); 358 private final BlockingQueue<CapabilitiesChangedEvent> mCapabilitiesChangedHistory = 359 new LinkedBlockingQueue<>(); 360 361 @Override waitForAvailable()362 public Network waitForAvailable() throws InterruptedException { 363 return mAvailableHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); 364 } 365 366 @Override waitForLost()367 public Network waitForLost() throws InterruptedException { 368 return mLostHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); 369 } 370 waitForOnCapabilitiesChanged()371 public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception { 372 return waitForOnCapabilitiesChanged(NETWORK_CB_TIMEOUT_MS); 373 } 374 waitForOnCapabilitiesChanged(long timeoutMillis)375 public CapabilitiesChangedEvent waitForOnCapabilitiesChanged(long timeoutMillis) 376 throws Exception { 377 return mCapabilitiesChangedHistory.poll(timeoutMillis, TimeUnit.MILLISECONDS); 378 } 379 380 @Override onAvailable(@onNull Network network)381 public void onAvailable(@NonNull Network network) { 382 mAvailableHistory.offer(network); 383 } 384 385 @Override onLost(@onNull Network network)386 public void onLost(@NonNull Network network) { 387 mLostHistory.offer(network); 388 } 389 390 @Override onCapabilitiesChanged( @onNull Network network, @NonNull NetworkCapabilities nc)391 public void onCapabilitiesChanged( 392 @NonNull Network network, @NonNull NetworkCapabilities nc) { 393 mCapabilitiesChangedHistory.offer(new CapabilitiesChangedEvent(network, nc)); 394 } 395 396 public class CapabilitiesChangedEvent { 397 public final Network network; 398 public final NetworkCapabilities networkCapabilities; 399 CapabilitiesChangedEvent( @onNull Network network, @NonNull NetworkCapabilities networkCapabilities)400 public CapabilitiesChangedEvent( 401 @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { 402 this.network = network; 403 this.networkCapabilities = networkCapabilities; 404 } 405 } 406 } 407 } 408