Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 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 com.android.internal.util.Preconditions.checkNotNull; |
| 20 | |
| 21 | import android.annotation.NonNull; |
Benedict Wong | 512ab0d | 2019-04-18 19:18:43 -0700 | [diff] [blame] | 22 | import android.annotation.Nullable; |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 23 | import android.content.Context; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 24 | import android.net.ConnectivityManager; |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 25 | import android.net.INetd; |
| 26 | import android.net.ITestNetworkManager; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 27 | import android.net.IpPrefix; |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 28 | import android.net.LinkAddress; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 29 | import android.net.LinkProperties; |
| 30 | import android.net.NetworkAgent; |
| 31 | import android.net.NetworkCapabilities; |
| 32 | import android.net.NetworkInfo; |
| 33 | import android.net.NetworkInfo.DetailedState; |
| 34 | import android.net.RouteInfo; |
| 35 | import android.net.StringNetworkSpecifier; |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 36 | import android.net.TestNetworkInterface; |
| 37 | import android.net.util.NetdService; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 38 | import android.os.Binder; |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 39 | import android.os.Handler; |
| 40 | import android.os.HandlerThread; |
| 41 | import android.os.IBinder; |
| 42 | import android.os.INetworkManagementService; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 43 | import android.os.Looper; |
| 44 | import android.os.ParcelFileDescriptor; |
| 45 | import android.os.RemoteException; |
| 46 | import android.util.SparseArray; |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 47 | |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 48 | import com.android.internal.annotations.GuardedBy; |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 49 | import com.android.internal.annotations.VisibleForTesting; |
| 50 | |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 51 | import java.io.UncheckedIOException; |
| 52 | import java.net.Inet4Address; |
| 53 | import java.net.Inet6Address; |
| 54 | import java.net.InterfaceAddress; |
| 55 | import java.net.NetworkInterface; |
| 56 | import java.net.SocketException; |
Benedict Wong | 512ab0d | 2019-04-18 19:18:43 -0700 | [diff] [blame] | 57 | import java.util.ArrayList; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 58 | import java.util.concurrent.atomic.AtomicInteger; |
| 59 | |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 60 | /** @hide */ |
| 61 | class TestNetworkService extends ITestNetworkManager.Stub { |
| 62 | @NonNull private static final String TAG = TestNetworkService.class.getSimpleName(); |
| 63 | @NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK"; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 64 | @NonNull private static final String TEST_TUN_PREFIX = "testtun"; |
Lorenzo Colitti | b15fcce | 2019-04-01 23:41:12 +0900 | [diff] [blame] | 65 | @NonNull private static final String TEST_TAP_PREFIX = "testtap"; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 66 | @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger(); |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 67 | |
| 68 | @NonNull private final Context mContext; |
| 69 | @NonNull private final INetworkManagementService mNMS; |
| 70 | @NonNull private final INetd mNetd; |
| 71 | |
| 72 | @NonNull private final HandlerThread mHandlerThread; |
| 73 | @NonNull private final Handler mHandler; |
| 74 | |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 75 | // Native method stubs |
Lorenzo Colitti | b15fcce | 2019-04-01 23:41:12 +0900 | [diff] [blame] | 76 | private static native int jniCreateTunTap(boolean isTun, @NonNull String iface); |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 77 | |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 78 | @VisibleForTesting |
| 79 | protected TestNetworkService( |
| 80 | @NonNull Context context, @NonNull INetworkManagementService netManager) { |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 81 | mHandlerThread = new HandlerThread("TestNetworkServiceThread"); |
| 82 | mHandlerThread.start(); |
| 83 | mHandler = new Handler(mHandlerThread.getLooper()); |
| 84 | |
| 85 | mContext = checkNotNull(context, "missing Context"); |
| 86 | mNMS = checkNotNull(netManager, "missing INetworkManagementService"); |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 87 | mNetd = checkNotNull(NetdService.getInstance(), "could not get netd instance"); |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | /** |
Lorenzo Colitti | b15fcce | 2019-04-01 23:41:12 +0900 | [diff] [blame] | 91 | * Create a TUN or TAP interface with the given interface name and link addresses |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 92 | * |
Lorenzo Colitti | b15fcce | 2019-04-01 23:41:12 +0900 | [diff] [blame] | 93 | * <p>This method will return the FileDescriptor to the interface. Close it to tear down the |
| 94 | * interface. |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 95 | */ |
Lorenzo Colitti | b15fcce | 2019-04-01 23:41:12 +0900 | [diff] [blame] | 96 | private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) { |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 97 | enforceTestNetworkPermissions(mContext); |
| 98 | |
| 99 | checkNotNull(linkAddrs, "missing linkAddrs"); |
| 100 | |
Lorenzo Colitti | b15fcce | 2019-04-01 23:41:12 +0900 | [diff] [blame] | 101 | String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX; |
| 102 | String iface = ifacePrefix + sTestTunIndex.getAndIncrement(); |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 103 | return Binder.withCleanCallingIdentity( |
| 104 | () -> { |
| 105 | try { |
| 106 | ParcelFileDescriptor tunIntf = |
Lorenzo Colitti | b15fcce | 2019-04-01 23:41:12 +0900 | [diff] [blame] | 107 | ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface)); |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 108 | for (LinkAddress addr : linkAddrs) { |
| 109 | mNetd.interfaceAddAddress( |
| 110 | iface, |
| 111 | addr.getAddress().getHostAddress(), |
| 112 | addr.getPrefixLength()); |
| 113 | } |
| 114 | |
| 115 | return new TestNetworkInterface(tunIntf, iface); |
| 116 | } catch (RemoteException e) { |
| 117 | throw e.rethrowFromSystemServer(); |
| 118 | } |
| 119 | }); |
| 120 | } |
| 121 | |
Lorenzo Colitti | b15fcce | 2019-04-01 23:41:12 +0900 | [diff] [blame] | 122 | /** |
| 123 | * Create a TUN interface with the given interface name and link addresses |
| 124 | * |
| 125 | * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the |
| 126 | * TUN interface. |
| 127 | */ |
| 128 | @Override |
| 129 | public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) { |
| 130 | return createInterface(true, linkAddrs); |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Create a TAP interface with the given interface name |
| 135 | * |
| 136 | * <p>This method will return the FileDescriptor to the TAP interface. Close it to tear down the |
| 137 | * TAP interface. |
| 138 | */ |
| 139 | @Override |
| 140 | public TestNetworkInterface createTapInterface() { |
| 141 | return createInterface(false, new LinkAddress[0]); |
| 142 | } |
| 143 | |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 144 | // Tracker for TestNetworkAgents |
| 145 | @GuardedBy("mTestNetworkTracker") |
| 146 | @NonNull |
| 147 | private final SparseArray<TestNetworkAgent> mTestNetworkTracker = new SparseArray<>(); |
| 148 | |
| 149 | public class TestNetworkAgent extends NetworkAgent implements IBinder.DeathRecipient { |
| 150 | private static final int NETWORK_SCORE = 1; // Use a low, non-zero score. |
| 151 | |
| 152 | private final int mUid; |
| 153 | @NonNull private final NetworkInfo mNi; |
| 154 | @NonNull private final NetworkCapabilities mNc; |
| 155 | @NonNull private final LinkProperties mLp; |
| 156 | |
| 157 | @GuardedBy("mBinderLock") |
| 158 | @NonNull |
| 159 | private IBinder mBinder; |
| 160 | |
| 161 | @NonNull private final Object mBinderLock = new Object(); |
| 162 | |
| 163 | private TestNetworkAgent( |
| 164 | @NonNull Looper looper, |
| 165 | @NonNull Context context, |
| 166 | @NonNull NetworkInfo ni, |
| 167 | @NonNull NetworkCapabilities nc, |
| 168 | @NonNull LinkProperties lp, |
| 169 | int uid, |
| 170 | @NonNull IBinder binder) |
| 171 | throws RemoteException { |
| 172 | super(looper, context, TEST_NETWORK_TYPE, ni, nc, lp, NETWORK_SCORE); |
| 173 | |
| 174 | mUid = uid; |
| 175 | mNi = ni; |
| 176 | mNc = nc; |
| 177 | mLp = lp; |
| 178 | |
| 179 | synchronized (mBinderLock) { |
| 180 | mBinder = binder; // Binder null-checks in create() |
| 181 | |
| 182 | try { |
| 183 | mBinder.linkToDeath(this, 0); |
| 184 | } catch (RemoteException e) { |
| 185 | binderDied(); |
| 186 | throw e; // Abort, signal failure up the stack. |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | /** |
| 192 | * If the Binder object dies, this function is called to free the resources of this |
| 193 | * TestNetworkAgent |
| 194 | */ |
| 195 | @Override |
| 196 | public void binderDied() { |
| 197 | teardown(); |
| 198 | } |
| 199 | |
| 200 | @Override |
| 201 | protected void unwanted() { |
| 202 | teardown(); |
| 203 | } |
| 204 | |
| 205 | private void teardown() { |
| 206 | mNi.setDetailedState(DetailedState.DISCONNECTED, null, null); |
| 207 | mNi.setIsAvailable(false); |
| 208 | sendNetworkInfo(mNi); |
| 209 | |
| 210 | // Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than |
| 211 | // once (otherwise it could throw an exception) |
| 212 | synchronized (mBinderLock) { |
| 213 | // If mBinder is null, this Test Network has already been cleaned up. |
| 214 | if (mBinder == null) return; |
| 215 | mBinder.unlinkToDeath(this, 0); |
| 216 | mBinder = null; |
| 217 | } |
| 218 | |
| 219 | // Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up |
| 220 | // resources, even for binder death or unwanted calls. |
| 221 | synchronized (mTestNetworkTracker) { |
| 222 | mTestNetworkTracker.remove(netId); |
| 223 | } |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | private TestNetworkAgent registerTestNetworkAgent( |
| 228 | @NonNull Looper looper, |
| 229 | @NonNull Context context, |
| 230 | @NonNull String iface, |
Benedict Wong | 512ab0d | 2019-04-18 19:18:43 -0700 | [diff] [blame] | 231 | @Nullable LinkProperties lp, |
| 232 | boolean isMetered, |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 233 | int callingUid, |
| 234 | @NonNull IBinder binder) |
| 235 | throws RemoteException, SocketException { |
| 236 | checkNotNull(looper, "missing Looper"); |
| 237 | checkNotNull(context, "missing Context"); |
| 238 | // iface and binder validity checked by caller |
| 239 | |
| 240 | // Build network info with special testing type |
| 241 | NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_TEST, 0, TEST_NETWORK_TYPE, ""); |
| 242 | ni.setDetailedState(DetailedState.CONNECTED, null, null); |
| 243 | ni.setIsAvailable(true); |
| 244 | |
| 245 | // Build narrow set of NetworkCapabilities, useful only for testing |
| 246 | NetworkCapabilities nc = new NetworkCapabilities(); |
| 247 | nc.clearAll(); // Remove default capabilities. |
| 248 | nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST); |
| 249 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); |
| 250 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); |
| 251 | nc.setNetworkSpecifier(new StringNetworkSpecifier(iface)); |
Benedict Wong | 512ab0d | 2019-04-18 19:18:43 -0700 | [diff] [blame] | 252 | if (!isMetered) { |
| 253 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); |
| 254 | } |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 255 | |
| 256 | // Build LinkProperties |
Benedict Wong | 512ab0d | 2019-04-18 19:18:43 -0700 | [diff] [blame] | 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 | } |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 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 | checkNotNull(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(Inet4Address.ANY, 0), null, iface)); |
| 286 | } |
| 287 | if (allowIPv6) { |
| 288 | lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface)); |
| 289 | } |
| 290 | |
| 291 | return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder); |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 292 | } |
| 293 | |
| 294 | /** |
| 295 | * Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS |
| 296 | * permission. |
| 297 | * |
| 298 | * <p>This method provides a Network that is useful only for testing. |
| 299 | */ |
| 300 | @Override |
Benedict Wong | 512ab0d | 2019-04-18 19:18:43 -0700 | [diff] [blame] | 301 | public void setupTestNetwork( |
| 302 | @NonNull String iface, |
| 303 | @Nullable LinkProperties lp, |
| 304 | boolean isMetered, |
| 305 | @NonNull IBinder binder) { |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 306 | enforceTestNetworkPermissions(mContext); |
| 307 | |
| 308 | checkNotNull(iface, "missing Iface"); |
| 309 | checkNotNull(binder, "missing IBinder"); |
| 310 | |
| 311 | if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX) |
| 312 | || iface.startsWith(TEST_TUN_PREFIX))) { |
| 313 | throw new IllegalArgumentException( |
| 314 | "Cannot create network for non ipsec, non-testtun interface"); |
| 315 | } |
| 316 | |
| 317 | // Setup needs to be done with NETWORK_STACK privileges. |
| 318 | int callingUid = Binder.getCallingUid(); |
| 319 | Binder.withCleanCallingIdentity( |
| 320 | () -> { |
| 321 | try { |
| 322 | mNMS.setInterfaceUp(iface); |
| 323 | |
| 324 | // Synchronize all accesses to mTestNetworkTracker to prevent the case |
| 325 | // where: |
| 326 | // 1. TestNetworkAgent successfully binds to death of binder |
| 327 | // 2. Before it is added to the mTestNetworkTracker, binder dies, |
| 328 | // binderDied() is called (on a different thread) |
| 329 | // 3. This thread is pre-empted, put() is called after remove() |
| 330 | synchronized (mTestNetworkTracker) { |
| 331 | TestNetworkAgent agent = |
| 332 | registerTestNetworkAgent( |
| 333 | mHandler.getLooper(), |
| 334 | mContext, |
| 335 | iface, |
Benedict Wong | 512ab0d | 2019-04-18 19:18:43 -0700 | [diff] [blame] | 336 | lp, |
| 337 | isMetered, |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 338 | callingUid, |
| 339 | binder); |
| 340 | |
| 341 | mTestNetworkTracker.put(agent.netId, agent); |
| 342 | } |
| 343 | } catch (SocketException e) { |
| 344 | throw new UncheckedIOException(e); |
| 345 | } catch (RemoteException e) { |
| 346 | throw e.rethrowFromSystemServer(); |
| 347 | } |
| 348 | }); |
| 349 | } |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 350 | |
| 351 | /** Teardown a test network */ |
| 352 | @Override |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 353 | public void teardownTestNetwork(int netId) { |
| 354 | enforceTestNetworkPermissions(mContext); |
| 355 | |
Benedict Wong | 7df36ed | 2019-03-12 21:54:16 -0700 | [diff] [blame] | 356 | final TestNetworkAgent agent; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 357 | synchronized (mTestNetworkTracker) { |
| 358 | agent = mTestNetworkTracker.get(netId); |
| 359 | } |
| 360 | |
| 361 | if (agent == null) { |
| 362 | return; // Already torn down |
| 363 | } else if (agent.mUid != Binder.getCallingUid()) { |
| 364 | throw new SecurityException("Attempted to modify other user's test networks"); |
| 365 | } |
| 366 | |
| 367 | // Safe to be called multiple times. |
| 368 | agent.teardown(); |
| 369 | } |
| 370 | |
Benedict Wong | 3ec38dc | 2019-04-09 16:29:43 -0700 | [diff] [blame] | 371 | private static final String PERMISSION_NAME = |
| 372 | android.Manifest.permission.MANAGE_TEST_NETWORKS; |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 373 | |
| 374 | public static void enforceTestNetworkPermissions(@NonNull Context context) { |
Benedict Wong | 3ec38dc | 2019-04-09 16:29:43 -0700 | [diff] [blame] | 375 | context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService"); |
Benedict Wong | 6c24213 | 2018-11-14 17:53:19 -0800 | [diff] [blame] | 376 | } |
Benedict Wong | e40eab6 | 2018-11-14 17:50:13 -0800 | [diff] [blame] | 377 | } |