1 /* 2 * Copyright (C) 2018 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 static android.net.TestNetworkManager.CLAT_INTERFACE_PREFIX; 20 import static android.net.TestNetworkManager.TEST_TAP_PREFIX; 21 import static android.net.TestNetworkManager.TEST_TUN_PREFIX; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.content.Context; 26 import android.net.ConnectivityManager; 27 import android.net.INetd; 28 import android.net.ITestNetworkManager; 29 import android.net.IpPrefix; 30 import android.net.LinkAddress; 31 import android.net.LinkProperties; 32 import android.net.NetworkAgent; 33 import android.net.NetworkAgentConfig; 34 import android.net.NetworkCapabilities; 35 import android.net.NetworkProvider; 36 import android.net.RouteInfo; 37 import android.net.TestNetworkInterface; 38 import android.net.TestNetworkSpecifier; 39 import android.os.Binder; 40 import android.os.Handler; 41 import android.os.HandlerThread; 42 import android.os.IBinder; 43 import android.os.Looper; 44 import android.os.ParcelFileDescriptor; 45 import android.os.RemoteException; 46 import android.util.SparseArray; 47 48 import com.android.internal.annotations.GuardedBy; 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.net.module.util.NetworkStackConstants; 51 import com.android.net.module.util.ServiceConnectivityJni; 52 53 import java.io.IOException; 54 import java.io.UncheckedIOException; 55 import java.net.Inet4Address; 56 import java.net.Inet6Address; 57 import java.net.InterfaceAddress; 58 import java.net.NetworkInterface; 59 import java.net.SocketException; 60 import java.util.ArrayList; 61 import java.util.Objects; 62 import java.util.concurrent.atomic.AtomicInteger; 63 64 /** @hide */ 65 class TestNetworkService extends ITestNetworkManager.Stub { 66 @NonNull private static final String TEST_NETWORK_LOGTAG = "TestNetworkAgent"; 67 @NonNull private static final String TEST_NETWORK_PROVIDER_NAME = "TestNetworkProvider"; 68 @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger(); 69 70 @NonNull private final Context mContext; 71 @NonNull private final INetd mNetd; 72 73 @NonNull private final HandlerThread mHandlerThread; 74 @NonNull private final Handler mHandler; 75 76 @NonNull private final ConnectivityManager mCm; 77 @NonNull private final NetworkProvider mNetworkProvider; 78 79 @VisibleForTesting TestNetworkService(@onNull Context context)80 protected TestNetworkService(@NonNull Context context) { 81 mHandlerThread = new HandlerThread("TestNetworkServiceThread"); 82 mHandlerThread.start(); 83 mHandler = new Handler(mHandlerThread.getLooper()); 84 85 mContext = Objects.requireNonNull(context, "missing Context"); 86 mNetd = Objects.requireNonNull( 87 INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)), 88 "could not get netd instance"); 89 mCm = mContext.getSystemService(ConnectivityManager.class); 90 mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(), 91 TEST_NETWORK_PROVIDER_NAME); 92 final long token = Binder.clearCallingIdentity(); 93 try { 94 mCm.registerNetworkProvider(mNetworkProvider); 95 } finally { 96 Binder.restoreCallingIdentity(token); 97 } 98 } 99 100 // TODO: find a way to allow the caller to pass in non-clat interface names, ensuring that 101 // those names do not conflict with names created by callers that do not pass in an interface 102 // name. isValidInterfaceName(@onNull final String iface)103 private static boolean isValidInterfaceName(@NonNull final String iface) { 104 return iface.startsWith(CLAT_INTERFACE_PREFIX + TEST_TUN_PREFIX) 105 || iface.startsWith(CLAT_INTERFACE_PREFIX + TEST_TAP_PREFIX); 106 } 107 108 /** 109 * Create a TUN or TAP interface with the specified parameters. 110 * 111 * <p>This method will return the FileDescriptor to the interface. Close it to tear down the 112 * interface. 113 */ 114 @Override createInterface(boolean isTun, boolean hasCarrier, boolean bringUp, boolean disableIpv6ProvisioningDelay, LinkAddress[] linkAddrs, @Nullable String iface)115 public TestNetworkInterface createInterface(boolean isTun, boolean hasCarrier, boolean bringUp, 116 boolean disableIpv6ProvisioningDelay, LinkAddress[] linkAddrs, @Nullable String iface) { 117 enforceTestNetworkPermissions(mContext); 118 119 Objects.requireNonNull(linkAddrs, "missing linkAddrs"); 120 121 String interfaceName = iface; 122 if (iface == null) { 123 String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX; 124 interfaceName = ifacePrefix + sTestTunIndex.getAndIncrement(); 125 } else if (!isValidInterfaceName(iface)) { 126 throw new IllegalArgumentException("invalid interface name requested: " + iface); 127 } 128 129 final long token = Binder.clearCallingIdentity(); 130 try { 131 // Note: if the interface is brought up by ethernet, setting IFF_MULTICAST 132 // races NetUtils#setInterfaceUp(). This flag is not necessary for ethernet 133 // tests, so let's not set it when bringUp is false. See also b/242343156. 134 // In the future, we could use RTM_SETLINK with ifi_change set to set the 135 // flags atomically. 136 final boolean setIffMulticast = bringUp; 137 ParcelFileDescriptor tunIntf = ParcelFileDescriptor.adoptFd( 138 ServiceConnectivityJni.createTunTap( 139 isTun, hasCarrier, setIffMulticast, interfaceName)); 140 141 // Disable DAD and remove router_solicitation_delay before assigning link addresses. 142 if (disableIpv6ProvisioningDelay) { 143 mNetd.setProcSysNet( 144 INetd.IPV6, INetd.CONF, interfaceName, "router_solicitation_delay", "0"); 145 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, interfaceName, "dad_transmits", "0"); 146 } 147 148 for (LinkAddress addr : linkAddrs) { 149 mNetd.interfaceAddAddress( 150 interfaceName, 151 addr.getAddress().getHostAddress(), 152 addr.getPrefixLength()); 153 } 154 155 if (bringUp) { 156 ServiceConnectivityJni.bringUpInterface(interfaceName); 157 } 158 159 return new TestNetworkInterface(tunIntf, interfaceName); 160 } catch (RemoteException e) { 161 throw e.rethrowFromSystemServer(); 162 } finally { 163 Binder.restoreCallingIdentity(token); 164 } 165 } 166 167 // Tracker for TestNetworkAgents 168 @GuardedBy("mTestNetworkTracker") 169 @NonNull 170 private final SparseArray<TestNetworkAgent> mTestNetworkTracker = new SparseArray<>(); 171 172 public class TestNetworkAgent extends NetworkAgent implements IBinder.DeathRecipient { 173 private static final int NETWORK_SCORE = 1; // Use a low, non-zero score. 174 175 private final int mUid; 176 177 @GuardedBy("mBinderLock") 178 @NonNull 179 private IBinder mBinder; 180 181 @NonNull private final Object mBinderLock = new Object(); 182 TestNetworkAgent( @onNull Context context, @NonNull Looper looper, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @NonNull NetworkAgentConfig config, int uid, @NonNull IBinder binder, @NonNull NetworkProvider np)183 private TestNetworkAgent( 184 @NonNull Context context, 185 @NonNull Looper looper, 186 @NonNull NetworkCapabilities nc, 187 @NonNull LinkProperties lp, 188 @NonNull NetworkAgentConfig config, 189 int uid, 190 @NonNull IBinder binder, 191 @NonNull NetworkProvider np) 192 throws RemoteException { 193 super(context, looper, TEST_NETWORK_LOGTAG, nc, lp, NETWORK_SCORE, config, np); 194 mUid = uid; 195 synchronized (mBinderLock) { 196 mBinder = binder; // Binder null-checks in create() 197 198 try { 199 mBinder.linkToDeath(this, 0); 200 } catch (RemoteException e) { 201 binderDied(); 202 throw e; // Abort, signal failure up the stack. 203 } 204 } 205 } 206 207 /** 208 * If the Binder object dies, this function is called to free the resources of this 209 * TestNetworkAgent 210 */ 211 @Override binderDied()212 public void binderDied() { 213 teardown(); 214 } 215 216 @Override unwanted()217 protected void unwanted() { 218 teardown(); 219 } 220 teardown()221 private void teardown() { 222 unregister(); 223 224 // Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than 225 // once (otherwise it could throw an exception) 226 synchronized (mBinderLock) { 227 // If mBinder is null, this Test Network has already been cleaned up. 228 if (mBinder == null) return; 229 mBinder.unlinkToDeath(this, 0); 230 mBinder = null; 231 } 232 233 // Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up 234 // resources, even for binder death or unwanted calls. 235 synchronized (mTestNetworkTracker) { 236 mTestNetworkTracker.remove(getNetwork().getNetId()); 237 } 238 } 239 } 240 registerTestNetworkAgent( @onNull Looper looper, @NonNull Context context, @NonNull String iface, @Nullable LinkProperties lp, boolean isMetered, int callingUid, @NonNull int[] administratorUids, @NonNull IBinder binder)241 private TestNetworkAgent registerTestNetworkAgent( 242 @NonNull Looper looper, 243 @NonNull Context context, 244 @NonNull String iface, 245 @Nullable LinkProperties lp, 246 boolean isMetered, 247 int callingUid, 248 @NonNull int[] administratorUids, 249 @NonNull IBinder binder) 250 throws RemoteException, SocketException { 251 Objects.requireNonNull(looper, "missing Looper"); 252 Objects.requireNonNull(context, "missing Context"); 253 // iface and binder validity checked by caller 254 255 // Build narrow set of NetworkCapabilities, useful only for testing 256 NetworkCapabilities nc = new NetworkCapabilities(); 257 nc.clearAll(); // Remove default capabilities. 258 nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST); 259 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); 260 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 261 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); 262 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); 263 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED); 264 nc.setNetworkSpecifier(new TestNetworkSpecifier(iface)); 265 nc.setAdministratorUids(administratorUids); 266 if (!isMetered) { 267 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); 268 } 269 270 // Build LinkProperties 271 if (lp == null) { 272 lp = new LinkProperties(); 273 } else { 274 lp = new LinkProperties(lp); 275 // Use LinkAddress(es) from the interface itself to minimize how much the caller 276 // is trusted. 277 lp.setLinkAddresses(new ArrayList<>()); 278 } 279 lp.setInterfaceName(iface); 280 281 // Find the currently assigned addresses, and add them to LinkProperties 282 boolean allowIPv4 = false, allowIPv6 = false; 283 NetworkInterface netIntf = NetworkInterface.getByName(iface); 284 Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf); 285 286 for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) { 287 lp.addLinkAddress( 288 new LinkAddress(intfAddr.getAddress(), intfAddr.getNetworkPrefixLength())); 289 290 if (intfAddr.getAddress() instanceof Inet6Address) { 291 allowIPv6 |= !intfAddr.getAddress().isLinkLocalAddress(); 292 } else if (intfAddr.getAddress() instanceof Inet4Address) { 293 allowIPv4 = true; 294 } 295 } 296 297 // Add global routes (but as non-default, non-internet providing network) 298 if (allowIPv4) { 299 lp.addRoute(new RouteInfo(new IpPrefix( 300 NetworkStackConstants.IPV4_ADDR_ANY, 0), null, iface)); 301 } 302 if (allowIPv6) { 303 lp.addRoute(new RouteInfo(new IpPrefix( 304 NetworkStackConstants.IPV6_ADDR_ANY, 0), null, iface)); 305 } 306 307 // For testing purpose, fill legacy type for NetworkStatsService since it does not 308 // support transport types. 309 final TestNetworkAgent agent = new TestNetworkAgent(context, looper, nc, lp, 310 new NetworkAgentConfig.Builder().setLegacyType(ConnectivityManager.TYPE_TEST) 311 .build(), callingUid, binder, mNetworkProvider); 312 agent.register(); 313 agent.markConnected(); 314 return agent; 315 } 316 317 /** 318 * Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS 319 * permission. 320 * 321 * <p>This method provides a Network that is useful only for testing. 322 */ 323 @Override setupTestNetwork( @onNull String iface, @Nullable LinkProperties lp, boolean isMetered, @NonNull int[] administratorUids, @NonNull IBinder binder)324 public void setupTestNetwork( 325 @NonNull String iface, 326 @Nullable LinkProperties lp, 327 boolean isMetered, 328 @NonNull int[] administratorUids, 329 @NonNull IBinder binder) { 330 enforceTestNetworkPermissions(mContext); 331 332 Objects.requireNonNull(iface, "missing Iface"); 333 Objects.requireNonNull(binder, "missing IBinder"); 334 335 if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX) 336 || iface.startsWith(TEST_TUN_PREFIX))) { 337 throw new IllegalArgumentException( 338 "Cannot create network for non ipsec, non-testtun interface"); 339 } 340 341 try { 342 // Synchronize all accesses to mTestNetworkTracker to prevent the case where: 343 // 1. TestNetworkAgent successfully binds to death of binder 344 // 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called 345 // (on a different thread) 346 // 3. This thread is pre-empted, put() is called after remove() 347 synchronized (mTestNetworkTracker) { 348 TestNetworkAgent agent = 349 registerTestNetworkAgent( 350 mHandler.getLooper(), 351 mContext, 352 iface, 353 lp, 354 isMetered, 355 Binder.getCallingUid(), 356 administratorUids, 357 binder); 358 359 mTestNetworkTracker.put(agent.getNetwork().getNetId(), agent); 360 } 361 } catch (SocketException e) { 362 throw new UncheckedIOException(e); 363 } catch (RemoteException e) { 364 throw e.rethrowFromSystemServer(); 365 } 366 } 367 368 /** Teardown a test network */ 369 @Override teardownTestNetwork(int netId)370 public void teardownTestNetwork(int netId) { 371 enforceTestNetworkPermissions(mContext); 372 373 final TestNetworkAgent agent; 374 synchronized (mTestNetworkTracker) { 375 agent = mTestNetworkTracker.get(netId); 376 } 377 378 if (agent == null) { 379 return; // Already torn down 380 } else if (agent.mUid != Binder.getCallingUid()) { 381 throw new SecurityException("Attempted to modify other user's test networks"); 382 } 383 384 // Safe to be called multiple times. 385 agent.teardown(); 386 } 387 388 private static final String PERMISSION_NAME = 389 android.Manifest.permission.MANAGE_TEST_NETWORKS; 390 enforceTestNetworkPermissions(@onNull Context context)391 public static void enforceTestNetworkPermissions(@NonNull Context context) { 392 context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService"); 393 } 394 395 /** Enable / disable TestNetworkInterface carrier */ 396 @Override setCarrierEnabled(@onNull TestNetworkInterface iface, boolean enabled)397 public void setCarrierEnabled(@NonNull TestNetworkInterface iface, boolean enabled) { 398 enforceTestNetworkPermissions(mContext); 399 ServiceConnectivityJni.setTunTapCarrierEnabled(iface.getInterfaceName(), 400 iface.getFileDescriptor().getFd(), enabled); 401 // Explicitly close fd after use to prevent StrictMode from complaining. 402 // Also, explicitly referencing iface guarantees that the object is not garbage collected 403 // before setTunTapCarrierEnabled() executes. 404 try { 405 iface.getFileDescriptor().close(); 406 } catch (IOException e) { 407 // if the close fails, there is not much that can be done -- move on. 408 } 409 } 410 } 411