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.setNetworkSpecifier(new TestNetworkSpecifier(iface)); 271 nc.setAdministratorUids(administratorUids); 272 if (!isMetered) { 273 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); 274 } 275 276 // Build LinkProperties 277 if (lp == null) { 278 lp = new LinkProperties(); 279 } else { 280 lp = new LinkProperties(lp); 281 // Use LinkAddress(es) from the interface itself to minimize how much the caller 282 // is trusted. 283 lp.setLinkAddresses(new ArrayList<>()); 284 } 285 lp.setInterfaceName(iface); 286 287 // Find the currently assigned addresses, and add them to LinkProperties 288 boolean allowIPv4 = false, allowIPv6 = false; 289 NetworkInterface netIntf = NetworkInterface.getByName(iface); 290 Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf); 291 292 for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) { 293 lp.addLinkAddress( 294 new LinkAddress(intfAddr.getAddress(), intfAddr.getNetworkPrefixLength())); 295 296 if (intfAddr.getAddress() instanceof Inet6Address) { 297 allowIPv6 |= !intfAddr.getAddress().isLinkLocalAddress(); 298 } else if (intfAddr.getAddress() instanceof Inet4Address) { 299 allowIPv4 = true; 300 } 301 } 302 303 // Add global routes (but as non-default, non-internet providing network) 304 if (allowIPv4) { 305 lp.addRoute(new RouteInfo(new IpPrefix( 306 NetworkStackConstants.IPV4_ADDR_ANY, 0), null, iface)); 307 } 308 if (allowIPv6) { 309 lp.addRoute(new RouteInfo(new IpPrefix( 310 NetworkStackConstants.IPV6_ADDR_ANY, 0), null, iface)); 311 } 312 313 // For testing purpose, fill legacy type for NetworkStatsService since it does not 314 // support transport types. 315 final TestNetworkAgent agent = new TestNetworkAgent(context, looper, nc, lp, 316 new NetworkAgentConfig.Builder().setLegacyType(ConnectivityManager.TYPE_TEST) 317 .build(), callingUid, binder, mNetworkProvider); 318 agent.register(); 319 agent.markConnected(); 320 return agent; 321 } 322 323 /** 324 * Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS 325 * permission. 326 * 327 * <p>This method provides a Network that is useful only for testing. 328 */ 329 @Override setupTestNetwork( @onNull String iface, @Nullable LinkProperties lp, boolean isMetered, @NonNull int[] administratorUids, @NonNull IBinder binder)330 public void setupTestNetwork( 331 @NonNull String iface, 332 @Nullable LinkProperties lp, 333 boolean isMetered, 334 @NonNull int[] administratorUids, 335 @NonNull IBinder binder) { 336 enforceTestNetworkPermissions(mContext); 337 338 Objects.requireNonNull(iface, "missing Iface"); 339 Objects.requireNonNull(binder, "missing IBinder"); 340 341 if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX) 342 || iface.startsWith(TEST_TUN_PREFIX))) { 343 throw new IllegalArgumentException( 344 "Cannot create network for non ipsec, non-testtun interface"); 345 } 346 347 try { 348 // Synchronize all accesses to mTestNetworkTracker to prevent the case where: 349 // 1. TestNetworkAgent successfully binds to death of binder 350 // 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called 351 // (on a different thread) 352 // 3. This thread is pre-empted, put() is called after remove() 353 synchronized (mTestNetworkTracker) { 354 TestNetworkAgent agent = 355 registerTestNetworkAgent( 356 mHandler.getLooper(), 357 mContext, 358 iface, 359 lp, 360 isMetered, 361 Binder.getCallingUid(), 362 administratorUids, 363 binder); 364 365 mTestNetworkTracker.put(agent.getNetwork().getNetId(), agent); 366 } 367 } catch (SocketException e) { 368 throw new UncheckedIOException(e); 369 } catch (RemoteException e) { 370 throw e.rethrowFromSystemServer(); 371 } 372 } 373 374 /** Teardown a test network */ 375 @Override teardownTestNetwork(int netId)376 public void teardownTestNetwork(int netId) { 377 enforceTestNetworkPermissions(mContext); 378 379 final TestNetworkAgent agent; 380 synchronized (mTestNetworkTracker) { 381 agent = mTestNetworkTracker.get(netId); 382 } 383 384 if (agent == null) { 385 return; // Already torn down 386 } else if (agent.mUid != Binder.getCallingUid()) { 387 throw new SecurityException("Attempted to modify other user's test networks"); 388 } 389 390 // Safe to be called multiple times. 391 agent.teardown(); 392 } 393 394 private static final String PERMISSION_NAME = 395 android.Manifest.permission.MANAGE_TEST_NETWORKS; 396 enforceTestNetworkPermissions(@onNull Context context)397 public static void enforceTestNetworkPermissions(@NonNull Context context) { 398 context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService"); 399 } 400 401 /** Enable / disable TestNetworkInterface carrier */ 402 @Override setCarrierEnabled(@onNull TestNetworkInterface iface, boolean enabled)403 public void setCarrierEnabled(@NonNull TestNetworkInterface iface, boolean enabled) { 404 enforceTestNetworkPermissions(mContext); 405 nativeSetTunTapCarrierEnabled(iface.getInterfaceName(), iface.getFileDescriptor().getFd(), 406 enabled); 407 // Explicitly close fd after use to prevent StrictMode from complaining. 408 // Also, explicitly referencing iface guarantees that the object is not garbage collected 409 // before nativeSetTunTapCarrierEnabled() executes. 410 try { 411 iface.getFileDescriptor().close(); 412 } catch (IOException e) { 413 // if the close fails, there is not much that can be done -- move on. 414 } 415 } 416 } 417