• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 android.net;
18 
19 import android.app.Activity;
20 import android.app.Service;
21 import android.app.PendingIntent;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.os.Binder;
25 import android.os.IBinder;
26 import android.os.Parcel;
27 import android.os.ParcelFileDescriptor;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 
31 import com.android.internal.net.VpnConfig;
32 
33 import java.net.InetAddress;
34 import java.net.Inet4Address;
35 import java.net.Inet6Address;
36 import java.net.DatagramSocket;
37 import java.net.Socket;
38 import java.util.ArrayList;
39 
40 /**
41  * VpnService is a base class for applications to extend and build their
42  * own VPN solutions. In general, it creates a virtual network interface,
43  * configures addresses and routing rules, and returns a file descriptor
44  * to the application. Each read from the descriptor retrieves an outgoing
45  * packet which was routed to the interface. Each write to the descriptor
46  * injects an incoming packet just like it was received from the interface.
47  * The interface is running on Internet Protocol (IP), so packets are
48  * always started with IP headers. The application then completes a VPN
49  * connection by processing and exchanging packets with the remote server
50  * over a tunnel.
51  *
52  * <p>Letting applications intercept packets raises huge security concerns.
53  * A VPN application can easily break the network. Besides, two of them may
54  * conflict with each other. The system takes several actions to address
55  * these issues. Here are some key points:
56  * <ul>
57  *   <li>User action is required to create a VPN connection.</li>
58  *   <li>There can be only one VPN connection running at the same time. The
59  *       existing interface is deactivated when a new one is created.</li>
60  *   <li>A system-managed notification is shown during the lifetime of a
61  *       VPN connection.</li>
62  *   <li>A system-managed dialog gives the information of the current VPN
63  *       connection. It also provides a button to disconnect.</li>
64  *   <li>The network is restored automatically when the file descriptor is
65  *       closed. It also covers the cases when a VPN application is crashed
66  *       or killed by the system.</li>
67  * </ul>
68  *
69  * <p>There are two primary methods in this class: {@link #prepare} and
70  * {@link Builder#establish}. The former deals with user action and stops
71  * the VPN connection created by another application. The latter creates
72  * a VPN interface using the parameters supplied to the {@link Builder}.
73  * An application must call {@link #prepare} to grant the right to use
74  * other methods in this class, and the right can be revoked at any time.
75  * Here are the general steps to create a VPN connection:
76  * <ol>
77  *   <li>When the user press the button to connect, call {@link #prepare}
78  *       and launch the returned intent.</li>
79  *   <li>When the application becomes prepared, start the service.</li>
80  *   <li>Create a tunnel to the remote server and negotiate the network
81  *       parameters for the VPN connection.</li>
82  *   <li>Supply those parameters to a {@link Builder} and create a VPN
83  *       interface by calling {@link Builder#establish}.</li>
84  *   <li>Process and exchange packets between the tunnel and the returned
85  *       file descriptor.</li>
86  *   <li>When {@link #onRevoke} is invoked, close the file descriptor and
87  *       shut down the tunnel gracefully.</li>
88  * </ol>
89  *
90  * <p>Services extended this class need to be declared with appropriate
91  * permission and intent filter. Their access must be secured by
92  * {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and
93  * their intent filter must match {@link #SERVICE_INTERFACE} action. Here
94  * is an example of declaring a VPN service in {@code AndroidManifest.xml}:
95  * <pre>
96  * &lt;service android:name=".ExampleVpnService"
97  *         android:permission="android.permission.BIND_VPN_SERVICE"&gt;
98  *     &lt;intent-filter&gt;
99  *         &lt;action android:name="android.net.VpnService"/&gt;
100  *     &lt;/intent-filter&gt;
101  * &lt;/service&gt;</pre>
102  *
103  * @see Builder
104  */
105 public class VpnService extends Service {
106 
107     /**
108      * The action must be matched by the intent filter of this service. It also
109      * needs to require {@link android.Manifest.permission#BIND_VPN_SERVICE}
110      * permission so that other applications cannot abuse it.
111      */
112     public static final String SERVICE_INTERFACE = VpnConfig.SERVICE_INTERFACE;
113 
114     /**
115      * Use IConnectivityManager since those methods are hidden and not
116      * available in ConnectivityManager.
117      */
getService()118     private static IConnectivityManager getService() {
119         return IConnectivityManager.Stub.asInterface(
120                 ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
121     }
122 
123     /**
124      * Prepare to establish a VPN connection. This method returns {@code null}
125      * if the VPN application is already prepared. Otherwise, it returns an
126      * {@link Intent} to a system activity. The application should launch the
127      * activity using {@link Activity#startActivityForResult} to get itself
128      * prepared. The activity may pop up a dialog to require user action, and
129      * the result will come back via its {@link Activity#onActivityResult}.
130      * If the result is {@link Activity#RESULT_OK}, the application becomes
131      * prepared and is granted to use other methods in this class.
132      *
133      * <p>Only one application can be granted at the same time. The right
134      * is revoked when another application is granted. The application
135      * losing the right will be notified via its {@link #onRevoke}. Unless
136      * it becomes prepared again, subsequent calls to other methods in this
137      * class will fail.
138      *
139      * @see #onRevoke
140      */
prepare(Context context)141     public static Intent prepare(Context context) {
142         try {
143             if (getService().prepareVpn(context.getPackageName(), null)) {
144                 return null;
145             }
146         } catch (RemoteException e) {
147             // ignore
148         }
149         return VpnConfig.getIntentForConfirmation();
150     }
151 
152     /**
153      * Protect a socket from VPN connections. The socket will be bound to the
154      * current default network interface, so its traffic will not be forwarded
155      * through VPN. This method is useful if some connections need to be kept
156      * outside of VPN. For example, a VPN tunnel should protect itself if its
157      * destination is covered by VPN routes. Otherwise its outgoing packets
158      * will be sent back to the VPN interface and cause an infinite loop. This
159      * method will fail if the application is not prepared or is revoked.
160      *
161      * <p class="note">The socket is NOT closed by this method.
162      *
163      * @return {@code true} on success.
164      */
protect(int socket)165     public boolean protect(int socket) {
166         ParcelFileDescriptor dup = null;
167         try {
168             dup = ParcelFileDescriptor.fromFd(socket);
169             return getService().protectVpn(dup);
170         } catch (Exception e) {
171             return false;
172         } finally {
173             try {
174                 dup.close();
175             } catch (Exception e) {
176                 // ignore
177             }
178         }
179     }
180 
181     /**
182      * Convenience method to protect a {@link Socket} from VPN connections.
183      *
184      * @return {@code true} on success.
185      * @see #protect(int)
186      */
protect(Socket socket)187     public boolean protect(Socket socket) {
188         return protect(socket.getFileDescriptor$().getInt$());
189     }
190 
191     /**
192      * Convenience method to protect a {@link DatagramSocket} from VPN
193      * connections.
194      *
195      * @return {@code true} on success.
196      * @see #protect(int)
197      */
protect(DatagramSocket socket)198     public boolean protect(DatagramSocket socket) {
199         return protect(socket.getFileDescriptor$().getInt$());
200     }
201 
202     /**
203      * Return the communication interface to the service. This method returns
204      * {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE}
205      * action. Applications overriding this method must identify the intent
206      * and return the corresponding interface accordingly.
207      *
208      * @see Service#onBind
209      */
210     @Override
onBind(Intent intent)211     public IBinder onBind(Intent intent) {
212         if (intent != null && SERVICE_INTERFACE.equals(intent.getAction())) {
213             return new Callback();
214         }
215         return null;
216     }
217 
218     /**
219      * Invoked when the application is revoked. At this moment, the VPN
220      * interface is already deactivated by the system. The application should
221      * close the file descriptor and shut down gracefully. The default
222      * implementation of this method is calling {@link Service#stopSelf()}.
223      *
224      * <p class="note">Calls to this method may not happen on the main thread
225      * of the process.
226      *
227      * @see #prepare
228      */
onRevoke()229     public void onRevoke() {
230         stopSelf();
231     }
232 
233     /**
234      * Use raw Binder instead of AIDL since now there is only one usage.
235      */
236     private class Callback extends Binder {
237         @Override
onTransact(int code, Parcel data, Parcel reply, int flags)238         protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
239             if (code == IBinder.LAST_CALL_TRANSACTION) {
240                 onRevoke();
241                 return true;
242             }
243             return false;
244         }
245     }
246 
247     /**
248      * Helper class to create a VPN interface. This class should be always
249      * used within the scope of the outer {@link VpnService}.
250      *
251      * @see VpnService
252      */
253     public class Builder {
254 
255         private final VpnConfig mConfig = new VpnConfig();
256         private final StringBuilder mAddresses = new StringBuilder();
257         private final StringBuilder mRoutes = new StringBuilder();
258 
Builder()259         public Builder() {
260             mConfig.user = VpnService.this.getClass().getName();
261         }
262 
263         /**
264          * Set the name of this session. It will be displayed in
265          * system-managed dialogs and notifications. This is recommended
266          * not required.
267          */
setSession(String session)268         public Builder setSession(String session) {
269             mConfig.session = session;
270             return this;
271         }
272 
273         /**
274          * Set the {@link PendingIntent} to an activity for users to
275          * configure the VPN connection. If it is not set, the button
276          * to configure will not be shown in system-managed dialogs.
277          */
setConfigureIntent(PendingIntent intent)278         public Builder setConfigureIntent(PendingIntent intent) {
279             mConfig.configureIntent = intent;
280             return this;
281         }
282 
283         /**
284          * Set the maximum transmission unit (MTU) of the VPN interface. If
285          * it is not set, the default value in the operating system will be
286          * used.
287          *
288          * @throws IllegalArgumentException if the value is not positive.
289          */
setMtu(int mtu)290         public Builder setMtu(int mtu) {
291             if (mtu <= 0) {
292                 throw new IllegalArgumentException("Bad mtu");
293             }
294             mConfig.mtu = mtu;
295             return this;
296         }
297 
298         /**
299          * Private method to validate address and prefixLength.
300          */
check(InetAddress address, int prefixLength)301         private void check(InetAddress address, int prefixLength) {
302             if (address.isLoopbackAddress()) {
303                 throw new IllegalArgumentException("Bad address");
304             }
305             if (address instanceof Inet4Address) {
306                 if (prefixLength < 0 || prefixLength > 32) {
307                     throw new IllegalArgumentException("Bad prefixLength");
308                 }
309             } else if (address instanceof Inet6Address) {
310                 if (prefixLength < 0 || prefixLength > 128) {
311                     throw new IllegalArgumentException("Bad prefixLength");
312                 }
313             } else {
314                 throw new IllegalArgumentException("Unsupported family");
315             }
316         }
317 
318         /**
319          * Add a network address to the VPN interface. Both IPv4 and IPv6
320          * addresses are supported. At least one address must be set before
321          * calling {@link #establish}.
322          *
323          * @throws IllegalArgumentException if the address is invalid.
324          */
addAddress(InetAddress address, int prefixLength)325         public Builder addAddress(InetAddress address, int prefixLength) {
326             check(address, prefixLength);
327 
328             if (address.isAnyLocalAddress()) {
329                 throw new IllegalArgumentException("Bad address");
330             }
331 
332             mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
333             return this;
334         }
335 
336         /**
337          * Convenience method to add a network address to the VPN interface
338          * using a numeric address string. See {@link InetAddress} for the
339          * definitions of numeric address formats.
340          *
341          * @throws IllegalArgumentException if the address is invalid.
342          * @see #addAddress(InetAddress, int)
343          */
addAddress(String address, int prefixLength)344         public Builder addAddress(String address, int prefixLength) {
345             return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
346         }
347 
348         /**
349          * Add a network route to the VPN interface. Both IPv4 and IPv6
350          * routes are supported.
351          *
352          * @throws IllegalArgumentException if the route is invalid.
353          */
addRoute(InetAddress address, int prefixLength)354         public Builder addRoute(InetAddress address, int prefixLength) {
355             check(address, prefixLength);
356 
357             int offset = prefixLength / 8;
358             byte[] bytes = address.getAddress();
359             if (offset < bytes.length) {
360                 for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) {
361                     if (bytes[offset] != 0) {
362                         throw new IllegalArgumentException("Bad address");
363                     }
364                 }
365             }
366 
367             mRoutes.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
368             return this;
369         }
370 
371         /**
372          * Convenience method to add a network route to the VPN interface
373          * using a numeric address string. See {@link InetAddress} for the
374          * definitions of numeric address formats.
375          *
376          * @throws IllegalArgumentException if the route is invalid.
377          * @see #addRoute(InetAddress, int)
378          */
addRoute(String address, int prefixLength)379         public Builder addRoute(String address, int prefixLength) {
380             return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
381         }
382 
383         /**
384          * Add a DNS server to the VPN connection. Both IPv4 and IPv6
385          * addresses are supported. If none is set, the DNS servers of
386          * the default network will be used.
387          *
388          * @throws IllegalArgumentException if the address is invalid.
389          */
addDnsServer(InetAddress address)390         public Builder addDnsServer(InetAddress address) {
391             if (address.isLoopbackAddress() || address.isAnyLocalAddress()) {
392                 throw new IllegalArgumentException("Bad address");
393             }
394             if (mConfig.dnsServers == null) {
395                 mConfig.dnsServers = new ArrayList<String>();
396             }
397             mConfig.dnsServers.add(address.getHostAddress());
398             return this;
399         }
400 
401         /**
402          * Convenience method to add a DNS server to the VPN connection
403          * using a numeric address string. See {@link InetAddress} for the
404          * definitions of numeric address formats.
405          *
406          * @throws IllegalArgumentException if the address is invalid.
407          * @see #addDnsServer(InetAddress)
408          */
addDnsServer(String address)409         public Builder addDnsServer(String address) {
410             return addDnsServer(InetAddress.parseNumericAddress(address));
411         }
412 
413         /**
414          * Add a search domain to the DNS resolver.
415          */
addSearchDomain(String domain)416         public Builder addSearchDomain(String domain) {
417             if (mConfig.searchDomains == null) {
418                 mConfig.searchDomains = new ArrayList<String>();
419             }
420             mConfig.searchDomains.add(domain);
421             return this;
422         }
423 
424         /**
425          * Create a VPN interface using the parameters supplied to this
426          * builder. The interface works on IP packets, and a file descriptor
427          * is returned for the application to access them. Each read
428          * retrieves an outgoing packet which was routed to the interface.
429          * Each write injects an incoming packet just like it was received
430          * from the interface. The file descriptor is put into non-blocking
431          * mode by default to avoid blocking Java threads. To use the file
432          * descriptor completely in native space, see
433          * {@link ParcelFileDescriptor#detachFd()}. The application MUST
434          * close the file descriptor when the VPN connection is terminated.
435          * The VPN interface will be removed and the network will be
436          * restored by the system automatically.
437          *
438          * <p>To avoid conflicts, there can be only one active VPN interface
439          * at the same time. Usually network parameters are never changed
440          * during the lifetime of a VPN connection. It is also common for an
441          * application to create a new file descriptor after closing the
442          * previous one. However, it is rare but not impossible to have two
443          * interfaces while performing a seamless handover. In this case, the
444          * old interface will be deactivated when the new one is created
445          * successfully. Both file descriptors are valid but now outgoing
446          * packets will be routed to the new interface. Therefore, after
447          * draining the old file descriptor, the application MUST close it
448          * and start using the new file descriptor. If the new interface
449          * cannot be created, the existing interface and its file descriptor
450          * remain untouched.
451          *
452          * <p>An exception will be thrown if the interface cannot be created
453          * for any reason. However, this method returns {@code null} if the
454          * application is not prepared or is revoked. This helps solve
455          * possible race conditions between other VPN applications.
456          *
457          * @return {@link ParcelFileDescriptor} of the VPN interface, or
458          *         {@code null} if the application is not prepared.
459          * @throws IllegalArgumentException if a parameter is not accepted
460          *         by the operating system.
461          * @throws IllegalStateException if a parameter cannot be applied
462          *         by the operating system.
463          * @throws SecurityException if the service is not properly declared
464          *         in {@code AndroidManifest.xml}.
465          * @see VpnService
466          */
establish()467         public ParcelFileDescriptor establish() {
468             mConfig.addresses = mAddresses.toString();
469             mConfig.routes = mRoutes.toString();
470 
471             try {
472                 return getService().establishVpn(mConfig);
473             } catch (RemoteException e) {
474                 throw new IllegalStateException(e);
475             }
476         }
477     }
478 }
479