Skip to content

Commit 34f8631

Browse files
jsharkeyAndroid (Google) Code Review
authored andcommitted
Merge "Migrate legacy VPN arguments to system_server." into jb-mr1-dev
2 parents 96702ad + 82f8521 commit 34f8631

File tree

6 files changed

+195
-19
lines changed

6 files changed

+195
-19
lines changed

core/java/android/net/IConnectivityManager.aidl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import android.os.ParcelFileDescriptor;
2626

2727
import com.android.internal.net.LegacyVpnInfo;
2828
import com.android.internal.net.VpnConfig;
29+
import com.android.internal.net.VpnProfile;
2930

3031
/**
3132
* Interface that answers queries about, and allows changing, the
@@ -118,7 +119,7 @@ interface IConnectivityManager
118119

119120
ParcelFileDescriptor establishVpn(in VpnConfig config);
120121

121-
void startLegacyVpn(in VpnConfig config, in String[] racoon, in String[] mtpd);
122+
void startLegacyVpn(in VpnProfile profile);
122123

123124
LegacyVpnInfo getLegacyVpnInfo();
124125
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright (C) 2012 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+
17+
package com.android.internal.net;
18+
19+
parcelable VpnProfile;

core/java/com/android/internal/net/VpnProfile.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package com.android.internal.net;
1818

19+
import android.os.Parcel;
20+
import android.os.Parcelable;
21+
1922
import java.nio.charset.Charsets;
2023

2124
/**
@@ -27,7 +30,7 @@
2730
*
2831
* @hide
2932
*/
30-
public class VpnProfile implements Cloneable {
33+
public class VpnProfile implements Cloneable, Parcelable {
3134
// Match these constants with R.array.vpn_types.
3235
public static final int TYPE_PPTP = 0;
3336
public static final int TYPE_L2TP_IPSEC_PSK = 1;
@@ -120,4 +123,28 @@ public byte[] encode() {
120123
builder.append('\0').append(ipsecServerCert);
121124
return builder.toString().getBytes(Charsets.UTF_8);
122125
}
126+
127+
@Override
128+
public void writeToParcel(Parcel out, int flags) {
129+
out.writeString(key);
130+
out.writeByteArray(encode());
131+
}
132+
133+
public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
134+
@Override
135+
public VpnProfile createFromParcel(Parcel in) {
136+
final String key = in.readString();
137+
return decode(key, in.createByteArray());
138+
}
139+
140+
@Override
141+
public VpnProfile[] newArray(int size) {
142+
return new VpnProfile[size];
143+
}
144+
};
145+
146+
@Override
147+
public int describeContents() {
148+
return 0;
149+
}
123150
}

packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,11 @@ public void onClick(DialogInterface dialog, int which) {
123123
if (which == DialogInterface.BUTTON_POSITIVE) {
124124
mConfig.configureIntent.send();
125125
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
126-
mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
126+
if (mConfig.legacy) {
127+
mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
128+
} else {
129+
mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
130+
}
127131
}
128132
} catch (Exception e) {
129133
Log.e(TAG, "onClick", e);

services/java/com/android/server/ConnectivityService.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
3232
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
3333

34+
import android.app.NotificationManager;
35+
import android.app.PendingIntent;
3436
import android.bluetooth.BluetoothTetheringDataTracker;
3537
import android.content.ContentResolver;
3638
import android.content.Context;
@@ -78,15 +80,18 @@
7880
import android.os.SystemClock;
7981
import android.os.SystemProperties;
8082
import android.provider.Settings;
83+
import android.security.KeyStore;
8184
import android.text.TextUtils;
8285
import android.util.EventLog;
8386
import android.util.Slog;
8487
import android.util.SparseIntArray;
8588

8689
import com.android.internal.net.LegacyVpnInfo;
8790
import com.android.internal.net.VpnConfig;
91+
import com.android.internal.net.VpnProfile;
8892
import com.android.internal.telephony.Phone;
8993
import com.android.internal.telephony.PhoneConstants;
94+
import com.android.internal.util.Preconditions;
9095
import com.android.server.am.BatteryStatsService;
9196
import com.android.server.connectivity.Tethering;
9297
import com.android.server.connectivity.Vpn;
@@ -137,6 +142,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
137142
private Tethering mTethering;
138143
private boolean mTetheringConfigValid = false;
139144

145+
private final KeyStore mKeyStore;
146+
140147
private Vpn mVpn;
141148
private VpnCallback mVpnCallback = new VpnCallback();
142149

@@ -371,6 +378,7 @@ public ConnectivityService(Context context, INetworkManagementService netManager
371378
mContext = checkNotNull(context, "missing Context");
372379
mNetd = checkNotNull(netManager, "missing INetworkManagementService");
373380
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
381+
mKeyStore = KeyStore.getInstance();
374382

375383
try {
376384
mPolicyManager.registerListener(mPolicyListener);
@@ -3124,14 +3132,16 @@ public ParcelFileDescriptor establishVpn(VpnConfig config) {
31243132
}
31253133

31263134
/**
3127-
* Start legacy VPN and return an intent to VpnDialogs. This method is
3128-
* used by VpnSettings and not available in ConnectivityManager.
3129-
* Permissions are checked in Vpn class.
3130-
* @hide
3135+
* Start legacy VPN, controlling native daemons as needed. Creates a
3136+
* secondary thread to perform connection work, returning quickly.
31313137
*/
31323138
@Override
3133-
public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
3134-
mVpn.startLegacyVpn(config, racoon, mtpd);
3139+
public void startLegacyVpn(VpnProfile profile) {
3140+
final LinkProperties egress = getActiveLinkProperties();
3141+
if (egress == null) {
3142+
throw new IllegalStateException("Missing active network connection");
3143+
}
3144+
mVpn.startLegacyVpn(profile, mKeyStore, egress);
31353145
}
31363146

31373147
/**

services/java/com/android/server/connectivity/Vpn.java

Lines changed: 125 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@
3434
import android.net.BaseNetworkStateTracker;
3535
import android.net.ConnectivityManager;
3636
import android.net.INetworkManagementEventObserver;
37+
import android.net.LinkProperties;
3738
import android.net.LocalSocket;
3839
import android.net.LocalSocketAddress;
3940
import android.net.NetworkInfo;
41+
import android.net.RouteInfo;
4042
import android.net.NetworkInfo.DetailedState;
4143
import android.os.Binder;
4244
import android.os.FileUtils;
@@ -48,18 +50,24 @@
4850
import android.os.RemoteException;
4951
import android.os.SystemClock;
5052
import android.os.SystemService;
53+
import android.security.Credentials;
54+
import android.security.KeyStore;
5155
import android.util.Log;
56+
import android.widget.Toast;
5257

5358
import com.android.internal.R;
5459
import com.android.internal.net.LegacyVpnInfo;
5560
import com.android.internal.net.VpnConfig;
61+
import com.android.internal.net.VpnProfile;
5662
import com.android.internal.util.Preconditions;
5763
import com.android.server.ConnectivityService.VpnCallback;
5864
import com.android.server.net.BaseNetworkObserver;
5965

6066
import java.io.File;
6167
import java.io.InputStream;
6268
import java.io.OutputStream;
69+
import java.net.Inet4Address;
70+
import java.net.InetAddress;
6371
import java.nio.charset.Charsets;
6472
import java.util.Arrays;
6573

@@ -430,20 +438,127 @@ private void hideNotification() {
430438
private native int jniCheck(String interfaze);
431439
private native void jniProtect(int socket, String interfaze);
432440

441+
private static String findLegacyVpnGateway(LinkProperties prop) {
442+
for (RouteInfo route : prop.getRoutes()) {
443+
// Currently legacy VPN only works on IPv4.
444+
if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
445+
return route.getGateway().getHostAddress();
446+
}
447+
}
448+
449+
throw new IllegalStateException("Unable to find suitable gateway");
450+
}
451+
433452
/**
434-
* Start legacy VPN. This method stops the daemons and restart them
435-
* if arguments are not null. Heavy things are offloaded to another
436-
* thread, so callers will not be blocked for a long time.
437-
*
438-
* @param config The parameters to configure the network.
439-
* @param racoon The arguments to be passed to racoon.
440-
* @param mtpd The arguments to be passed to mtpd.
453+
* Start legacy VPN, controlling native daemons as needed. Creates a
454+
* secondary thread to perform connection work, returning quickly.
441455
*/
442-
public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
443-
stopLegacyVpn();
456+
public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
457+
if (keyStore.state() != KeyStore.State.UNLOCKED) {
458+
throw new IllegalStateException("KeyStore isn't unlocked");
459+
}
460+
461+
final String iface = egress.getInterfaceName();
462+
final String gateway = findLegacyVpnGateway(egress);
463+
464+
// Load certificates.
465+
String privateKey = "";
466+
String userCert = "";
467+
String caCert = "";
468+
String serverCert = "";
469+
if (!profile.ipsecUserCert.isEmpty()) {
470+
privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
471+
byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
472+
userCert = (value == null) ? null : new String(value, Charsets.UTF_8);
473+
}
474+
if (!profile.ipsecCaCert.isEmpty()) {
475+
byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
476+
caCert = (value == null) ? null : new String(value, Charsets.UTF_8);
477+
}
478+
if (!profile.ipsecServerCert.isEmpty()) {
479+
byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
480+
serverCert = (value == null) ? null : new String(value, Charsets.UTF_8);
481+
}
482+
if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
483+
throw new IllegalStateException("Cannot load credentials");
484+
}
485+
486+
// Prepare arguments for racoon.
487+
String[] racoon = null;
488+
switch (profile.type) {
489+
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
490+
racoon = new String[] {
491+
iface, profile.server, "udppsk", profile.ipsecIdentifier,
492+
profile.ipsecSecret, "1701",
493+
};
494+
break;
495+
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
496+
racoon = new String[] {
497+
iface, profile.server, "udprsa", privateKey, userCert,
498+
caCert, serverCert, "1701",
499+
};
500+
break;
501+
case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
502+
racoon = new String[] {
503+
iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
504+
profile.ipsecSecret, profile.username, profile.password, "", gateway,
505+
};
506+
break;
507+
case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
508+
racoon = new String[] {
509+
iface, profile.server, "xauthrsa", privateKey, userCert,
510+
caCert, serverCert, profile.username, profile.password, "", gateway,
511+
};
512+
break;
513+
case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
514+
racoon = new String[] {
515+
iface, profile.server, "hybridrsa",
516+
caCert, serverCert, profile.username, profile.password, "", gateway,
517+
};
518+
break;
519+
}
520+
521+
// Prepare arguments for mtpd.
522+
String[] mtpd = null;
523+
switch (profile.type) {
524+
case VpnProfile.TYPE_PPTP:
525+
mtpd = new String[] {
526+
iface, "pptp", profile.server, "1723",
527+
"name", profile.username, "password", profile.password,
528+
"linkname", "vpn", "refuse-eap", "nodefaultroute",
529+
"usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
530+
(profile.mppe ? "+mppe" : "nomppe"),
531+
};
532+
break;
533+
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
534+
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
535+
mtpd = new String[] {
536+
iface, "l2tp", profile.server, "1701", profile.l2tpSecret,
537+
"name", profile.username, "password", profile.password,
538+
"linkname", "vpn", "refuse-eap", "nodefaultroute",
539+
"usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
540+
};
541+
break;
542+
}
444543

445-
// TODO: move legacy definition to settings
544+
VpnConfig config = new VpnConfig();
446545
config.legacy = true;
546+
config.user = profile.key;
547+
config.interfaze = iface;
548+
config.session = profile.name;
549+
config.routes = profile.routes;
550+
if (!profile.dnsServers.isEmpty()) {
551+
config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
552+
}
553+
if (!profile.searchDomains.isEmpty()) {
554+
config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
555+
}
556+
557+
startLegacyVpn(config, racoon, mtpd);
558+
}
559+
560+
private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
561+
stopLegacyVpn();
447562

448563
// Prepare for the new request. This also checks the caller.
449564
prepare(null, VpnConfig.LEGACY_VPN);

0 commit comments

Comments
 (0)