blob: 940cc363f742c9a79636164d7e17b0eb92ffee21 [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 Inwoodc185f082018-08-20 14:28:54 +010019import android.annotation.UnsupportedAppUsage;
Mathew Inwood55418ea2018-12-20 15:30:45 +000020import android.os.Build;
Takayuki, Ogura5ad260d2019-01-25 19:47:05 +090021import android.net.ProxyInfo;
22import android.net.Uri;
Jeff Sharkey82f85212012-08-24 11:17:25 -070023import android.os.Parcel;
24import android.os.Parcelable;
Jeff Sharkey69ddab42012-08-25 00:05:46 -070025import android.text.TextUtils;
Jeff Sharkey82f85212012-08-24 11:17:25 -070026
Jeff Sharkey69ddab42012-08-25 00:05:46 -070027import java.net.InetAddress;
Elliott Hughesd396a442013-06-28 16:24:48 -070028import java.nio.charset.StandardCharsets;
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070029
30/**
31 * Parcel-like entity class for VPN profiles. To keep things simple, all
32 * fields are package private. Methods are provided for serialization, so
33 * storage can be implemented easily. Two rules are set for this class.
34 * First, all fields must be kept non-null. Second, always make a copy
35 * using clone() before modifying.
36 *
37 * @hide
38 */
Jeff Sharkey82f85212012-08-24 11:17:25 -070039public class VpnProfile implements Cloneable, Parcelable {
Jeff Sharkey69ddab42012-08-25 00:05:46 -070040 private static final String TAG = "VpnProfile";
41
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070042 // Match these constants with R.array.vpn_types.
43 public static final int TYPE_PPTP = 0;
44 public static final int TYPE_L2TP_IPSEC_PSK = 1;
45 public static final int TYPE_L2TP_IPSEC_RSA = 2;
46 public static final int TYPE_IPSEC_XAUTH_PSK = 3;
47 public static final int TYPE_IPSEC_XAUTH_RSA = 4;
48 public static final int TYPE_IPSEC_HYBRID_RSA = 5;
49 public static final int TYPE_MAX = 5;
50
Takayuki, Ogura5ad260d2019-01-25 19:47:05 +090051 // Match these constants with R.array.vpn_proxy_settings.
52 public static final int PROXY_NONE = 0;
53 public static final int PROXY_MANUAL = 1;
54
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070055 // Entity fields.
Mathew Inwoodc185f082018-08-20 14:28:54 +010056 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070057 public final String key; // -1
Mathew Inwoodc185f082018-08-20 14:28:54 +010058 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070059 public String name = ""; // 0
Mathew Inwoodc185f082018-08-20 14:28:54 +010060 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070061 public int type = TYPE_PPTP; // 1
Mathew Inwood55418ea2018-12-20 15:30:45 +000062 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070063 public String server = ""; // 2
Mathew Inwoodc185f082018-08-20 14:28:54 +010064 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070065 public String username = ""; // 3
66 public String password = ""; // 4
67 public String dnsServers = ""; // 5
68 public String searchDomains = ""; // 6
69 public String routes = ""; // 7
70 public boolean mppe = true; // 8
71 public String l2tpSecret = ""; // 9
72 public String ipsecIdentifier = "";// 10
73 public String ipsecSecret = ""; // 11
74 public String ipsecUserCert = ""; // 12
75 public String ipsecCaCert = ""; // 13
76 public String ipsecServerCert = "";// 14
Takayuki, Ogura5ad260d2019-01-25 19:47:05 +090077 public ProxyInfo proxy = null; // 15~18
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070078
79 // Helper fields.
Mathew Inwoodc185f082018-08-20 14:28:54 +010080 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -070081 public boolean saveLogin = false;
82
83 public VpnProfile(String key) {
84 this.key = key;
85 }
86
Mathew Inwoodc185f082018-08-20 14:28:54 +010087 @UnsupportedAppUsage
Jeff Sharkey6e7aa772012-10-19 10:48:11 -070088 public VpnProfile(Parcel in) {
89 key = in.readString();
90 name = in.readString();
91 type = in.readInt();
92 server = in.readString();
93 username = in.readString();
94 password = in.readString();
95 dnsServers = in.readString();
96 searchDomains = in.readString();
97 routes = in.readString();
98 mppe = in.readInt() != 0;
99 l2tpSecret = in.readString();
100 ipsecIdentifier = in.readString();
101 ipsecSecret = in.readString();
102 ipsecUserCert = in.readString();
103 ipsecCaCert = in.readString();
104 ipsecServerCert = in.readString();
105 saveLogin = in.readInt() != 0;
Takayuki, Ogura5ad260d2019-01-25 19:47:05 +0900106 proxy = in.readParcelable(null);
Jeff Sharkey6e7aa772012-10-19 10:48:11 -0700107 }
108
109 @Override
110 public void writeToParcel(Parcel out, int flags) {
111 out.writeString(key);
112 out.writeString(name);
113 out.writeInt(type);
114 out.writeString(server);
115 out.writeString(username);
116 out.writeString(password);
117 out.writeString(dnsServers);
118 out.writeString(searchDomains);
119 out.writeString(routes);
120 out.writeInt(mppe ? 1 : 0);
121 out.writeString(l2tpSecret);
122 out.writeString(ipsecIdentifier);
123 out.writeString(ipsecSecret);
124 out.writeString(ipsecUserCert);
125 out.writeString(ipsecCaCert);
126 out.writeString(ipsecServerCert);
127 out.writeInt(saveLogin ? 1 : 0);
Takayuki, Ogura5ad260d2019-01-25 19:47:05 +0900128 out.writeParcelable(proxy, flags);
Jeff Sharkey6e7aa772012-10-19 10:48:11 -0700129 }
130
Mathew Inwoodc185f082018-08-20 14:28:54 +0100131 @UnsupportedAppUsage
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700132 public static VpnProfile decode(String key, byte[] value) {
133 try {
134 if (key == null) {
135 return null;
136 }
137
Elliott Hughesd396a442013-06-28 16:24:48 -0700138 String[] values = new String(value, StandardCharsets.UTF_8).split("\0", -1);
Takayuki, Ogura5ad260d2019-01-25 19:47:05 +0900139 // There can be 14 - 19 Bytes in values.length.
140 if (values.length < 14 || values.length > 19) {
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700141 return null;
142 }
143
144 VpnProfile profile = new VpnProfile(key);
145 profile.name = values[0];
Narayan Kamatha09b4d22016-04-15 18:32:45 +0100146 profile.type = Integer.parseInt(values[1]);
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700147 if (profile.type < 0 || profile.type > TYPE_MAX) {
148 return null;
149 }
150 profile.server = values[2];
151 profile.username = values[3];
152 profile.password = values[4];
153 profile.dnsServers = values[5];
154 profile.searchDomains = values[6];
155 profile.routes = values[7];
Tobias Thiererb0800dc2016-04-21 17:51:41 +0100156 profile.mppe = Boolean.parseBoolean(values[8]);
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700157 profile.l2tpSecret = values[9];
158 profile.ipsecIdentifier = values[10];
159 profile.ipsecSecret = values[11];
160 profile.ipsecUserCert = values[12];
161 profile.ipsecCaCert = values[13];
162 profile.ipsecServerCert = (values.length > 14) ? values[14] : "";
Takayuki, Ogura5ad260d2019-01-25 19:47:05 +0900163 if (values.length > 15) {
164 String host = (values.length > 15) ? values[15] : "";
165 String port = (values.length > 16) ? values[16] : "";
166 String exclList = (values.length > 17) ? values[17] : "";
167 String pacFileUrl = (values.length > 18) ? values[18] : "";
168 if (pacFileUrl.isEmpty()) {
169 profile.proxy = new ProxyInfo(host, port.isEmpty() ?
170 0 : Integer.parseInt(port), exclList);
171 } else {
172 profile.proxy = new ProxyInfo(pacFileUrl);
173 }
174 } // else profle.proxy = null
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700175 profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
176 return profile;
177 } catch (Exception e) {
178 // ignore
179 }
180 return null;
181 }
182
183 public byte[] encode() {
184 StringBuilder builder = new StringBuilder(name);
185 builder.append('\0').append(type);
186 builder.append('\0').append(server);
187 builder.append('\0').append(saveLogin ? username : "");
188 builder.append('\0').append(saveLogin ? password : "");
189 builder.append('\0').append(dnsServers);
190 builder.append('\0').append(searchDomains);
191 builder.append('\0').append(routes);
192 builder.append('\0').append(mppe);
193 builder.append('\0').append(l2tpSecret);
194 builder.append('\0').append(ipsecIdentifier);
195 builder.append('\0').append(ipsecSecret);
196 builder.append('\0').append(ipsecUserCert);
197 builder.append('\0').append(ipsecCaCert);
198 builder.append('\0').append(ipsecServerCert);
Takayuki, Ogura5ad260d2019-01-25 19:47:05 +0900199 if (proxy != null) {
200 builder.append('\0').append(proxy.getHost() != null ? proxy.getHost() : "");
201 builder.append('\0').append(proxy.getPort());
202 builder.append('\0').append(proxy.getExclusionListAsString() != null ?
203 proxy.getExclusionListAsString() : "");
204 builder.append('\0').append(proxy.getPacFileUrl().toString());
205 }
Elliott Hughesd396a442013-06-28 16:24:48 -0700206 return builder.toString().getBytes(StandardCharsets.UTF_8);
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700207 }
Jeff Sharkey82f85212012-08-24 11:17:25 -0700208
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700209 /**
Charles He16dd8502017-03-20 21:56:42 +0000210 * Tests if profile is valid for lockdown, which requires IPv4 address for
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700211 * both server and DNS. Server hostnames would require using DNS before
212 * connection.
213 */
214 public boolean isValidLockdownProfile() {
Charles He16dd8502017-03-20 21:56:42 +0000215 return isTypeValidForLockdown()
216 && isServerAddressNumeric()
217 && hasDns()
218 && areDnsAddressesNumeric();
219 }
Robin Leebae6d822016-07-06 10:30:04 +0100220
Charles He16dd8502017-03-20 21:56:42 +0000221 /** Returns {@code true} if the VPN type is valid for lockdown. */
222 public boolean isTypeValidForLockdown() {
223 // b/7064069: lockdown firewall blocks ports used for PPTP
224 return type != TYPE_PPTP;
225 }
226
227 /** Returns {@code true} if the server address is numeric, e.g. 8.8.8.8 */
228 public boolean isServerAddressNumeric() {
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700229 try {
230 InetAddress.parseNumericAddress(server);
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700231 } catch (IllegalArgumentException e) {
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700232 return false;
233 }
Charles He16dd8502017-03-20 21:56:42 +0000234 return true;
235 }
236
237 /** Returns {@code true} if one or more DNS servers are specified. */
238 public boolean hasDns() {
239 return !TextUtils.isEmpty(dnsServers);
240 }
241
242 /**
243 * Returns {@code true} if all DNS servers have numeric addresses,
244 * e.g. 8.8.8.8
245 */
246 public boolean areDnsAddressesNumeric() {
247 try {
248 for (String dnsServer : dnsServers.split(" +")) {
249 InetAddress.parseNumericAddress(dnsServer);
250 }
251 } catch (IllegalArgumentException e) {
252 return false;
253 }
254 return true;
Jeff Sharkey69ddab42012-08-25 00:05:46 -0700255 }
256
Jeff Sharkey82f85212012-08-24 11:17:25 -0700257 public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
258 @Override
259 public VpnProfile createFromParcel(Parcel in) {
Jeff Sharkey6e7aa772012-10-19 10:48:11 -0700260 return new VpnProfile(in);
Jeff Sharkey82f85212012-08-24 11:17:25 -0700261 }
262
263 @Override
264 public VpnProfile[] newArray(int size) {
265 return new VpnProfile[size];
266 }
267 };
268
269 @Override
270 public int describeContents() {
271 return 0;
272 }
Jeff Sharkey971a3cf2012-07-19 17:10:09 -0700273}