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