Home | History | Annotate | Download | only in net
      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.PendingIntent;
     21 import android.app.Service;
     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.DatagramSocket;
     34 import java.net.Inet4Address;
     35 import java.net.Inet6Address;
     36 import java.net.InetAddress;
     37 import java.net.Socket;
     38 import java.util.ArrayList;
     39 import java.util.List;
     40 
     41 /**
     42  * VpnService is a base class for applications to extend and build their
     43  * own VPN solutions. In general, it creates a virtual network interface,
     44  * configures addresses and routing rules, and returns a file descriptor
     45  * to the application. Each read from the descriptor retrieves an outgoing
     46  * packet which was routed to the interface. Each write to the descriptor
     47  * injects an incoming packet just like it was received from the interface.
     48  * The interface is running on Internet Protocol (IP), so packets are
     49  * always started with IP headers. The application then completes a VPN
     50  * connection by processing and exchanging packets with the remote server
     51  * over a tunnel.
     52  *
     53  * <p>Letting applications intercept packets raises huge security concerns.
     54  * A VPN application can easily break the network. Besides, two of them may
     55  * conflict with each other. The system takes several actions to address
     56  * these issues. Here are some key points:
     57  * <ul>
     58  *   <li>User action is required to create a VPN connection.</li>
     59  *   <li>There can be only one VPN connection running at the same time. The
     60  *       existing interface is deactivated when a new one is created.</li>
     61  *   <li>A system-managed notification is shown during the lifetime of a
     62  *       VPN connection.</li>
     63  *   <li>A system-managed dialog gives the information of the current VPN
     64  *       connection. It also provides a button to disconnect.</li>
     65  *   <li>The network is restored automatically when the file descriptor is
     66  *       closed. It also covers the cases when a VPN application is crashed
     67  *       or killed by the system.</li>
     68  * </ul>
     69  *
     70  * <p>There are two primary methods in this class: {@link #prepare} and
     71  * {@link Builder#establish}. The former deals with user action and stops
     72  * the VPN connection created by another application. The latter creates
     73  * a VPN interface using the parameters supplied to the {@link Builder}.
     74  * An application must call {@link #prepare} to grant the right to use
     75  * other methods in this class, and the right can be revoked at any time.
     76  * Here are the general steps to create a VPN connection:
     77  * <ol>
     78  *   <li>When the user press the button to connect, call {@link #prepare}
     79  *       and launch the returned intent.</li>
     80  *   <li>When the application becomes prepared, start the service.</li>
     81  *   <li>Create a tunnel to the remote server and negotiate the network
     82  *       parameters for the VPN connection.</li>
     83  *   <li>Supply those parameters to a {@link Builder} and create a VPN
     84  *       interface by calling {@link Builder#establish}.</li>
     85  *   <li>Process and exchange packets between the tunnel and the returned
     86  *       file descriptor.</li>
     87  *   <li>When {@link #onRevoke} is invoked, close the file descriptor and
     88  *       shut down the tunnel gracefully.</li>
     89  * </ol>
     90  *
     91  * <p>Services extended this class need to be declared with appropriate
     92  * permission and intent filter. Their access must be secured by
     93  * {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and
     94  * their intent filter must match {@link #SERVICE_INTERFACE} action. Here
     95  * is an example of declaring a VPN service in {@code AndroidManifest.xml}:
     96  * <pre>
     97  * &lt;service android:name=".ExampleVpnService"
     98  *         android:permission="android.permission.BIND_VPN_SERVICE"&gt;
     99  *     &lt;intent-filter&gt;
    100  *         &lt;action android:name="android.net.VpnService"/&gt;
    101  *     &lt;/intent-filter&gt;
    102  * &lt;/service&gt;</pre>
    103  *
    104  * @see Builder
    105  */
    106 public class VpnService extends Service {
    107 
    108     /**
    109      * The action must be matched by the intent filter of this service. It also
    110      * needs to require {@link android.Manifest.permission#BIND_VPN_SERVICE}
    111      * permission so that other applications cannot abuse it.
    112      */
    113     public static final String SERVICE_INTERFACE = VpnConfig.SERVICE_INTERFACE;
    114 
    115     /**
    116      * Use IConnectivityManager since those methods are hidden and not
    117      * available in ConnectivityManager.
    118      */
    119     private static IConnectivityManager getService() {
    120         return IConnectivityManager.Stub.asInterface(
    121                 ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
    122     }
    123 
    124     /**
    125      * Prepare to establish a VPN connection. This method returns {@code null}
    126      * if the VPN application is already prepared. Otherwise, it returns an
    127      * {@link Intent} to a system activity. The application should launch the
    128      * activity using {@link Activity#startActivityForResult} to get itself
    129      * prepared. The activity may pop up a dialog to require user action, and
    130      * the result will come back via its {@link Activity#onActivityResult}.
    131      * If the result is {@link Activity#RESULT_OK}, the application becomes
    132      * prepared and is granted to use other methods in this class.
    133      *
    134      * <p>Only one application can be granted at the same time. The right
    135      * is revoked when another application is granted. The application
    136      * losing the right will be notified via its {@link #onRevoke}. Unless
    137      * it becomes prepared again, subsequent calls to other methods in this
    138      * class will fail.
    139      *
    140      * @see #onRevoke
    141      */
    142     public static Intent prepare(Context context) {
    143         try {
    144             if (getService().prepareVpn(context.getPackageName(), null)) {
    145                 return null;
    146             }
    147         } catch (RemoteException e) {
    148             // ignore
    149         }
    150         return VpnConfig.getIntentForConfirmation();
    151     }
    152 
    153     /**
    154      * Protect a socket from VPN connections. After protecting, data sent
    155      * through this socket will go directly to the underlying network,
    156      * so its traffic will not be forwarded through the VPN.
    157      * This method is useful if some connections need to be kept
    158      * outside of VPN. For example, a VPN tunnel should protect itself if its
    159      * destination is covered by VPN routes. Otherwise its outgoing packets
    160      * will be sent back to the VPN interface and cause an infinite loop. This
    161      * method will fail if the application is not prepared or is revoked.
    162      *
    163      * <p class="note">The socket is NOT closed by this method.
    164      *
    165      * @return {@code true} on success.
    166      */
    167     public boolean protect(int socket) {
    168         ParcelFileDescriptor dup = null;
    169         try {
    170             dup = ParcelFileDescriptor.fromFd(socket);
    171             return getService().protectVpn(dup);
    172         } catch (Exception e) {
    173             return false;
    174         } finally {
    175             try {
    176                 dup.close();
    177             } catch (Exception e) {
    178                 // ignore
    179             }
    180         }
    181     }
    182 
    183     /**
    184      * Convenience method to protect a {@link Socket} from VPN connections.
    185      *
    186      * @return {@code true} on success.
    187      * @see #protect(int)
    188      */
    189     public boolean protect(Socket socket) {
    190         return protect(socket.getFileDescriptor$().getInt$());
    191     }
    192 
    193     /**
    194      * Convenience method to protect a {@link DatagramSocket} from VPN
    195      * connections.
    196      *
    197      * @return {@code true} on success.
    198      * @see #protect(int)
    199      */
    200     public boolean protect(DatagramSocket socket) {
    201         return protect(socket.getFileDescriptor$().getInt$());
    202     }
    203 
    204     /**
    205      * Return the communication interface to the service. This method returns
    206      * {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE}
    207      * action. Applications overriding this method must identify the intent
    208      * and return the corresponding interface accordingly.
    209      *
    210      * @see Service#onBind
    211      */
    212     @Override
    213     public IBinder onBind(Intent intent) {
    214         if (intent != null && SERVICE_INTERFACE.equals(intent.getAction())) {
    215             return new Callback();
    216         }
    217         return null;
    218     }
    219 
    220     /**
    221      * Invoked when the application is revoked. At this moment, the VPN
    222      * interface is already deactivated by the system. The application should
    223      * close the file descriptor and shut down gracefully. The default
    224      * implementation of this method is calling {@link Service#stopSelf()}.
    225      *
    226      * <p class="note">Calls to this method may not happen on the main thread
    227      * of the process.
    228      *
    229      * @see #prepare
    230      */
    231     public void onRevoke() {
    232         stopSelf();
    233     }
    234 
    235     /**
    236      * Use raw Binder instead of AIDL since now there is only one usage.
    237      */
    238     private class Callback extends Binder {
    239         @Override
    240         protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
    241             if (code == IBinder.LAST_CALL_TRANSACTION) {
    242                 onRevoke();
    243                 return true;
    244             }
    245             return false;
    246         }
    247     }
    248 
    249     /**
    250      * Helper class to create a VPN interface. This class should be always
    251      * used within the scope of the outer {@link VpnService}.
    252      *
    253      * @see VpnService
    254      */
    255     public class Builder {
    256 
    257         private final VpnConfig mConfig = new VpnConfig();
    258         private final List<LinkAddress> mAddresses = new ArrayList<LinkAddress>();
    259         private final List<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
    260 
    261         public Builder() {
    262             mConfig.user = VpnService.this.getClass().getName();
    263         }
    264 
    265         /**
    266          * Set the name of this session. It will be displayed in
    267          * system-managed dialogs and notifications. This is recommended
    268          * not required.
    269          */
    270         public Builder setSession(String session) {
    271             mConfig.session = session;
    272             return this;
    273         }
    274 
    275         /**
    276          * Set the {@link PendingIntent} to an activity for users to
    277          * configure the VPN connection. If it is not set, the button
    278          * to configure will not be shown in system-managed dialogs.
    279          */
    280         public Builder setConfigureIntent(PendingIntent intent) {
    281             mConfig.configureIntent = intent;
    282             return this;
    283         }
    284 
    285         /**
    286          * Set the maximum transmission unit (MTU) of the VPN interface. If
    287          * it is not set, the default value in the operating system will be
    288          * used.
    289          *
    290          * @throws IllegalArgumentException if the value is not positive.
    291          */
    292         public Builder setMtu(int mtu) {
    293             if (mtu <= 0) {
    294                 throw new IllegalArgumentException("Bad mtu");
    295             }
    296             mConfig.mtu = mtu;
    297             return this;
    298         }
    299 
    300         /**
    301          * Private method to validate address and prefixLength.
    302          */
    303         private void check(InetAddress address, int prefixLength) {
    304             if (address.isLoopbackAddress()) {
    305                 throw new IllegalArgumentException("Bad address");
    306             }
    307             if (address instanceof Inet4Address) {
    308                 if (prefixLength < 0 || prefixLength > 32) {
    309                     throw new IllegalArgumentException("Bad prefixLength");
    310                 }
    311             } else if (address instanceof Inet6Address) {
    312                 if (prefixLength < 0 || prefixLength > 128) {
    313                     throw new IllegalArgumentException("Bad prefixLength");
    314                 }
    315             } else {
    316                 throw new IllegalArgumentException("Unsupported family");
    317             }
    318         }
    319 
    320         /**
    321          * Add a network address to the VPN interface. Both IPv4 and IPv6
    322          * addresses are supported. At least one address must be set before
    323          * calling {@link #establish}.
    324          *
    325          * @throws IllegalArgumentException if the address is invalid.
    326          */
    327         public Builder addAddress(InetAddress address, int prefixLength) {
    328             check(address, prefixLength);
    329 
    330             if (address.isAnyLocalAddress()) {
    331                 throw new IllegalArgumentException("Bad address");
    332             }
    333             mAddresses.add(new LinkAddress(address, prefixLength));
    334             return this;
    335         }
    336 
    337         /**
    338          * Convenience method to add a network address to the VPN interface
    339          * using a numeric address string. See {@link InetAddress} for the
    340          * definitions of numeric address formats.
    341          *
    342          * @throws IllegalArgumentException if the address is invalid.
    343          * @see #addAddress(InetAddress, int)
    344          */
    345         public Builder addAddress(String address, int prefixLength) {
    346             return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
    347         }
    348 
    349         /**
    350          * Add a network route to the VPN interface. Both IPv4 and IPv6
    351          * routes are supported.
    352          *
    353          * @throws IllegalArgumentException if the route is invalid.
    354          */
    355         public Builder addRoute(InetAddress address, int prefixLength) {
    356             check(address, prefixLength);
    357 
    358             int offset = prefixLength / 8;
    359             byte[] bytes = address.getAddress();
    360             if (offset < bytes.length) {
    361                 for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) {
    362                     if (bytes[offset] != 0) {
    363                         throw new IllegalArgumentException("Bad address");
    364                     }
    365                 }
    366             }
    367             mRoutes.add(new RouteInfo(new LinkAddress(address, prefixLength), null));
    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          */
    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          */
    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          */
    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          */
    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          */
    467         public ParcelFileDescriptor establish() {
    468             mConfig.addresses = mAddresses;
    469             mConfig.routes = mRoutes;
    470 
    471             try {
    472                 return getService().establishVpn(mConfig);
    473             } catch (RemoteException e) {
    474                 throw new IllegalStateException(e);
    475             }
    476         }
    477     }
    478 }
    479