Vpn.java revision 2e46764a707bd14cad22bc179669eeecb2d7c647
1ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/* 2ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Copyright (C) 2011 The Android Open Source Project 3ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 4ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 5ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * you may not use this file except in compliance with the License. 6ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * You may obtain a copy of the License at 7ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 8ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 9ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 10ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software 11ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 12ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * See the License for the specific language governing permissions and 14ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * limitations under the License. 15ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 16ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 17ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehpackage com.android.server.connectivity; 18ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 19ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.app.Notification; 20ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.app.NotificationManager; 21ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Context; 22ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Intent; 23ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.ApplicationInfo; 24ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.PackageManager; 25ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.res.Resources; 26ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.Bitmap; 27ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.Canvas; 28ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.drawable.Drawable; 29ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.net.INetworkManagementEventObserver; 3085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocket; 3185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocketAddress; 32ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.Binder; 33ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.ParcelFileDescriptor; 3485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.Process; 3585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemClock; 3685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemProperties; 37ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.util.Log; 38ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 39ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport com.android.internal.R; 402e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yehimport com.android.internal.net.LegacyVpnInfo; 4104ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yehimport com.android.internal.net.VpnConfig; 42ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport com.android.server.ConnectivityService.VpnCallback; 43ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 4485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.io.OutputStream; 4585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.nio.charset.Charsets; 4641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yehimport java.util.Arrays; 4785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 48ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/** 49ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @hide 50ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 51ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehpublic class Vpn extends INetworkManagementEventObserver.Stub { 52ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 53ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final static String TAG = "Vpn"; 54ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final static String VPN = android.Manifest.permission.VPN; 55ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 56ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final Context mContext; 57ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final VpnCallback mCallback; 58ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 59c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private String mPackage = VpnConfig.LEGACY_VPN; 60c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private String mInterface; 6185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private LegacyVpnRunner mLegacyVpnRunner; 62ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 63ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh public Vpn(Context context, VpnCallback callback) { 64ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext = context; 65ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mCallback = callback; 66ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 67ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 68ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 69e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * Protect a socket from routing changes by binding it to the given 70e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * interface. The socket IS closed by this method. 71ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 72e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param socket The socket to be bound. 73e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param name The name of the interface. 74e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh */ 75c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh public void protect(ParcelFileDescriptor socket, String interfaze) { 76e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh try { 77e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh mContext.enforceCallingPermission(VPN, "protect"); 78c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh jniProtect(socket.getFd(), interfaze); 79e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh } finally { 80e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh try { 81e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh socket.close(); 82e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh } catch (Exception e) { 83e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // ignore 84e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh } 85e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh } 86e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh } 87e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 88e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh /** 89100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Prepare for a VPN application. This method is designed to solve 90100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * race conditions. It first compares the current prepared package 91100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * with {@code oldPackage}. If they are the same, the prepared 92100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * package is revoked and replaced with {@code newPackage}. If 93100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * {@code oldPackage} is {@code null}, the comparison is omitted. 94100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * If {@code newPackage} is the same package or {@code null}, the 95100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revocation is omitted. This method returns {@code true} if the 96100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * operation is succeeded. 97e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * 98100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Legacy VPN is handled specially since it is not a real package. 99100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and 100100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * it can be revoked by itself. 101100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * 102100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @param oldPackage The package name of the old VPN application. 103100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @param newPackage The package name of the new VPN application. 104100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @return true if the operation is succeeded. 105ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 106100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh public synchronized boolean prepare(String oldPackage, String newPackage) { 107100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Return false if the package does not match. 108c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (oldPackage != null && !oldPackage.equals(mPackage)) { 109100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return false; 110100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh } 111100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh 112100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Return true if we do not need to revoke. 113100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh if (newPackage == null || 114c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh (newPackage.equals(mPackage) && !newPackage.equals(VpnConfig.LEGACY_VPN))) { 115100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return true; 116ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 117ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 118100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Only system user can revoke a package. 11941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (Binder.getCallingUid() != Process.SYSTEM_UID) { 12041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh throw new SecurityException("Unauthorized Caller"); 12141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 1227b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh 1237b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh // Check the permission of the given package. 12441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 125100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh if (!newPackage.equals(VpnConfig.LEGACY_VPN) && 126100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh pm.checkPermission(VPN, newPackage) != PackageManager.PERMISSION_GRANTED) { 127100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh throw new SecurityException(newPackage + " does not have " + VPN); 128ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 129ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 130ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Reset the interface and hide the notification. 131c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (mInterface != null) { 132c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh jniReset(mInterface); 1337b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh mCallback.restore(); 134ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh hideNotification(); 135c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = null; 136ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 137ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 138e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Send out the broadcast or stop LegacyVpnRunner. 139c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (!mPackage.equals(VpnConfig.LEGACY_VPN)) { 1407b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED); 141c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh intent.setPackage(mPackage); 1427b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1437b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh mContext.sendBroadcast(intent); 144e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh } else if (mLegacyVpnRunner != null) { 14541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mLegacyVpnRunner.exit(); 14641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mLegacyVpnRunner = null; 14741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 14841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 149c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); 150c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mPackage = newPackage; 151100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return true; 152ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 153ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 154ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 155e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * Establish a VPN network and return the file descriptor of the VPN 156e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * interface. This methods returns {@code null} if the application is 157100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revoked or not prepared. 158ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 159e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param config The parameters to configure the network. 160e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @return The file descriptor of the VPN interface. 161ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 16204ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yeh public synchronized ParcelFileDescriptor establish(VpnConfig config) { 163ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Check the permission of the caller. 164ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext.enforceCallingPermission(VPN, "establish"); 165ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 166ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Check if the caller is already prepared. 167ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 168ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh ApplicationInfo app = null; 169ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 170c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh app = pm.getApplicationInfo(mPackage, 0); 171ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (Exception e) { 1727b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 173ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 174ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (Binder.getCallingUid() != app.uid) { 1757b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 176ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 177ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 178a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh // Load the label. 179a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh String label = app.loadLabel(pm).toString(); 180a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 181a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh // Load the icon and convert it into a bitmap. 182a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh Drawable icon = app.loadIcon(pm); 183a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh Bitmap bitmap = null; 184a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) { 185a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh int width = mContext.getResources().getDimensionPixelSize( 186a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh android.R.dimen.notification_large_icon_width); 187a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh int height = mContext.getResources().getDimensionPixelSize( 188a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh android.R.dimen.notification_large_icon_height); 189a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh icon.setBounds(0, 0, width, height); 190a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 191a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh icon.draw(new Canvas(bitmap)); 192a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh } 193a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 194e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Configure the interface. Abort if any of these steps fails. 195c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd( 1963281034c1c458b4eecd867d20b64dc5edd68ec14Chia-chi Yeh jniConfigure(config.mtu, config.addresses, config.routes)); 197ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 198c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh String interfaze = jniGetName(tun.getFd()); 199c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (mInterface != null && !mInterface.equals(interfaze)) { 200c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh jniReset(mInterface); 201ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 202c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = interfaze; 203ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (RuntimeException e) { 204ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 205c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh tun.close(); 206ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (Exception ex) { 207ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // ignore 208ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 209ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh throw e; 210ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 211ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 2128909b10175303bd5e2ca82b7ba12cd0017050ef3Chia-chi Yeh // Override DNS servers and search domains. 2138909b10175303bd5e2ca82b7ba12cd0017050ef3Chia-chi Yeh mCallback.override(config.dnsServers, config.searchDomains); 214ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 2158909b10175303bd5e2ca82b7ba12cd0017050ef3Chia-chi Yeh // Fill more values. 216c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh config.packagz = mPackage; 217c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh config.interfaze = mInterface; 2188909b10175303bd5e2ca82b7ba12cd0017050ef3Chia-chi Yeh 2198909b10175303bd5e2ca82b7ba12cd0017050ef3Chia-chi Yeh // Show the notification! 220383e0524726d64302322abeba16d87faf66bae99Chia-chi Yeh showNotification(config, label, bitmap); 221c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh return tun; 222ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 223ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 224ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 225c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh public void interfaceStatusChanged(String interfaze, boolean up) { 226f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen } 227f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen 228f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen // INetworkManagementEventObserver.Stub 229c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh public void interfaceLinkStateChanged(String interfaze, boolean up) { 230ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 231ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 232ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 233c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh public void interfaceAdded(String interfaze) { 234ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 235ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 236ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 237c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh public synchronized void interfaceRemoved(String interfaze) { 238c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { 239ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mCallback.restore(); 240e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh hideNotification(); 241c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = null; 242ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 243ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 244ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 245a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh private void showNotification(VpnConfig config, String label, Bitmap icon) { 246ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh NotificationManager nm = (NotificationManager) 247ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext.getSystemService(Context.NOTIFICATION_SERVICE); 248ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 249ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (nm != null) { 250a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh String title = (label == null) ? mContext.getString(R.string.vpn_title) : 251a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh mContext.getString(R.string.vpn_title_long, label); 25234e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh String text = (config.session == null) ? mContext.getString(R.string.vpn_text) : 25334e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh mContext.getString(R.string.vpn_text_long, config.session); 2542e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh config.startTime = SystemClock.elapsedRealtime(); 255a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 256ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh long identity = Binder.clearCallingIdentity(); 257ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh Notification notification = new Notification.Builder(mContext) 258ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .setSmallIcon(R.drawable.vpn_connected) 259a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh .setLargeIcon(icon) 260a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh .setContentTitle(title) 261f8905fd13da0bfd6049daebc1cf4f8af286a04deChia-chi Yeh .setContentText(text) 2622e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh .setContentIntent(VpnConfig.getIntentForStatusPanel(mContext, config)) 263ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .setDefaults(Notification.DEFAULT_ALL) 264ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .setOngoing(true) 265ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .getNotification(); 266ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh nm.notify(R.drawable.vpn_connected, notification); 267ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh Binder.restoreCallingIdentity(identity); 268ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 269ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 270ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 271ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private void hideNotification() { 272ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh NotificationManager nm = (NotificationManager) 273ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext.getSystemService(Context.NOTIFICATION_SERVICE); 274ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 275ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (nm != null) { 276ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh long identity = Binder.clearCallingIdentity(); 277ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh nm.cancel(R.drawable.vpn_connected); 278ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh Binder.restoreCallingIdentity(identity); 279ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 280ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 281ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 2823281034c1c458b4eecd867d20b64dc5edd68ec14Chia-chi Yeh private native int jniConfigure(int mtu, String addresses, String routes); 283c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native String jniGetName(int tun); 284c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native void jniReset(String interfaze); 285c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native int jniCheck(String interfaze); 286c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native void jniProtect(int socket, String interfaze); 28785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 28885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 2892e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * Start legacy VPN. This method stops the daemons and restart them 2902e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * if arguments are not null. Heavy things are offloaded to another 291e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * thread, so callers will not be blocked for a long time. 29285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * 293e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param config The parameters to configure the network. 29485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * @param raoocn The arguments to be passed to racoon. 29585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * @param mtpd The arguments to be passed to mtpd. 29685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 2972e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { 298100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Prepare for the new request. This also checks the caller. 299100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh prepare(null, VpnConfig.LEGACY_VPN); 30085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 3012e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Start a new LegacyVpnRunner and we are done! 302100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); 303100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner.start(); 30485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 30585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 30685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 3072e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * Return the information of the current ongoing legacy VPN. 3082e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh */ 3092e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public synchronized LegacyVpnInfo getLegacyVpnInfo() { 3102e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Only system user can call this method. 3112e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh if (Binder.getCallingUid() != Process.SYSTEM_UID) { 3122e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh throw new SecurityException("Unauthorized Caller"); 3132e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 3142e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo(); 3152e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 3162e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 3172e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh /** 31885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * Bringing up a VPN connection takes time, and that is all this thread 31985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * does. Here we have plenty of time. The only thing we need to take 32085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * care of is responding to interruptions as soon as possible. Otherwise 32185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * requests will be piled up. This can be done in a Handler as a state 32285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * machine, but it is much easier to read in the current form. 32385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 32485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private class LegacyVpnRunner extends Thread { 32585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private static final String TAG = "LegacyVpnRunner"; 32685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private static final String NONE = "--"; 32785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 32841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh private final VpnConfig mConfig; 3291f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh private final String[] mDaemons; 33085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private final String[][] mArguments; 3312e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh private final LegacyVpnInfo mInfo; 3322e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 33385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private long mTimer = -1; 33485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 33541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) { 33685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh super(TAG); 33741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig = config; 33841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mDaemons = new String[] {"racoon", "mtpd"}; 33941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mArguments = new String[][] {racoon, mtpd}; 3402e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo = new LegacyVpnInfo(); 341e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 3422e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Legacy VPN is not a real package, so we use it to carry the key. 3432e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.key = mConfig.packagz; 34434e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh mConfig.packagz = VpnConfig.LEGACY_VPN; 34541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 34641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 34741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public void exit() { 348e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // We assume that everything is reset after the daemons die. 34941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh for (String daemon : mDaemons) { 35041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh SystemProperties.set("ctl.stop", daemon); 35141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 35241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh interrupt(); 35385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 35485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 3552e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public LegacyVpnInfo getInfo() { 3562e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Update the info when VPN is disconnected. 3572e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh if (mInfo.state == LegacyVpnInfo.STATE_CONNECTED && mInterface == null) { 3582e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED; 3592e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.intent = null; 3602e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 3612e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh return mInfo; 3622e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 3632e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 36485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh @Override 36585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh public void run() { 36685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the previous thread since it has been interrupted. 3672e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Waiting"); 36885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh synchronized (TAG) { 3692e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Executing"); 37085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh execute(); 37185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 37285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 37385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 37485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void checkpoint(boolean yield) throws InterruptedException { 37585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh long now = SystemClock.elapsedRealtime(); 37685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mTimer == -1) { 37785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mTimer = now; 37885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(1); 37985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } else if (now - mTimer <= 30000) { 38085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(yield ? 200 : 1); 38185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } else { 3822e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_TIMEOUT; 3832e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh throw new IllegalStateException("time is up"); 38485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 38585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 38685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 38785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void execute() { 38885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Catch all exceptions so we can clean up few things. 38985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 39085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Initialize the timer. 39185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 3922e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_INITIALIZING; 39385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 3941f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // First stop the daemons. 3951f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (String daemon : mDaemons) { 3961f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh SystemProperties.set("ctl.stop", daemon); 39785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 39885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 3991f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemons to stop. 4001f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (String daemon : mDaemons) { 4011f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String key = "init.svc." + daemon; 40285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (!"stopped".equals(SystemProperties.get(key))) { 40385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 40485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 40585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 40685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 40785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Reset the properties. 40885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh SystemProperties.set("vpn.dns", NONE); 40985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh SystemProperties.set("vpn.via", NONE); 41085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (!NONE.equals(SystemProperties.get("vpn.dns")) || 41185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh !NONE.equals(SystemProperties.get("vpn.via"))) { 41285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 41385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 41485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 415e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if we need to restart any of the daemons. 41685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh boolean restart = false; 41785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String[] arguments : mArguments) { 41885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh restart = restart || (arguments != null); 41985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 42085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (!restart) { 4212e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED; 42285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh return; 42385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 4242e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_CONNECTING; 42585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 4261f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon with arguments. 4271f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 42885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String[] arguments = mArguments[i]; 42985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (arguments == null) { 43085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh continue; 43185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 43285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 4331f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon. 4341f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 4351f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh SystemProperties.set("ctl.start", daemon); 43685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 4371f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemon to start. 4381f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String key = "init.svc." + daemon; 43985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (!"running".equals(SystemProperties.get(key))) { 44085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 44185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 44285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 44385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Create the control socket. 44485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh LocalSocket socket = new LocalSocket(); 44585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh LocalSocketAddress address = new LocalSocketAddress( 4461f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh daemon, LocalSocketAddress.Namespace.RESERVED); 44785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 44885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the socket to connect. 44985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (true) { 45085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 45185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh socket.connect(address); 45285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh break; 45385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 45485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // ignore 45585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 45685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 45785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 45885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh socket.setSoTimeout(500); 45985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 46085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Send over the arguments. 4611f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh OutputStream out = socket.getOutputStream(); 46285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String argument : arguments) { 46385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh byte[] bytes = argument.getBytes(Charsets.UTF_8); 46485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (bytes.length >= 0xFFFF) { 4653281034c1c458b4eecd867d20b64dc5edd68ec14Chia-chi Yeh throw new IllegalArgumentException("argument is too large"); 46685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 4671f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length >> 8); 4681f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length); 4691f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes); 47085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 47185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 47285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 47385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Send End-Of-Arguments. 4741f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(0xFF); 4751f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(0xFF); 4761f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.flush(); 47785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh socket.close(); 47885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 47985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 48085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Now here is the beast from the old days. We check few 48185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // properties to figure out the current status. Ideally we 48285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // can read things back from the sockets and get rid of the 48385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // properties, but we have no time... 48485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (NONE.equals(SystemProperties.get("vpn.dns")) || 48585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh NONE.equals(SystemProperties.get("vpn.via"))) { 48685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 4871f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Check if a running daemon is dead. 4881f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 4891f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 49085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mArguments[i] != null && !"running".equals( 4911f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh SystemProperties.get("init.svc." + daemon))) { 4922e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh throw new IllegalStateException(daemon + " is dead"); 49385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 49485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 49585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 49685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 49785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 49841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh // Now we are connected. Get the interface. 49934e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh mConfig.interfaze = SystemProperties.get("vpn.via"); 50085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 50141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh // Get the DNS servers if they are not set in config. 50241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { 50341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh String dnsServers = SystemProperties.get("vpn.dns").trim(); 50441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (!dnsServers.isEmpty()) { 50541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); 50641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 50741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 50841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 5093281034c1c458b4eecd867d20b64dc5edd68ec14Chia-chi Yeh // TODO: support search domains from ISAKMP mode config. 510e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 511e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // The final step must be synchronized. 51241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh synchronized (Vpn.this) { 51341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh // Check if the thread is interrupted while we are waiting. 51441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh checkpoint(false); 51541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 516e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if the interface is gone while we are waiting. 517c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (jniCheck(mConfig.interfaze) == 0) { 51834e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh throw new IllegalStateException(mConfig.interfaze + " is gone"); 51941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 520e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 521e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Now INetworkManagementEventObserver is watching our back. 522c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = mConfig.interfaze; 52341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mCallback.override(mConfig.dnsServers, mConfig.searchDomains); 52441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh showNotification(mConfig, null, null); 5252e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 5262e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Connected!"); 5272e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_CONNECTED; 5282e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.intent = VpnConfig.getIntentForStatusPanel(mContext, null); 52941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 53085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 5312e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Aborting", e); 532e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh exit(); 5332e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } finally { 5342e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Do not leave an unstable state. 5352e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING || 5362e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state == LegacyVpnInfo.STATE_CONNECTING) { 5372e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_FAILED; 5382e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 53985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 54085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 54185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 542ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh} 543