/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.net;

import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;

import java.net.InetAddress;
import java.nio.charset.StandardCharsets;

Parcel-like entity class for VPN profiles. To keep things simple, all fields are package private. Methods are provided for serialization, so storage can be implemented easily. Two rules are set for this class. First, all fields must be kept non-null. Second, always make a copy using clone() before modifying.
@hide
/** * Parcel-like entity class for VPN profiles. To keep things simple, all * fields are package private. Methods are provided for serialization, so * storage can be implemented easily. Two rules are set for this class. * First, all fields must be kept non-null. Second, always make a copy * using clone() before modifying. * * @hide */
public class VpnProfile implements Cloneable, Parcelable { private static final String TAG = "VpnProfile"; // Match these constants with R.array.vpn_types. public static final int TYPE_PPTP = 0; public static final int TYPE_L2TP_IPSEC_PSK = 1; public static final int TYPE_L2TP_IPSEC_RSA = 2; public static final int TYPE_IPSEC_XAUTH_PSK = 3; public static final int TYPE_IPSEC_XAUTH_RSA = 4; public static final int TYPE_IPSEC_HYBRID_RSA = 5; public static final int TYPE_MAX = 5; // Entity fields. public final String key; // -1 public String name = ""; // 0 public int type = TYPE_PPTP; // 1 public String server = ""; // 2 public String username = ""; // 3 public String password = ""; // 4 public String dnsServers = ""; // 5 public String searchDomains = ""; // 6 public String routes = ""; // 7 public boolean mppe = true; // 8 public String l2tpSecret = ""; // 9 public String ipsecIdentifier = "";// 10 public String ipsecSecret = ""; // 11 public String ipsecUserCert = ""; // 12 public String ipsecCaCert = ""; // 13 public String ipsecServerCert = "";// 14 // Helper fields. public boolean saveLogin = false; public VpnProfile(String key) { this.key = key; } public VpnProfile(Parcel in) { key = in.readString(); name = in.readString(); type = in.readInt(); server = in.readString(); username = in.readString(); password = in.readString(); dnsServers = in.readString(); searchDomains = in.readString(); routes = in.readString(); mppe = in.readInt() != 0; l2tpSecret = in.readString(); ipsecIdentifier = in.readString(); ipsecSecret = in.readString(); ipsecUserCert = in.readString(); ipsecCaCert = in.readString(); ipsecServerCert = in.readString(); saveLogin = in.readInt() != 0; } @Override public void writeToParcel(Parcel out, int flags) { out.writeString(key); out.writeString(name); out.writeInt(type); out.writeString(server); out.writeString(username); out.writeString(password); out.writeString(dnsServers); out.writeString(searchDomains); out.writeString(routes); out.writeInt(mppe ? 1 : 0); out.writeString(l2tpSecret); out.writeString(ipsecIdentifier); out.writeString(ipsecSecret); out.writeString(ipsecUserCert); out.writeString(ipsecCaCert); out.writeString(ipsecServerCert); out.writeInt(saveLogin ? 1 : 0); } public static VpnProfile decode(String key, byte[] value) { try { if (key == null) { return null; } String[] values = new String(value, StandardCharsets.UTF_8).split("\0", -1); // There can be 14 or 15 values in ICS MR1. if (values.length < 14 || values.length > 15) { return null; } VpnProfile profile = new VpnProfile(key); profile.name = values[0]; profile.type = Integer.parseInt(values[1]); if (profile.type < 0 || profile.type > TYPE_MAX) { return null; } profile.server = values[2]; profile.username = values[3]; profile.password = values[4]; profile.dnsServers = values[5]; profile.searchDomains = values[6]; profile.routes = values[7]; profile.mppe = Boolean.parseBoolean(values[8]); profile.l2tpSecret = values[9]; profile.ipsecIdentifier = values[10]; profile.ipsecSecret = values[11]; profile.ipsecUserCert = values[12]; profile.ipsecCaCert = values[13]; profile.ipsecServerCert = (values.length > 14) ? values[14] : ""; profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty(); return profile; } catch (Exception e) { // ignore } return null; } public byte[] encode() { StringBuilder builder = new StringBuilder(name); builder.append('\0').append(type); builder.append('\0').append(server); builder.append('\0').append(saveLogin ? username : ""); builder.append('\0').append(saveLogin ? password : ""); builder.append('\0').append(dnsServers); builder.append('\0').append(searchDomains); builder.append('\0').append(routes); builder.append('\0').append(mppe); builder.append('\0').append(l2tpSecret); builder.append('\0').append(ipsecIdentifier); builder.append('\0').append(ipsecSecret); builder.append('\0').append(ipsecUserCert); builder.append('\0').append(ipsecCaCert); builder.append('\0').append(ipsecServerCert); return builder.toString().getBytes(StandardCharsets.UTF_8); }
Tests if profile is valid for lockdown, which requires IPv4 address for both server and DNS. Server hostnames would require using DNS before connection.
/** * Tests if profile is valid for lockdown, which requires IPv4 address for * both server and DNS. Server hostnames would require using DNS before * connection. */
public boolean isValidLockdownProfile() { return isTypeValidForLockdown() && isServerAddressNumeric() && hasDns() && areDnsAddressesNumeric(); }
Returns true if the VPN type is valid for lockdown.
/** Returns {@code true} if the VPN type is valid for lockdown. */
public boolean isTypeValidForLockdown() { // b/7064069: lockdown firewall blocks ports used for PPTP return type != TYPE_PPTP; }
Returns true if the server address is numeric, e.g. 8.8.8.8
/** Returns {@code true} if the server address is numeric, e.g. 8.8.8.8 */
public boolean isServerAddressNumeric() { try { InetAddress.parseNumericAddress(server); } catch (IllegalArgumentException e) { return false; } return true; }
Returns true if one or more DNS servers are specified.
/** Returns {@code true} if one or more DNS servers are specified. */
public boolean hasDns() { return !TextUtils.isEmpty(dnsServers); }
Returns true if all DNS servers have numeric addresses, e.g. 8.8.8.8
/** * Returns {@code true} if all DNS servers have numeric addresses, * e.g. 8.8.8.8 */
public boolean areDnsAddressesNumeric() { try { for (String dnsServer : dnsServers.split(" +")) { InetAddress.parseNumericAddress(dnsServer); } } catch (IllegalArgumentException e) { return false; } return true; } public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() { @Override public VpnProfile createFromParcel(Parcel in) { return new VpnProfile(in); } @Override public VpnProfile[] newArray(int size) { return new VpnProfile[size]; } }; @Override public int describeContents() { return 0; } }