blob: 0ea73460e105a84a8e0fb3d32fbd354309b4d504 [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
Lorenzo Colitti6fba2a82020-03-19 11:46:55 +000019import static android.net.TestNetworkManager.TEST_TAP_PREFIX;
20import static android.net.TestNetworkManager.TEST_TUN_PREFIX;
21
Benedict Wonge40eab62018-11-14 17:50:13 -080022import android.annotation.NonNull;
Benedict Wong512ab0d2019-04-18 19:18:43 -070023import android.annotation.Nullable;
Benedict Wonge40eab62018-11-14 17:50:13 -080024import android.content.Context;
Benedict Wong6c242132018-11-14 17:53:19 -080025import android.net.ConnectivityManager;
Benedict Wonge40eab62018-11-14 17:50:13 -080026import android.net.INetd;
27import android.net.ITestNetworkManager;
Benedict Wong6c242132018-11-14 17:53:19 -080028import android.net.IpPrefix;
Benedict Wonge40eab62018-11-14 17:50:13 -080029import android.net.LinkAddress;
Benedict Wong6c242132018-11-14 17:53:19 -080030import android.net.LinkProperties;
31import android.net.NetworkAgent;
32import android.net.NetworkCapabilities;
33import android.net.NetworkInfo;
34import android.net.NetworkInfo.DetailedState;
35import android.net.RouteInfo;
36import android.net.StringNetworkSpecifier;
Benedict Wonge40eab62018-11-14 17:50:13 -080037import android.net.TestNetworkInterface;
38import android.net.util.NetdService;
Benedict Wong6c242132018-11-14 17:53:19 -080039import android.os.Binder;
Benedict Wonge40eab62018-11-14 17:50:13 -080040import android.os.Handler;
41import android.os.HandlerThread;
42import android.os.IBinder;
43import android.os.INetworkManagementService;
Benedict Wong6c242132018-11-14 17:53:19 -080044import android.os.Looper;
45import android.os.ParcelFileDescriptor;
46import android.os.RemoteException;
47import android.util.SparseArray;
Benedict Wonge40eab62018-11-14 17:50:13 -080048
Benedict Wong6c242132018-11-14 17:53:19 -080049import com.android.internal.annotations.GuardedBy;
Benedict Wonge40eab62018-11-14 17:50:13 -080050import com.android.internal.annotations.VisibleForTesting;
51
Benedict Wong6c242132018-11-14 17:53:19 -080052import java.io.UncheckedIOException;
53import java.net.Inet4Address;
54import java.net.Inet6Address;
55import java.net.InterfaceAddress;
56import java.net.NetworkInterface;
57import java.net.SocketException;
Benedict Wong512ab0d2019-04-18 19:18:43 -070058import java.util.ArrayList;
Daulet Zhanguzinea1a7ca2020-01-03 09:46:50 +000059import java.util.Objects;
Benedict Wong6c242132018-11-14 17:53:19 -080060import java.util.concurrent.atomic.AtomicInteger;
61
Benedict Wonge40eab62018-11-14 17:50:13 -080062/** @hide */
63class TestNetworkService extends ITestNetworkManager.Stub {
64 @NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
65 @NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
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
Daulet Zhanguzinea1a7ca2020-01-03 09:46:50 +000085 mContext = Objects.requireNonNull(context, "missing Context");
86 mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
87 mNetd = Objects.requireNonNull(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
Daulet Zhanguzinea1a7ca2020-01-03 09:46:50 +000099 Objects.requireNonNull(linkAddrs, "missing linkAddrs");
Benedict Wong6c242132018-11-14 17:53:19 -0800100
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) {
Chalard Jean29c6e0c2020-01-16 17:13:26 +0900222 mTestNetworkTracker.remove(getNetwork().netId);
Benedict Wong6c242132018-11-14 17:53:19 -0800223 }
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,
Automerger Merge Workerfcfddef2020-03-16 20:31:58 +0000234 @NonNull int[] administratorUids,
Benedict Wong6c242132018-11-14 17:53:19 -0800235 @NonNull IBinder binder)
236 throws RemoteException, SocketException {
Daulet Zhanguzinea1a7ca2020-01-03 09:46:50 +0000237 Objects.requireNonNull(looper, "missing Looper");
238 Objects.requireNonNull(context, "missing Context");
Benedict Wong6c242132018-11-14 17:53:19 -0800239 // iface and binder validity checked by caller
240
241 // Build network info with special testing type
242 NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_TEST, 0, TEST_NETWORK_TYPE, "");
243 ni.setDetailedState(DetailedState.CONNECTED, null, null);
244 ni.setIsAvailable(true);
245
246 // Build narrow set of NetworkCapabilities, useful only for testing
247 NetworkCapabilities nc = new NetworkCapabilities();
248 nc.clearAll(); // Remove default capabilities.
249 nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
250 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
251 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
252 nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
Cody Kestingf7ac9962020-03-16 18:15:28 -0700253 nc.setAdministratorUids(administratorUids);
Benedict Wong512ab0d2019-04-18 19:18:43 -0700254 if (!isMetered) {
255 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
256 }
Benedict Wong6c242132018-11-14 17:53:19 -0800257
258 // Build LinkProperties
Benedict Wong512ab0d2019-04-18 19:18:43 -0700259 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 }
Benedict Wong6c242132018-11-14 17:53:19 -0800267 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);
Daulet Zhanguzinea1a7ca2020-01-03 09:46:50 +0000272 Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf);
Benedict Wong6c242132018-11-14 17:53:19 -0800273
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(Inet4Address.ANY, 0), null, iface));
288 }
289 if (allowIPv6) {
290 lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
291 }
292
293 return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder);
Benedict Wonge40eab62018-11-14 17:50:13 -0800294 }
295
296 /**
297 * Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS
298 * permission.
299 *
300 * <p>This method provides a Network that is useful only for testing.
301 */
302 @Override
Benedict Wong512ab0d2019-04-18 19:18:43 -0700303 public void setupTestNetwork(
304 @NonNull String iface,
305 @Nullable LinkProperties lp,
306 boolean isMetered,
Automerger Merge Workerfcfddef2020-03-16 20:31:58 +0000307 @NonNull int[] administratorUids,
Benedict Wong512ab0d2019-04-18 19:18:43 -0700308 @NonNull IBinder binder) {
Benedict Wong6c242132018-11-14 17:53:19 -0800309 enforceTestNetworkPermissions(mContext);
310
Daulet Zhanguzinea1a7ca2020-01-03 09:46:50 +0000311 Objects.requireNonNull(iface, "missing Iface");
312 Objects.requireNonNull(binder, "missing IBinder");
Benedict Wong6c242132018-11-14 17:53:19 -0800313
314 if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX)
315 || iface.startsWith(TEST_TUN_PREFIX))) {
316 throw new IllegalArgumentException(
317 "Cannot create network for non ipsec, non-testtun interface");
318 }
319
320 // Setup needs to be done with NETWORK_STACK privileges.
321 int callingUid = Binder.getCallingUid();
322 Binder.withCleanCallingIdentity(
323 () -> {
324 try {
325 mNMS.setInterfaceUp(iface);
326
327 // Synchronize all accesses to mTestNetworkTracker to prevent the case
328 // where:
329 // 1. TestNetworkAgent successfully binds to death of binder
330 // 2. Before it is added to the mTestNetworkTracker, binder dies,
331 // binderDied() is called (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,
Benedict Wong512ab0d2019-04-18 19:18:43 -0700339 lp,
340 isMetered,
Benedict Wong6c242132018-11-14 17:53:19 -0800341 callingUid,
Automerger Merge Workerfcfddef2020-03-16 20:31:58 +0000342 administratorUids,
Benedict Wong6c242132018-11-14 17:53:19 -0800343 binder);
344
Chalard Jean29c6e0c2020-01-16 17:13:26 +0900345 mTestNetworkTracker.put(agent.getNetwork().netId, agent);
Benedict Wong6c242132018-11-14 17:53:19 -0800346 }
347 } catch (SocketException e) {
348 throw new UncheckedIOException(e);
349 } catch (RemoteException e) {
350 throw e.rethrowFromSystemServer();
351 }
352 });
353 }
Benedict Wonge40eab62018-11-14 17:50:13 -0800354
355 /** Teardown a test network */
356 @Override
Benedict Wong6c242132018-11-14 17:53:19 -0800357 public void teardownTestNetwork(int netId) {
358 enforceTestNetworkPermissions(mContext);
359
Benedict Wong7df36ed2019-03-12 21:54:16 -0700360 final TestNetworkAgent agent;
Benedict Wong6c242132018-11-14 17:53:19 -0800361 synchronized (mTestNetworkTracker) {
362 agent = mTestNetworkTracker.get(netId);
363 }
364
365 if (agent == null) {
366 return; // Already torn down
367 } else if (agent.mUid != Binder.getCallingUid()) {
368 throw new SecurityException("Attempted to modify other user's test networks");
369 }
370
371 // Safe to be called multiple times.
372 agent.teardown();
373 }
374
Benedict Wong3ec38dc2019-04-09 16:29:43 -0700375 private static final String PERMISSION_NAME =
376 android.Manifest.permission.MANAGE_TEST_NETWORKS;
Benedict Wong6c242132018-11-14 17:53:19 -0800377
378 public static void enforceTestNetworkPermissions(@NonNull Context context) {
Benedict Wong3ec38dc2019-04-09 16:29:43 -0700379 context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
Benedict Wong6c242132018-11-14 17:53:19 -0800380 }
Benedict Wonge40eab62018-11-14 17:50:13 -0800381}