/* * 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.settings.vpn2;import com.android.settings.R;import android.content.Context; import android.content.DialogInterface; import android.net.IConnectivityManager; import android.net.LinkProperties; import android.net.RouteInfo; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.ServiceManager; import android.preference.Preference; import android.preference.PreferenceGroup; import android.security.Credentials; import android.security.KeyStore; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.Toast;import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.settings.SettingsPreferenceFragment;import java.net.Inet4Address; import java.nio.charset.Charsets; import java.util.Arrays; import java.util.HashMap;public class VpnSettings extends SettingsPreferenceFragment implements Handler.Callback, Preference.OnPreferenceClickListener, DialogInterface.OnClickListener, DialogInterface.OnDismissListener { private static final String TAG = "VpnSettings"; private final IConnectivityManager mService = IConnectivityManager.Stub .asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); private final KeyStore mKeyStore = KeyStore.getInstance(); private boolean mUnlocking = false; private HashMap<String, VpnPreference> mPreferences; private VpnDialog mDialog; private Handler mUpdater; private LegacyVpnInfo mInfo; // The key of the profile for the current ContextMenu. private String mSelectedKey; @Override public void onCreate(Bundle savedState) { super.onCreate(savedState); addPreferencesFromResource(R.xml.vpn_settings2); getPreferenceScreen().setOrderingAsAdded(false); if (savedState != null) { VpnProfile profile = VpnProfile.decode(savedState.getString("VpnKey"), savedState.getByteArray("VpnProfile")); if (profile != null) { mDialog = new VpnDialog(getActivity(), this, profile, savedState.getBoolean("VpnEditing")); } } } @Override public void onSaveInstanceState(Bundle savedState) { // We do not save view hierarchy, as they are just profiles. if (mDialog != null) { VpnProfile profile = mDialog.getProfile(); savedState.putString("VpnKey", profile.key); savedState.putByteArray("VpnProfile", profile.encode()); savedState.putBoolean("VpnEditing", mDialog.isEditing()); } // else? } @Override public void onResume() { super.onResume(); // Check KeyStore here, so others do not need to deal with it. if (mKeyStore.state() != KeyStore.State.UNLOCKED) { if (!mUnlocking) { // Let us unlock KeyStore. See you later! Credentials.getInstance().unlock(getActivity()); } else { // We already tried, but it is still not working! finishFragment(); } mUnlocking = !mUnlocking; return; } // Now KeyStore is always unlocked. Reset the flag. mUnlocking = false; // Currently we are the only user of profiles in KeyStore. // Assuming KeyStore and KeyGuard do the right thing, we can // safely cache profiles in the memory. if (mPreferences == null) { mPreferences = new HashMap<String, VpnPreference>(); PreferenceGroup group = getPreferenceScreen(); String[] keys = mKeyStore.saw(Credentials.VPN); if (keys != null && keys.length > 0) { Context context = getActivity(); for (String key : keys) { VpnProfile profile = VpnProfile.decode(key, mKeyStore.get(Credentials.VPN + key)); if (profile == null) { Log.w(TAG, "bad profile: key = " + key); mKeyStore.delete(Credentials.VPN + key); } else { VpnPreference preference = new VpnPreference(context, profile); mPreferences.put(key, preference); group.addPreference(preference); } } } group.findPreference("add_network").setOnPreferenceClickListener(this); } // Show the dialog if there is one. if (mDialog != null) { mDialog.setOnDismissListener(this); mDialog.show(); } // Start monitoring. if (mUpdater == null) { mUpdater = new Handler(this); } mUpdater.sendEmptyMessage(0); // Register for context menu. Hmmm, getListView() is hidden? registerForContextMenu(getListView()); } @Override public void onPause() { super.onPause(); // Hide the dialog if there is one. if (mDialog != null) { mDialog.setOnDismissListener(null); mDialog.dismiss(); } // Unregister for context menu. if (getView() != null) { unregisterForContextMenu(getListView()); } } @Override public void onDismiss(DialogInterface dialog) { // Here is the exit of a dialog. mDialog = null; } @Override public void onClick(DialogInterface dialog, int button) { if (button == DialogInterface.BUTTON_POSITIVE) { // Always save the profile. VpnProfile profile = mDialog.getProfile(); mKeyStore.put(Credentials.VPN + profile.key, profile.encode()); // Update the preference. VpnPreference preference = mPreferences.get(profile.key); if (preference != null) { disconnect(profile.key); preference.update(profile); } else { preference = new VpnPreference(getActivity(), profile); mPreferences.put(profile.key, preference); getPreferenceScreen().addPreference(preference); } // If we are not editing, connect! if (!mDialog.isEditing()) { try { connect(profile); } catch (Exception e) { Log.e(TAG, "connect", e); } } } } @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { if (mDialog != null) { Log.v(TAG, "onCreateContextMenu() is called when mDialog != null"); return; } if (info instanceof AdapterContextMenuInfo) { Preference preference = (Preference) getListView().getItemAtPosition( ((AdapterContextMenuInfo) info).position); if (preference instanceof VpnPreference) { VpnProfile profile = ((VpnPreference) preference).getProfile(); mSelectedKey = profile.key; menu.setHeaderTitle(profile.name); menu.add(Menu.NONE, R.string.vpn_menu_edit, 0, R.string.vpn_menu_edit); menu.add(Menu.NONE, R.string.vpn_menu_delete, 0, R.string.vpn_menu_delete); } } } @Override public boolean onContextItemSelected(MenuItem item) { if (mDialog != null) { Log.v(TAG, "onContextItemSelected() is called when mDialog != null"); return false; } VpnPreference preference = mPreferences.get(mSelectedKey); if (preference == null) { Log.v(TAG, "onContextItemSelected() is called but no preference is found"); return false; } switch (item.getItemId()) { case R.string.vpn_menu_edit: mDialog = new VpnDialog(getActivity(), this, preference.getProfile(), true); mDialog.setOnDismissListener(this); mDialog.show(); return true; case R.string.vpn_menu_delete: disconnect(mSelectedKey); getPreferenceScreen().removePreference(preference); mPreferences.remove(mSelectedKey); mKeyStore.delete(Credentials.VPN + mSelectedKey); return true; } return false; }
@Override public boolean onPreferenceClick(Preference preference) { if (mDialog != null) { Log.v(TAG, "onPreferenceClick() is called when mDialog != null"); return true; } if (preference instanceof VpnPreference) { VpnProfile profile = ((VpnPreference) preference).getProfile(); if (mInfo != null && profile.key.equals(mInfo.key) && mInfo.state == LegacyVpnInfo.STATE_CONNECTED) { try { mInfo.intent.send(); return true; } catch (Exception e) { // ignore } } mDialog = new VpnDialog(getActivity(), this, profile, false); } else { // Generate a new key. Here we just use the current time. long millis = System.currentTimeMillis(); while (mPreferences.containsKey(Long.toHexString(millis))) { ++millis; } mDialog = new VpnDialog(getActivity(), this, new VpnProfile(Long.toHexString(millis)), true); } mDialog.setOnDismissListener(this); mDialog.show(); return true; } @Override public boolean handleMessage(Message message) { mUpdater.removeMessages(0); if (isResumed()) { try { LegacyVpnInfo info = mService.getLegacyVpnInfo(); if (mInfo != null) { VpnPreference preference = mPreferences.get(mInfo.key); if (preference != null) { preference.update(-1); } mInfo = null; } if (info != null) { VpnPreference preference = mPreferences.get(info.key); if (preference != null) { preference.update(info.state); mInfo = info; } } } catch (Exception e) { // ignore } mUpdater.sendEmptyMessageDelayed(0, 1000); } return true; } private String[] getDefaultNetwork() throws Exception { LinkProperties network = mService.getActiveLinkProperties(); if (network == null) { Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show(); throw new IllegalStateException("Network is not available"); } String interfaze = network.getInterfaceName(); if (interfaze == null) { Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show(); throw new IllegalStateException("Cannot get the default interface"); } String gateway = null; for (RouteInfo route : network.getRoutes()) { // Currently legacy VPN only works on IPv4. if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) { gateway = route.getGateway().getHostAddress(); break; } } if (gateway == null) { Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show(); throw new IllegalStateException("Cannot get the default gateway"); } return new String[] {interfaze, gateway}; } }
private void connect(VpnProfile profile) throws Exception { // Get the default interface and the default gateway. String[] network = getDefaultNetwork(); String interfaze = network[0]; String gateway = network[1]; // Load certificates. String privateKey = ""; String userCert = ""; String caCert = ""; String serverCert = ""; if (!profile.ipsecUserCert.isEmpty()) { /* * VPN has a special exception in keystore to allow it to use system * UID certs. */ privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; byte[] value = mKeyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert); userCert = (value == null) ? null : new String(value, Charsets.UTF_8); } if (!profile.ipsecCaCert.isEmpty()) { byte[] value = mKeyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert); caCert = (value == null) ? null : new String(value, Charsets.UTF_8); } if (!profile.ipsecServerCert.isEmpty()) { byte[] value = mKeyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert); serverCert = (value == null) ? null : new String(value, Charsets.UTF_8); } if (privateKey == null || userCert == null || caCert == null || serverCert == null) { Toast.makeText(getActivity(), R.string.vpn_missing_cert, Toast.LENGTH_LONG).show(); throw new IllegalStateException("Cannot load credentials"); } // Prepare arguments for racoon. String[] racoon = null; switch (profile.type) { case VpnProfile.TYPE_L2TP_IPSEC_PSK: racoon = new String[] { interfaze, profile.server, "udppsk", profile.ipsecIdentifier, profile.ipsecSecret, "1701", }; break; case VpnProfile.TYPE_L2TP_IPSEC_RSA: racoon = new String[] { interfaze, profile.server, "udprsa", privateKey, userCert, caCert, serverCert, "1701", }; break; case VpnProfile.TYPE_IPSEC_XAUTH_PSK: racoon = new String[] { interfaze, profile.server, "xauthpsk", profile.ipsecIdentifier, profile.ipsecSecret, profile.username, profile.password, "", gateway, }; break; case VpnProfile.TYPE_IPSEC_XAUTH_RSA: racoon = new String[] { interfaze, profile.server, "xauthrsa", privateKey, userCert, caCert, serverCert, profile.username, profile.password, "", gateway, }; break; case VpnProfile.TYPE_IPSEC_HYBRID_RSA: racoon = new String[] { interfaze, profile.server, "hybridrsa", caCert, serverCert, profile.username, profile.password, "", gateway, }; break; } // Prepare arguments for mtpd. String[] mtpd = null; switch (profile.type) { case VpnProfile.TYPE_PPTP: mtpd = new String[] { interfaze, "pptp", profile.server, "1723", "name", profile.username, "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", (profile.mppe ? "+mppe" : "nomppe"), }; break; case VpnProfile.TYPE_L2TP_IPSEC_PSK: case VpnProfile.TYPE_L2TP_IPSEC_RSA: mtpd = new String[] { interfaze, "l2tp", profile.server, "1701", profile.l2tpSecret, "name", profile.username, "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", }; break; } VpnConfig config = new VpnConfig(); config.user = profile.key; config.interfaze = interfaze; config.session = profile.name; config.routes = profile.routes; if (!profile.dnsServers.isEmpty()) { config.dnsServers = Arrays.asList(profile.dnsServers.split(" +")); } if (!profile.searchDomains.isEmpty()) { config.searchDomains = Arrays.asList(profile.searchDomains.split(" +")); } mService.startLegacyVpn(config, racoon, mtpd); } private void disconnect(String key) { if (mInfo != null && key.equals(mInfo.key)) { try { mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); } catch (Exception e) { // ignore } } } @Override protected int getHelpResource() { return R.string.help_url_vpn; } private class VpnPreference extends Preference { private VpnProfile mProfile; private int mState = -1; VpnPreference(Context context, VpnProfile profile) { super(context); setPersistent(false); setOrder(0); setOnPreferenceClickListener(VpnSettings.this); mProfile = profile; update(); } VpnProfile getProfile() { return mProfile; } void update(VpnProfile profile) { mProfile = profile; update(); } void update(int state) { mState = state; update(); } void update() { if (mState < 0) { String[] types = getContext().getResources() .getStringArray(R.array.vpn_types_long); setSummary(types[mProfile.type]); } else { String[] states = getContext().getResources() .getStringArray(R.array.vpn_states); setSummary(states[mState]); } setTitle(mProfile.name); notifyHierarchyChanged(); } @Override public int compareTo(Preference preference) { int result = -1; if (preference instanceof VpnPreference) { VpnPreference another = (VpnPreference) preference; if ((result = another.mState - mState) == 0 && (result = mProfile.name.compareTo(another.mProfile.name)) == 0 && (result = mProfile.type - another.mProfile.type) == 0) { result = mProfile.key.compareTo(another.mProfile.key); } } return result; } }
/*
* 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.settings.vpn2;import com.android.settings.R;import android.content.Context;
import android.content.DialogInterface;
import android.net.IConnectivityManager;
import android.net.LinkProperties;
import android.net.RouteInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.preference.Preference;
import android.preference.PreferenceGroup;
import android.security.Credentials;
import android.security.KeyStore;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Toast;import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.settings.SettingsPreferenceFragment;import java.net.Inet4Address;
import java.nio.charset.Charsets;
import java.util.Arrays;
import java.util.HashMap;public class VpnSettings extends SettingsPreferenceFragment implements
Handler.Callback, Preference.OnPreferenceClickListener,
DialogInterface.OnClickListener, DialogInterface.OnDismissListener { private static final String TAG = "VpnSettings"; private final IConnectivityManager mService = IConnectivityManager.Stub
.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
private final KeyStore mKeyStore = KeyStore.getInstance();
private boolean mUnlocking = false; private HashMap<String, VpnPreference> mPreferences;
private VpnDialog mDialog; private Handler mUpdater;
private LegacyVpnInfo mInfo; // The key of the profile for the current ContextMenu.
private String mSelectedKey; @Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
addPreferencesFromResource(R.xml.vpn_settings2);
getPreferenceScreen().setOrderingAsAdded(false); if (savedState != null) {
VpnProfile profile = VpnProfile.decode(savedState.getString("VpnKey"),
savedState.getByteArray("VpnProfile"));
if (profile != null) {
mDialog = new VpnDialog(getActivity(), this, profile,
savedState.getBoolean("VpnEditing"));
}
}
} @Override
public void onSaveInstanceState(Bundle savedState) {
// We do not save view hierarchy, as they are just profiles.
if (mDialog != null) {
VpnProfile profile = mDialog.getProfile();
savedState.putString("VpnKey", profile.key);
savedState.putByteArray("VpnProfile", profile.encode());
savedState.putBoolean("VpnEditing", mDialog.isEditing());
}
// else?
} @Override
public void onResume() {
super.onResume(); // Check KeyStore here, so others do not need to deal with it.
if (mKeyStore.state() != KeyStore.State.UNLOCKED) {
if (!mUnlocking) {
// Let us unlock KeyStore. See you later!
Credentials.getInstance().unlock(getActivity());
} else {
// We already tried, but it is still not working!
finishFragment();
}
mUnlocking = !mUnlocking;
return;
} // Now KeyStore is always unlocked. Reset the flag.
mUnlocking = false; // Currently we are the only user of profiles in KeyStore.
// Assuming KeyStore and KeyGuard do the right thing, we can
// safely cache profiles in the memory.
if (mPreferences == null) {
mPreferences = new HashMap<String, VpnPreference>();
PreferenceGroup group = getPreferenceScreen(); String[] keys = mKeyStore.saw(Credentials.VPN);
if (keys != null && keys.length > 0) {
Context context = getActivity(); for (String key : keys) {
VpnProfile profile = VpnProfile.decode(key,
mKeyStore.get(Credentials.VPN + key));
if (profile == null) {
Log.w(TAG, "bad profile: key = " + key);
mKeyStore.delete(Credentials.VPN + key);
} else {
VpnPreference preference = new VpnPreference(context, profile);
mPreferences.put(key, preference);
group.addPreference(preference);
}
}
}
group.findPreference("add_network").setOnPreferenceClickListener(this);
} // Show the dialog if there is one.
if (mDialog != null) {
mDialog.setOnDismissListener(this);
mDialog.show();
} // Start monitoring.
if (mUpdater == null) {
mUpdater = new Handler(this);
}
mUpdater.sendEmptyMessage(0); // Register for context menu. Hmmm, getListView() is hidden?
registerForContextMenu(getListView());
} @Override
public void onPause() {
super.onPause(); // Hide the dialog if there is one.
if (mDialog != null) {
mDialog.setOnDismissListener(null);
mDialog.dismiss();
} // Unregister for context menu.
if (getView() != null) {
unregisterForContextMenu(getListView());
}
} @Override
public void onDismiss(DialogInterface dialog) {
// Here is the exit of a dialog.
mDialog = null;
} @Override
public void onClick(DialogInterface dialog, int button) {
if (button == DialogInterface.BUTTON_POSITIVE) {
// Always save the profile.
VpnProfile profile = mDialog.getProfile();
mKeyStore.put(Credentials.VPN + profile.key, profile.encode()); // Update the preference.
VpnPreference preference = mPreferences.get(profile.key);
if (preference != null) {
disconnect(profile.key);
preference.update(profile);
} else {
preference = new VpnPreference(getActivity(), profile);
mPreferences.put(profile.key, preference);
getPreferenceScreen().addPreference(preference);
} // If we are not editing, connect!
if (!mDialog.isEditing()) {
try {
connect(profile);
} catch (Exception e) {
Log.e(TAG, "connect", e);
}
}
}
} @Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
if (mDialog != null) {
Log.v(TAG, "onCreateContextMenu() is called when mDialog != null");
return;
} if (info instanceof AdapterContextMenuInfo) {
Preference preference = (Preference) getListView().getItemAtPosition(
((AdapterContextMenuInfo) info).position);
if (preference instanceof VpnPreference) {
VpnProfile profile = ((VpnPreference) preference).getProfile();
mSelectedKey = profile.key;
menu.setHeaderTitle(profile.name);
menu.add(Menu.NONE, R.string.vpn_menu_edit, 0, R.string.vpn_menu_edit);
menu.add(Menu.NONE, R.string.vpn_menu_delete, 0, R.string.vpn_menu_delete);
}
}
} @Override
public boolean onContextItemSelected(MenuItem item) {
if (mDialog != null) {
Log.v(TAG, "onContextItemSelected() is called when mDialog != null");
return false;
} VpnPreference preference = mPreferences.get(mSelectedKey);
if (preference == null) {
Log.v(TAG, "onContextItemSelected() is called but no preference is found");
return false;
} switch (item.getItemId()) {
case R.string.vpn_menu_edit:
mDialog = new VpnDialog(getActivity(), this, preference.getProfile(), true);
mDialog.setOnDismissListener(this);
mDialog.show();
return true;
case R.string.vpn_menu_delete:
disconnect(mSelectedKey);
getPreferenceScreen().removePreference(preference);
mPreferences.remove(mSelectedKey);
mKeyStore.delete(Credentials.VPN + mSelectedKey);
return true;
}
return false;
}
public boolean onPreferenceClick(Preference preference) {
if (mDialog != null) {
Log.v(TAG, "onPreferenceClick() is called when mDialog != null");
return true;
} if (preference instanceof VpnPreference) {
VpnProfile profile = ((VpnPreference) preference).getProfile();
if (mInfo != null && profile.key.equals(mInfo.key) &&
mInfo.state == LegacyVpnInfo.STATE_CONNECTED) {
try {
mInfo.intent.send();
return true;
} catch (Exception e) {
// ignore
}
}
mDialog = new VpnDialog(getActivity(), this, profile, false);
} else {
// Generate a new key. Here we just use the current time.
long millis = System.currentTimeMillis();
while (mPreferences.containsKey(Long.toHexString(millis))) {
++millis;
}
mDialog = new VpnDialog(getActivity(), this,
new VpnProfile(Long.toHexString(millis)), true);
}
mDialog.setOnDismissListener(this);
mDialog.show();
return true;
} @Override
public boolean handleMessage(Message message) {
mUpdater.removeMessages(0); if (isResumed()) {
try {
LegacyVpnInfo info = mService.getLegacyVpnInfo();
if (mInfo != null) {
VpnPreference preference = mPreferences.get(mInfo.key);
if (preference != null) {
preference.update(-1);
}
mInfo = null;
}
if (info != null) {
VpnPreference preference = mPreferences.get(info.key);
if (preference != null) {
preference.update(info.state);
mInfo = info;
}
}
} catch (Exception e) {
// ignore
}
mUpdater.sendEmptyMessageDelayed(0, 1000);
}
return true;
} private String[] getDefaultNetwork() throws Exception {
LinkProperties network = mService.getActiveLinkProperties();
if (network == null) {
Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show();
throw new IllegalStateException("Network is not available");
}
String interfaze = network.getInterfaceName();
if (interfaze == null) {
Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show();
throw new IllegalStateException("Cannot get the default interface");
}
String gateway = null;
for (RouteInfo route : network.getRoutes()) {
// Currently legacy VPN only works on IPv4.
if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
gateway = route.getGateway().getHostAddress();
break;
}
}
if (gateway == null) {
Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show();
throw new IllegalStateException("Cannot get the default gateway");
}
return new String[] {interfaze, gateway};
}
}
// Get the default interface and the default gateway.
String[] network = getDefaultNetwork();
String interfaze = network[0];
String gateway = network[1]; // Load certificates.
String privateKey = "";
String userCert = "";
String caCert = "";
String serverCert = "";
if (!profile.ipsecUserCert.isEmpty()) {
/*
* VPN has a special exception in keystore to allow it to use system
* UID certs.
*/
privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
byte[] value = mKeyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
userCert = (value == null) ? null : new String(value, Charsets.UTF_8);
}
if (!profile.ipsecCaCert.isEmpty()) {
byte[] value = mKeyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
caCert = (value == null) ? null : new String(value, Charsets.UTF_8);
}
if (!profile.ipsecServerCert.isEmpty()) {
byte[] value = mKeyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
serverCert = (value == null) ? null : new String(value, Charsets.UTF_8);
}
if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
Toast.makeText(getActivity(), R.string.vpn_missing_cert, Toast.LENGTH_LONG).show();
throw new IllegalStateException("Cannot load credentials");
} // Prepare arguments for racoon.
String[] racoon = null;
switch (profile.type) {
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
racoon = new String[] {
interfaze, profile.server, "udppsk", profile.ipsecIdentifier,
profile.ipsecSecret, "1701",
};
break;
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
racoon = new String[] {
interfaze, profile.server, "udprsa", privateKey, userCert,
caCert, serverCert, "1701",
};
break;
case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
racoon = new String[] {
interfaze, profile.server, "xauthpsk", profile.ipsecIdentifier,
profile.ipsecSecret, profile.username, profile.password, "", gateway,
};
break;
case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
racoon = new String[] {
interfaze, profile.server, "xauthrsa", privateKey, userCert,
caCert, serverCert, profile.username, profile.password, "", gateway,
};
break;
case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
racoon = new String[] {
interfaze, profile.server, "hybridrsa",
caCert, serverCert, profile.username, profile.password, "", gateway,
};
break;
} // Prepare arguments for mtpd.
String[] mtpd = null;
switch (profile.type) {
case VpnProfile.TYPE_PPTP:
mtpd = new String[] {
interfaze, "pptp", profile.server, "1723",
"name", profile.username, "password", profile.password,
"linkname", "vpn", "refuse-eap", "nodefaultroute",
"usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
(profile.mppe ? "+mppe" : "nomppe"),
};
break;
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
mtpd = new String[] {
interfaze, "l2tp", profile.server, "1701", profile.l2tpSecret,
"name", profile.username, "password", profile.password,
"linkname", "vpn", "refuse-eap", "nodefaultroute",
"usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
};
break;
} VpnConfig config = new VpnConfig();
config.user = profile.key;
config.interfaze = interfaze;
config.session = profile.name;
config.routes = profile.routes;
if (!profile.dnsServers.isEmpty()) {
config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
}
if (!profile.searchDomains.isEmpty()) {
config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
} mService.startLegacyVpn(config, racoon, mtpd);
} private void disconnect(String key) {
if (mInfo != null && key.equals(mInfo.key)) {
try {
mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
} catch (Exception e) {
// ignore
}
}
} @Override
protected int getHelpResource() {
return R.string.help_url_vpn;
} private class VpnPreference extends Preference {
private VpnProfile mProfile;
private int mState = -1; VpnPreference(Context context, VpnProfile profile) {
super(context);
setPersistent(false);
setOrder(0);
setOnPreferenceClickListener(VpnSettings.this); mProfile = profile;
update();
} VpnProfile getProfile() {
return mProfile;
} void update(VpnProfile profile) {
mProfile = profile;
update();
} void update(int state) {
mState = state;
update();
} void update() {
if (mState < 0) {
String[] types = getContext().getResources()
.getStringArray(R.array.vpn_types_long);
setSummary(types[mProfile.type]);
} else {
String[] states = getContext().getResources()
.getStringArray(R.array.vpn_states);
setSummary(states[mState]);
}
setTitle(mProfile.name);
notifyHierarchyChanged();
} @Override
public int compareTo(Preference preference) {
int result = -1;
if (preference instanceof VpnPreference) {
VpnPreference another = (VpnPreference) preference;
if ((result = another.mState - mState) == 0 &&
(result = mProfile.name.compareTo(another.mProfile.name)) == 0 &&
(result = mProfile.type - another.mProfile.type) == 0) {
result = mProfile.key.compareTo(another.mProfile.key);
}
}
return result;
}
}