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