blob: ec02432223de4032321faa67599a29521f8c9a67 [file] [log] [blame]
Jeff Sharkey971a3cf2012-07-19 17:10:09 -07001/*
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
Mathew Inwoodaf972c82018-08-20 14:13:20 +010019import android.annotation.UnsupportedAppUsage;
Mathew Inwood31755f92018-12-20 13:53:36 +000020import android.os.Build;
Jeff Sharkey82f85212012-08-24 11:17:25 -070021import android.os.Parcel;
22import android.os.Parcelable;
Jeff Sharkey69ddab42012-08-25 00:05:46 -070023import android.text.TextUtils;
Jeff Sharkey82f85212012-08-24 11:17:25 -070024
Jeff Sharkey69ddab42012-08-25 00:05:46 -070025import java.net.InetAddress;
Elliott Hughesd396a442013-06-28 16:24:48 -070026import java.nio.charset.StandardCharsets;
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070027
28/**
29 * Parcel-like entity class for VPN profiles. To keep things simple, all
30 * fields are package private. Methods are provided for serialization, so
31 * storage can be implemented easily. Two rules are set for this class.
32 * First, all fields must be kept non-null. Second, always make a copy
33 * using clone() before modifying.
34 *
35 * @hide
36 */
Jeff Sharkey82f85212012-08-24 11:17:25 -070037public class VpnProfile implements Cloneable, Parcelable {
Jeff Sharkey69ddab42012-08-25 00:05:46 -070038 private static final String TAG = "VpnProfile";
39
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070040 // Match these constants with R.array.vpn_types.
41 public static final int TYPE_PPTP = 0;
42 public static final int TYPE_L2TP_IPSEC_PSK = 1;
43 public static final int TYPE_L2TP_IPSEC_RSA = 2;
44 public static final int TYPE_IPSEC_XAUTH_PSK = 3;
45 public static final int TYPE_IPSEC_XAUTH_RSA = 4;
46 public static final int TYPE_IPSEC_HYBRID_RSA = 5;
47 public static final int TYPE_MAX = 5;
48
49 // Entity fields.
Mathew Inwoodaf972c82018-08-20 14:13:20 +010050 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070051 public final String key; // -1
Mathew Inwoodaf972c82018-08-20 14:13:20 +010052 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070053 public String name = ""; // 0
Mathew Inwoodaf972c82018-08-20 14:13:20 +010054 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070055 public int type = TYPE_PPTP; // 1
Mathew Inwood31755f92018-12-20 13:53:36 +000056 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070057 public String server = ""; // 2
Mathew Inwoodaf972c82018-08-20 14:13:20 +010058 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070059 public String username = ""; // 3
60 public String password = ""; // 4
61 public String dnsServers = ""; // 5
62 public String searchDomains = ""; // 6
63 public String routes = ""; // 7
64 public boolean mppe = true; // 8
65 public String l2tpSecret = ""; // 9
66 public String ipsecIdentifier = "";// 10
67 public String ipsecSecret = ""; // 11
68 public String ipsecUserCert = ""; // 12
69 public String ipsecCaCert = ""; // 13
70 public String ipsecServerCert = "";// 14
71
72 // Helper fields.
Mathew Inwoodaf972c82018-08-20 14:13:20 +010073 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070074 public boolean saveLogin = false;
75
76 public VpnProfile(String key) {
77 this.key = key;
78 }
79
Mathew Inwoodaf972c82018-08-20 14:13:20 +010080 @UnsupportedAppUsage
Jeff Sharkey6e7aa772012-10-19 10:48:11 -070081 public VpnProfile(Parcel in) {
82 key = in.readString();
83 name = in.readString();
84 type = in.readInt();
85 server = in.readString();
86 username = in.readString();
87 password = in.readString();
88 dnsServers = in.readString();
89 searchDomains = in.readString();
90 routes = in.readString();
91 mppe = in.readInt() != 0;
92 l2tpSecret = in.readString();
93 ipsecIdentifier = in.readString();
94 ipsecSecret = in.readString();
95 ipsecUserCert = in.readString();
96 ipsecCaCert = in.readString();
97 ipsecServerCert = in.readString();
98 saveLogin = in.readInt() != 0;
99 }
100
101 @Override
102 public void writeToParcel(Parcel out, int flags) {
103 out.writeString(key);
104 out.writeString(name);
105 out.writeInt(type);
106 out.writeString(server);
107 out.writeString(username);
108 out.writeString(password);
109 out.writeString(dnsServers);
110 out.writeString(searchDomains);
111 out.writeString(routes);
112 out.writeInt(mppe ? 1 : 0);
113 out.writeString(l2tpSecret);
114 out.writeString(ipsecIdentifier);
115 out.writeString(ipsecSecret);
116 out.writeString(ipsecUserCert);
117 out.writeString(ipsecCaCert);
118 out.writeString(ipsecServerCert);
119 out.writeInt(saveLogin ? 1 : 0);
120 }
121
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100122 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700123 public static VpnProfile decode(String key, byte[] value) {
124 try {
125 if (key == null) {
126 return null;
127 }
128
Elliott Hughesd396a442013-06-28 16:24:48 -0700129 String[] values = new String(value, StandardCharsets.UTF_8).split("\0", -1);
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700130 // There can be 14 or 15 values in ICS MR1.
131 if (values.length < 14 || values.length > 15) {
132 return null;
133 }
134
135 VpnProfile profile = new VpnProfile(key);
136 profile.name = values[0];
Narayan Kamatha09b4d22016-04-15 18:32:45 +0100137 profile.type = Integer.parseInt(values[1]);
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700138 if (profile.type < 0 || profile.type > TYPE_MAX) {
139 return null;
140 }
141 profile.server = values[2];
142 profile.username = values[3];
143 profile.password = values[4];
144 profile.dnsServers = values[5];
145 profile.searchDomains = values[6];
146 profile.routes = values[7];
Tobias Thiererb0800dc2016-04-21 17:51:41 +0100147 profile.mppe = Boolean.parseBoolean(values[8]);
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700148 profile.l2tpSecret = values[9];
149 profile.ipsecIdentifier = values[10];
150 profile.ipsecSecret = values[11];
151 profile.ipsecUserCert = values[12];
152 profile.ipsecCaCert = values[13];
153 profile.ipsecServerCert = (values.length > 14) ? values[14] : "";
154
155 profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
156 return profile;
157 } catch (Exception e) {
158 // ignore
159 }
160 return null;
161 }
162
163 public byte[] encode() {
164 StringBuilder builder = new StringBuilder(name);
165 builder.append('\0').append(type);
166 builder.append('\0').append(server);
167 builder.append('\0').append(saveLogin ? username : "");
168 builder.append('\0').append(saveLogin ? password : "");
169 builder.append('\0').append(dnsServers);
170 builder.append('\0').append(searchDomains);
171 builder.append('\0').append(routes);
172 builder.append('\0').append(mppe);
173 builder.append('\0').append(l2tpSecret);
174 builder.append('\0').append(ipsecIdentifier);
175 builder.append('\0').append(ipsecSecret);
176 builder.append('\0').append(ipsecUserCert);
177 builder.append('\0').append(ipsecCaCert);
178 builder.append('\0').append(ipsecServerCert);
Elliott Hughesd396a442013-06-28 16:24:48 -0700179 return builder.toString().getBytes(StandardCharsets.UTF_8);
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700180 }
Jeff Sharkey82f85212012-08-24 11:17:25 -0700181
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700182 /**
Charles He16dd8502017-03-20 21:56:42 +0000183 * Tests if profile is valid for lockdown, which requires IPv4 address for
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700184 * both server and DNS. Server hostnames would require using DNS before
185 * connection.
186 */
187 public boolean isValidLockdownProfile() {
Charles He16dd8502017-03-20 21:56:42 +0000188 return isTypeValidForLockdown()
189 && isServerAddressNumeric()
190 && hasDns()
191 && areDnsAddressesNumeric();
192 }
Robin Leebae6d822016-07-06 10:30:04 +0100193
Charles He16dd8502017-03-20 21:56:42 +0000194 /** Returns {@code true} if the VPN type is valid for lockdown. */
195 public boolean isTypeValidForLockdown() {
196 // b/7064069: lockdown firewall blocks ports used for PPTP
197 return type != TYPE_PPTP;
198 }
199
200 /** Returns {@code true} if the server address is numeric, e.g. 8.8.8.8 */
201 public boolean isServerAddressNumeric() {
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700202 try {
203 InetAddress.parseNumericAddress(server);
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700204 } catch (IllegalArgumentException e) {
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700205 return false;
206 }
Charles He16dd8502017-03-20 21:56:42 +0000207 return true;
208 }
209
210 /** Returns {@code true} if one or more DNS servers are specified. */
211 public boolean hasDns() {
212 return !TextUtils.isEmpty(dnsServers);
213 }
214
215 /**
216 * Returns {@code true} if all DNS servers have numeric addresses,
217 * e.g. 8.8.8.8
218 */
219 public boolean areDnsAddressesNumeric() {
220 try {
221 for (String dnsServer : dnsServers.split(" +")) {
222 InetAddress.parseNumericAddress(dnsServer);
223 }
224 } catch (IllegalArgumentException e) {
225 return false;
226 }
227 return true;
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700228 }
229
Jeff Sharkey82f85212012-08-24 11:17:25 -0700230 public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
231 @Override
232 public VpnProfile createFromParcel(Parcel in) {
Jeff Sharkey6e7aa772012-10-19 10:48:11 -0700233 return new VpnProfile(in);
Jeff Sharkey82f85212012-08-24 11:17:25 -0700234 }
235
236 @Override
237 public VpnProfile[] newArray(int size) {
238 return new VpnProfile[size];
239 }
240 };
241
242 @Override
243 public int describeContents() {
244 return 0;
245 }
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700246}