VpnProfile.java revision 69ddab4575ff684c533c995e07ca15fe18543fc0
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
17package com.android.internal.net;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.text.TextUtils;
22import android.util.Log;
23
24import java.net.InetAddress;
25import java.nio.charset.Charsets;
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 */
36public 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 static VpnProfile decode(String key, byte[] value) {
74        try {
75            if (key == null) {
76                return null;
77            }
78
79            String[] values = new String(value, Charsets.UTF_8).split("\0", -1);
80            // There can be 14 or 15 values in ICS MR1.
81            if (values.length < 14 || values.length > 15) {
82                return null;
83            }
84
85            VpnProfile profile = new VpnProfile(key);
86            profile.name = values[0];
87            profile.type = Integer.valueOf(values[1]);
88            if (profile.type < 0 || profile.type > TYPE_MAX) {
89                return null;
90            }
91            profile.server = values[2];
92            profile.username = values[3];
93            profile.password = values[4];
94            profile.dnsServers = values[5];
95            profile.searchDomains = values[6];
96            profile.routes = values[7];
97            profile.mppe = Boolean.valueOf(values[8]);
98            profile.l2tpSecret = values[9];
99            profile.ipsecIdentifier = values[10];
100            profile.ipsecSecret = values[11];
101            profile.ipsecUserCert = values[12];
102            profile.ipsecCaCert = values[13];
103            profile.ipsecServerCert = (values.length > 14) ? values[14] : "";
104
105            profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
106            return profile;
107        } catch (Exception e) {
108            // ignore
109        }
110        return null;
111    }
112
113    public byte[] encode() {
114        StringBuilder builder = new StringBuilder(name);
115        builder.append('\0').append(type);
116        builder.append('\0').append(server);
117        builder.append('\0').append(saveLogin ? username : "");
118        builder.append('\0').append(saveLogin ? password : "");
119        builder.append('\0').append(dnsServers);
120        builder.append('\0').append(searchDomains);
121        builder.append('\0').append(routes);
122        builder.append('\0').append(mppe);
123        builder.append('\0').append(l2tpSecret);
124        builder.append('\0').append(ipsecIdentifier);
125        builder.append('\0').append(ipsecSecret);
126        builder.append('\0').append(ipsecUserCert);
127        builder.append('\0').append(ipsecCaCert);
128        builder.append('\0').append(ipsecServerCert);
129        return builder.toString().getBytes(Charsets.UTF_8);
130    }
131
132    /**
133     * Test if profile is valid for lockdown, which requires IPv4 address for
134     * both server and DNS. Server hostnames would require using DNS before
135     * connection.
136     */
137    public boolean isValidLockdownProfile() {
138        try {
139            InetAddress.parseNumericAddress(server);
140
141            for (String dnsServer : dnsServers.split(" +")) {
142                InetAddress.parseNumericAddress(this.dnsServers);
143            }
144            if (TextUtils.isEmpty(dnsServers)) {
145                Log.w(TAG, "DNS required");
146                return false;
147            }
148
149            // Everything checked out above
150            return true;
151
152        } catch (IllegalArgumentException e) {
153            Log.w(TAG, "Invalid address", e);
154            return false;
155        }
156    }
157
158    @Override
159    public void writeToParcel(Parcel out, int flags) {
160        out.writeString(key);
161        out.writeByteArray(encode());
162    }
163
164    public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
165        @Override
166        public VpnProfile createFromParcel(Parcel in) {
167            final String key = in.readString();
168            return decode(key, in.createByteArray());
169        }
170
171        @Override
172        public VpnProfile[] newArray(int size) {
173            return new VpnProfile[size];
174        }
175    };
176
177    @Override
178    public int describeContents() {
179        return 0;
180    }
181}
182