Merge "Migrate legacy VPN arguments to system_server." into jb-mr1-dev
This commit is contained in:
@@ -26,6 +26,7 @@ import android.os.ParcelFileDescriptor;
|
||||
|
||||
import com.android.internal.net.LegacyVpnInfo;
|
||||
import com.android.internal.net.VpnConfig;
|
||||
import com.android.internal.net.VpnProfile;
|
||||
|
||||
/**
|
||||
* Interface that answers queries about, and allows changing, the
|
||||
@@ -118,7 +119,7 @@ interface IConnectivityManager
|
||||
|
||||
ParcelFileDescriptor establishVpn(in VpnConfig config);
|
||||
|
||||
void startLegacyVpn(in VpnConfig config, in String[] racoon, in String[] mtpd);
|
||||
void startLegacyVpn(in VpnProfile profile);
|
||||
|
||||
LegacyVpnInfo getLegacyVpnInfo();
|
||||
}
|
||||
|
||||
19
core/java/com/android/internal/net/VpnProfile.aidl
Normal file
19
core/java/com/android/internal/net/VpnProfile.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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;
|
||||
|
||||
parcelable VpnProfile;
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.internal.net;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.nio.charset.Charsets;
|
||||
|
||||
/**
|
||||
@@ -27,7 +30,7 @@ import java.nio.charset.Charsets;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class VpnProfile implements Cloneable {
|
||||
public class VpnProfile implements Cloneable, Parcelable {
|
||||
// Match these constants with R.array.vpn_types.
|
||||
public static final int TYPE_PPTP = 0;
|
||||
public static final int TYPE_L2TP_IPSEC_PSK = 1;
|
||||
@@ -120,4 +123,28 @@ public class VpnProfile implements Cloneable {
|
||||
builder.append('\0').append(ipsecServerCert);
|
||||
return builder.toString().getBytes(Charsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeString(key);
|
||||
out.writeByteArray(encode());
|
||||
}
|
||||
|
||||
public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
|
||||
@Override
|
||||
public VpnProfile createFromParcel(Parcel in) {
|
||||
final String key = in.readString();
|
||||
return decode(key, in.createByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VpnProfile[] newArray(int size) {
|
||||
return new VpnProfile[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,11 @@ public class ManageDialog extends AlertActivity implements
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
mConfig.configureIntent.send();
|
||||
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
|
||||
mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
|
||||
if (mConfig.legacy) {
|
||||
mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
|
||||
} else {
|
||||
mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "onClick", e);
|
||||
|
||||
@@ -31,6 +31,8 @@ import static android.net.ConnectivityManager.isNetworkTypeValid;
|
||||
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
|
||||
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.bluetooth.BluetoothTetheringDataTracker;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -78,6 +80,7 @@ import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.Settings;
|
||||
import android.security.KeyStore;
|
||||
import android.text.TextUtils;
|
||||
import android.util.EventLog;
|
||||
import android.util.Slog;
|
||||
@@ -85,8 +88,10 @@ import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.net.LegacyVpnInfo;
|
||||
import com.android.internal.net.VpnConfig;
|
||||
import com.android.internal.net.VpnProfile;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import com.android.internal.telephony.PhoneConstants;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.am.BatteryStatsService;
|
||||
import com.android.server.connectivity.Tethering;
|
||||
import com.android.server.connectivity.Vpn;
|
||||
@@ -137,6 +142,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
private Tethering mTethering;
|
||||
private boolean mTetheringConfigValid = false;
|
||||
|
||||
private final KeyStore mKeyStore;
|
||||
|
||||
private Vpn mVpn;
|
||||
private VpnCallback mVpnCallback = new VpnCallback();
|
||||
|
||||
@@ -371,6 +378,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
mContext = checkNotNull(context, "missing Context");
|
||||
mNetd = checkNotNull(netManager, "missing INetworkManagementService");
|
||||
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
|
||||
mKeyStore = KeyStore.getInstance();
|
||||
|
||||
try {
|
||||
mPolicyManager.registerListener(mPolicyListener);
|
||||
@@ -3124,14 +3132,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start legacy VPN and return an intent to VpnDialogs. This method is
|
||||
* used by VpnSettings and not available in ConnectivityManager.
|
||||
* Permissions are checked in Vpn class.
|
||||
* @hide
|
||||
* Start legacy VPN, controlling native daemons as needed. Creates a
|
||||
* secondary thread to perform connection work, returning quickly.
|
||||
*/
|
||||
@Override
|
||||
public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
|
||||
mVpn.startLegacyVpn(config, racoon, mtpd);
|
||||
public void startLegacyVpn(VpnProfile profile) {
|
||||
final LinkProperties egress = getActiveLinkProperties();
|
||||
if (egress == null) {
|
||||
throw new IllegalStateException("Missing active network connection");
|
||||
}
|
||||
mVpn.startLegacyVpn(profile, mKeyStore, egress);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,9 +34,11 @@ import android.graphics.drawable.Drawable;
|
||||
import android.net.BaseNetworkStateTracker;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.INetworkManagementEventObserver;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.LocalSocket;
|
||||
import android.net.LocalSocketAddress;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.NetworkInfo.DetailedState;
|
||||
import android.os.Binder;
|
||||
import android.os.FileUtils;
|
||||
@@ -48,11 +50,15 @@ import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemService;
|
||||
import android.security.Credentials;
|
||||
import android.security.KeyStore;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.net.LegacyVpnInfo;
|
||||
import com.android.internal.net.VpnConfig;
|
||||
import com.android.internal.net.VpnProfile;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.ConnectivityService.VpnCallback;
|
||||
import com.android.server.net.BaseNetworkObserver;
|
||||
@@ -60,6 +66,8 @@ import com.android.server.net.BaseNetworkObserver;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.charset.Charsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -430,20 +438,127 @@ public class Vpn extends BaseNetworkStateTracker {
|
||||
private native int jniCheck(String interfaze);
|
||||
private native void jniProtect(int socket, String interfaze);
|
||||
|
||||
/**
|
||||
* Start legacy VPN. This method stops the daemons and restart them
|
||||
* if arguments are not null. Heavy things are offloaded to another
|
||||
* thread, so callers will not be blocked for a long time.
|
||||
*
|
||||
* @param config The parameters to configure the network.
|
||||
* @param racoon The arguments to be passed to racoon.
|
||||
* @param mtpd The arguments to be passed to mtpd.
|
||||
*/
|
||||
public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
|
||||
stopLegacyVpn();
|
||||
private static String findLegacyVpnGateway(LinkProperties prop) {
|
||||
for (RouteInfo route : prop.getRoutes()) {
|
||||
// Currently legacy VPN only works on IPv4.
|
||||
if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
|
||||
return route.getGateway().getHostAddress();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move legacy definition to settings
|
||||
throw new IllegalStateException("Unable to find suitable gateway");
|
||||
}
|
||||
|
||||
/**
|
||||
* Start legacy VPN, controlling native daemons as needed. Creates a
|
||||
* secondary thread to perform connection work, returning quickly.
|
||||
*/
|
||||
public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
|
||||
if (keyStore.state() != KeyStore.State.UNLOCKED) {
|
||||
throw new IllegalStateException("KeyStore isn't unlocked");
|
||||
}
|
||||
|
||||
final String iface = egress.getInterfaceName();
|
||||
final String gateway = findLegacyVpnGateway(egress);
|
||||
|
||||
// Load certificates.
|
||||
String privateKey = "";
|
||||
String userCert = "";
|
||||
String caCert = "";
|
||||
String serverCert = "";
|
||||
if (!profile.ipsecUserCert.isEmpty()) {
|
||||
privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
|
||||
byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
|
||||
userCert = (value == null) ? null : new String(value, Charsets.UTF_8);
|
||||
}
|
||||
if (!profile.ipsecCaCert.isEmpty()) {
|
||||
byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
|
||||
caCert = (value == null) ? null : new String(value, Charsets.UTF_8);
|
||||
}
|
||||
if (!profile.ipsecServerCert.isEmpty()) {
|
||||
byte[] value = keyStore.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) {
|
||||
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[] {
|
||||
iface, profile.server, "udppsk", profile.ipsecIdentifier,
|
||||
profile.ipsecSecret, "1701",
|
||||
};
|
||||
break;
|
||||
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
|
||||
racoon = new String[] {
|
||||
iface, profile.server, "udprsa", privateKey, userCert,
|
||||
caCert, serverCert, "1701",
|
||||
};
|
||||
break;
|
||||
case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
|
||||
racoon = new String[] {
|
||||
iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
|
||||
profile.ipsecSecret, profile.username, profile.password, "", gateway,
|
||||
};
|
||||
break;
|
||||
case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
|
||||
racoon = new String[] {
|
||||
iface, profile.server, "xauthrsa", privateKey, userCert,
|
||||
caCert, serverCert, profile.username, profile.password, "", gateway,
|
||||
};
|
||||
break;
|
||||
case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
|
||||
racoon = new String[] {
|
||||
iface, 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[] {
|
||||
iface, "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[] {
|
||||
iface, "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.legacy = true;
|
||||
config.user = profile.key;
|
||||
config.interfaze = iface;
|
||||
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(" +"));
|
||||
}
|
||||
|
||||
startLegacyVpn(config, racoon, mtpd);
|
||||
}
|
||||
|
||||
private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
|
||||
stopLegacyVpn();
|
||||
|
||||
// Prepare for the new request. This also checks the caller.
|
||||
prepare(null, VpnConfig.LEGACY_VPN);
|
||||
|
||||
Reference in New Issue
Block a user