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