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