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