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