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