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.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      */
    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      */
    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      */
    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      */
    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      */
    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
    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      */
    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
    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 
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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.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