blob: d19d2ddd7c3c93edb3a6186a1627ec43975cac27 [file] [log] [blame]
Benedict Wonge40eab62018-11-14 17:50:13 -08001/*
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
17package com.android.server;
18
19import static com.android.internal.util.Preconditions.checkNotNull;
20
21import android.annotation.NonNull;
Benedict Wong512ab0d2019-04-18 19:18:43 -070022import android.annotation.Nullable;
Benedict Wonge40eab62018-11-14 17:50:13 -080023import android.content.Context;
Benedict Wong6c242132018-11-14 17:53:19 -080024import android.net.ConnectivityManager;
Benedict Wonge40eab62018-11-14 17:50:13 -080025import android.net.INetd;
26import android.net.ITestNetworkManager;
Benedict Wong6c242132018-11-14 17:53:19 -080027import android.net.IpPrefix;
Benedict Wonge40eab62018-11-14 17:50:13 -080028import android.net.LinkAddress;
Benedict Wong6c242132018-11-14 17:53:19 -080029import android.net.LinkProperties;
30import android.net.NetworkAgent;
31import android.net.NetworkCapabilities;
32import android.net.NetworkInfo;
33import android.net.NetworkInfo.DetailedState;
34import android.net.RouteInfo;
35import android.net.StringNetworkSpecifier;
Benedict Wonge40eab62018-11-14 17:50:13 -080036import android.net.TestNetworkInterface;
37import android.net.util.NetdService;
Benedict Wong6c242132018-11-14 17:53:19 -080038import android.os.Binder;
Benedict Wonge40eab62018-11-14 17:50:13 -080039import android.os.Handler;
40import android.os.HandlerThread;
41import android.os.IBinder;
42import android.os.INetworkManagementService;
Benedict Wong6c242132018-11-14 17:53:19 -080043import android.os.Looper;
44import android.os.ParcelFileDescriptor;
45import android.os.RemoteException;
46import android.util.SparseArray;
Benedict Wonge40eab62018-11-14 17:50:13 -080047
Benedict Wong6c242132018-11-14 17:53:19 -080048import com.android.internal.annotations.GuardedBy;
Benedict Wonge40eab62018-11-14 17:50:13 -080049import com.android.internal.annotations.VisibleForTesting;
50
Benedict Wong6c242132018-11-14 17:53:19 -080051import java.io.UncheckedIOException;
52import java.net.Inet4Address;
53import java.net.Inet6Address;
54import java.net.InterfaceAddress;
55import java.net.NetworkInterface;
56import java.net.SocketException;
Benedict Wong512ab0d2019-04-18 19:18:43 -070057import java.util.ArrayList;
Benedict Wong6c242132018-11-14 17:53:19 -080058import java.util.concurrent.atomic.AtomicInteger;
59
Benedict Wonge40eab62018-11-14 17:50:13 -080060/** @hide */
61class 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 Wong6c242132018-11-14 17:53:19 -080064 @NonNull private static final String TEST_TUN_PREFIX = "testtun";
Lorenzo Colittib15fcce2019-04-01 23:41:12 +090065 @NonNull private static final String TEST_TAP_PREFIX = "testtap";
Benedict Wong6c242132018-11-14 17:53:19 -080066 @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
Benedict Wonge40eab62018-11-14 17:50:13 -080067
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 Wong6c242132018-11-14 17:53:19 -080075 // Native method stubs
Lorenzo Colittib15fcce2019-04-01 23:41:12 +090076 private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
Benedict Wong6c242132018-11-14 17:53:19 -080077
Benedict Wonge40eab62018-11-14 17:50:13 -080078 @VisibleForTesting
79 protected TestNetworkService(
80 @NonNull Context context, @NonNull INetworkManagementService netManager) {
Benedict Wonge40eab62018-11-14 17:50:13 -080081 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 Wong6c242132018-11-14 17:53:19 -080087 mNetd = checkNotNull(NetdService.getInstance(), "could not get netd instance");
Benedict Wonge40eab62018-11-14 17:50:13 -080088 }
89
90 /**
Lorenzo Colittib15fcce2019-04-01 23:41:12 +090091 * Create a TUN or TAP interface with the given interface name and link addresses
Benedict Wonge40eab62018-11-14 17:50:13 -080092 *
Lorenzo Colittib15fcce2019-04-01 23:41:12 +090093 * <p>This method will return the FileDescriptor to the interface. Close it to tear down the
94 * interface.
Benedict Wonge40eab62018-11-14 17:50:13 -080095 */
Lorenzo Colittib15fcce2019-04-01 23:41:12 +090096 private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
Benedict Wong6c242132018-11-14 17:53:19 -080097 enforceTestNetworkPermissions(mContext);
98
99 checkNotNull(linkAddrs, "missing linkAddrs");
100
Lorenzo Colittib15fcce2019-04-01 23:41:12 +0900101 String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
102 String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
Benedict Wong6c242132018-11-14 17:53:19 -0800103 return Binder.withCleanCallingIdentity(
104 () -> {
105 try {
106 ParcelFileDescriptor tunIntf =
Lorenzo Colittib15fcce2019-04-01 23:41:12 +0900107 ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
Benedict Wong6c242132018-11-14 17:53:19 -0800108 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 Colittib15fcce2019-04-01 23:41:12 +0900122 /**
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 Wong6c242132018-11-14 17:53:19 -0800144 // 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 Wong512ab0d2019-04-18 19:18:43 -0700231 @Nullable LinkProperties lp,
232 boolean isMetered,
Benedict Wong6c242132018-11-14 17:53:19 -0800233 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 Wong512ab0d2019-04-18 19:18:43 -0700252 if (!isMetered) {
253 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
254 }
Benedict Wong6c242132018-11-14 17:53:19 -0800255
256 // Build LinkProperties
Benedict Wong512ab0d2019-04-18 19:18:43 -0700257 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 Wong6c242132018-11-14 17:53:19 -0800265 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 Wonge40eab62018-11-14 17:50:13 -0800292 }
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 Wong512ab0d2019-04-18 19:18:43 -0700301 public void setupTestNetwork(
302 @NonNull String iface,
303 @Nullable LinkProperties lp,
304 boolean isMetered,
305 @NonNull IBinder binder) {
Benedict Wong6c242132018-11-14 17:53:19 -0800306 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 Wong512ab0d2019-04-18 19:18:43 -0700336 lp,
337 isMetered,
Benedict Wong6c242132018-11-14 17:53:19 -0800338 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 Wonge40eab62018-11-14 17:50:13 -0800350
351 /** Teardown a test network */
352 @Override
Benedict Wong6c242132018-11-14 17:53:19 -0800353 public void teardownTestNetwork(int netId) {
354 enforceTestNetworkPermissions(mContext);
355
Benedict Wong7df36ed2019-03-12 21:54:16 -0700356 final TestNetworkAgent agent;
Benedict Wong6c242132018-11-14 17:53:19 -0800357 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 Wong3ec38dc2019-04-09 16:29:43 -0700371 private static final String PERMISSION_NAME =
372 android.Manifest.permission.MANAGE_TEST_NETWORKS;
Benedict Wong6c242132018-11-14 17:53:19 -0800373
374 public static void enforceTestNetworkPermissions(@NonNull Context context) {
Benedict Wong3ec38dc2019-04-09 16:29:43 -0700375 context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
Benedict Wong6c242132018-11-14 17:53:19 -0800376 }
Benedict Wonge40eab62018-11-14 17:50:13 -0800377}