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