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 com.android.internal.net;
     18 
     19 import android.os.Parcel;
     20 import android.os.Parcelable;
     21 import android.text.TextUtils;
     22 import android.util.Log;
     23 
     24 import java.net.InetAddress;
     25 import java.nio.charset.StandardCharsets;
     26 
     27 /**
     28  * Parcel-like entity class for VPN profiles. To keep things simple, all
     29  * fields are package private. Methods are provided for serialization, so
     30  * storage can be implemented easily. Two rules are set for this class.
     31  * First, all fields must be kept non-null. Second, always make a copy
     32  * using clone() before modifying.
     33  *
     34  * @hide
     35  */
     36 public class VpnProfile implements Cloneable, Parcelable {
     37     private static final String TAG = "VpnProfile";
     38 
     39     // Match these constants with R.array.vpn_types.
     40     public static final int TYPE_PPTP = 0;
     41     public static final int TYPE_L2TP_IPSEC_PSK = 1;
     42     public static final int TYPE_L2TP_IPSEC_RSA = 2;
     43     public static final int TYPE_IPSEC_XAUTH_PSK = 3;
     44     public static final int TYPE_IPSEC_XAUTH_RSA = 4;
     45     public static final int TYPE_IPSEC_HYBRID_RSA = 5;
     46     public static final int TYPE_MAX = 5;
     47 
     48     // Entity fields.
     49     public final String key;           // -1
     50     public String name = "";           // 0
     51     public int type = TYPE_PPTP;       // 1
     52     public String server = "";         // 2
     53     public String username = "";       // 3
     54     public String password = "";       // 4
     55     public String dnsServers = "";     // 5
     56     public String searchDomains = "";  // 6
     57     public String routes = "";         // 7
     58     public boolean mppe = true;        // 8
     59     public String l2tpSecret = "";     // 9
     60     public String ipsecIdentifier = "";// 10
     61     public String ipsecSecret = "";    // 11
     62     public String ipsecUserCert = "";  // 12
     63     public String ipsecCaCert = "";    // 13
     64     public String ipsecServerCert = "";// 14
     65 
     66     // Helper fields.
     67     public boolean saveLogin = false;
     68 
     69     public VpnProfile(String key) {
     70         this.key = key;
     71     }
     72 
     73     public VpnProfile(Parcel in) {
     74         key = in.readString();
     75         name = in.readString();
     76         type = in.readInt();
     77         server = in.readString();
     78         username = in.readString();
     79         password = in.readString();
     80         dnsServers = in.readString();
     81         searchDomains = in.readString();
     82         routes = in.readString();
     83         mppe = in.readInt() != 0;
     84         l2tpSecret = in.readString();
     85         ipsecIdentifier = in.readString();
     86         ipsecSecret = in.readString();
     87         ipsecUserCert = in.readString();
     88         ipsecCaCert = in.readString();
     89         ipsecServerCert = in.readString();
     90         saveLogin = in.readInt() != 0;
     91     }
     92 
     93     @Override
     94     public void writeToParcel(Parcel out, int flags) {
     95         out.writeString(key);
     96         out.writeString(name);
     97         out.writeInt(type);
     98         out.writeString(server);
     99         out.writeString(username);
    100         out.writeString(password);
    101         out.writeString(dnsServers);
    102         out.writeString(searchDomains);
    103         out.writeString(routes);
    104         out.writeInt(mppe ? 1 : 0);
    105         out.writeString(l2tpSecret);
    106         out.writeString(ipsecIdentifier);
    107         out.writeString(ipsecSecret);
    108         out.writeString(ipsecUserCert);
    109         out.writeString(ipsecCaCert);
    110         out.writeString(ipsecServerCert);
    111         out.writeInt(saveLogin ? 1 : 0);
    112     }
    113 
    114     public static VpnProfile decode(String key, byte[] value) {
    115         try {
    116             if (key == null) {
    117                 return null;
    118             }
    119 
    120             String[] values = new String(value, StandardCharsets.UTF_8).split("\0", -1);
    121             // There can be 14 or 15 values in ICS MR1.
    122             if (values.length < 14 || values.length > 15) {
    123                 return null;
    124             }
    125 
    126             VpnProfile profile = new VpnProfile(key);
    127             profile.name = values[0];
    128             profile.type = Integer.valueOf(values[1]);
    129             if (profile.type < 0 || profile.type > TYPE_MAX) {
    130                 return null;
    131             }
    132             profile.server = values[2];
    133             profile.username = values[3];
    134             profile.password = values[4];
    135             profile.dnsServers = values[5];
    136             profile.searchDomains = values[6];
    137             profile.routes = values[7];
    138             profile.mppe = Boolean.valueOf(values[8]);
    139             profile.l2tpSecret = values[9];
    140             profile.ipsecIdentifier = values[10];
    141             profile.ipsecSecret = values[11];
    142             profile.ipsecUserCert = values[12];
    143             profile.ipsecCaCert = values[13];
    144             profile.ipsecServerCert = (values.length > 14) ? values[14] : "";
    145 
    146             profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
    147             return profile;
    148         } catch (Exception e) {
    149             // ignore
    150         }
    151         return null;
    152     }
    153 
    154     public byte[] encode() {
    155         StringBuilder builder = new StringBuilder(name);
    156         builder.append('\0').append(type);
    157         builder.append('\0').append(server);
    158         builder.append('\0').append(saveLogin ? username : "");
    159         builder.append('\0').append(saveLogin ? password : "");
    160         builder.append('\0').append(dnsServers);
    161         builder.append('\0').append(searchDomains);
    162         builder.append('\0').append(routes);
    163         builder.append('\0').append(mppe);
    164         builder.append('\0').append(l2tpSecret);
    165         builder.append('\0').append(ipsecIdentifier);
    166         builder.append('\0').append(ipsecSecret);
    167         builder.append('\0').append(ipsecUserCert);
    168         builder.append('\0').append(ipsecCaCert);
    169         builder.append('\0').append(ipsecServerCert);
    170         return builder.toString().getBytes(StandardCharsets.UTF_8);
    171     }
    172 
    173     /**
    174      * Test if profile is valid for lockdown, which requires IPv4 address for
    175      * both server and DNS. Server hostnames would require using DNS before
    176      * connection.
    177      */
    178     public boolean isValidLockdownProfile() {
    179         try {
    180             InetAddress.parseNumericAddress(server);
    181 
    182             for (String dnsServer : dnsServers.split(" +")) {
    183                 InetAddress.parseNumericAddress(this.dnsServers);
    184             }
    185             if (TextUtils.isEmpty(dnsServers)) {
    186                 Log.w(TAG, "DNS required");
    187                 return false;
    188             }
    189 
    190             // Everything checked out above
    191             return true;
    192 
    193         } catch (IllegalArgumentException e) {
    194             Log.w(TAG, "Invalid address", e);
    195             return false;
    196         }
    197     }
    198 
    199     public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
    200         @Override
    201         public VpnProfile createFromParcel(Parcel in) {
    202             return new VpnProfile(in);
    203         }
    204 
    205         @Override
    206         public VpnProfile[] newArray(int size) {
    207             return new VpnProfile[size];
    208         }
    209     };
    210 
    211     @Override
    212     public int describeContents() {
    213         return 0;
    214     }
    215 }
    216