LockdownVpnTracker.java revision 15e47235c055495ec0ccc24768a6746a960d3a61
136e612a488511940b61f09803b270aa1c61b68e0Jason Sams/* 2dd6c8b34f172ba699954e4d3095dba8c0fd5e930Jason Sams * Copyright (C) 2012 The Android Open Source Project 336e612a488511940b61f09803b270aa1c61b68e0Jason Sams * 436e612a488511940b61f09803b270aa1c61b68e0Jason Sams * Licensed under the Apache License, Version 2.0 (the "License"); 536e612a488511940b61f09803b270aa1c61b68e0Jason Sams * you may not use this file except in compliance with the License. 636e612a488511940b61f09803b270aa1c61b68e0Jason Sams * You may obtain a copy of the License at 736e612a488511940b61f09803b270aa1c61b68e0Jason Sams * 836e612a488511940b61f09803b270aa1c61b68e0Jason Sams * http://www.apache.org/licenses/LICENSE-2.0 936e612a488511940b61f09803b270aa1c61b68e0Jason Sams * 1036e612a488511940b61f09803b270aa1c61b68e0Jason Sams * Unless required by applicable law or agreed to in writing, software 1136e612a488511940b61f09803b270aa1c61b68e0Jason Sams * distributed under the License is distributed on an "AS IS" BASIS, 1236e612a488511940b61f09803b270aa1c61b68e0Jason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1336e612a488511940b61f09803b270aa1c61b68e0Jason Sams * See the License for the specific language governing permissions and 1436e612a488511940b61f09803b270aa1c61b68e0Jason Sams * limitations under the License. 1536e612a488511940b61f09803b270aa1c61b68e0Jason Sams */ 1636e612a488511940b61f09803b270aa1c61b68e0Jason Sams 1736e612a488511940b61f09803b270aa1c61b68e0Jason Samspackage com.android.server.net; 1836e612a488511940b61f09803b270aa1c61b68e0Jason Sams 1943ee06857bb7f99446d1d84f8789016c5d105558Jason Samsimport static android.Manifest.permission.CONNECTIVITY_INTERNAL; 20dfac814c18f73dd7289f9927edca3e3b6ec6bc00Alex Sakhartchoukimport static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW; 2136e612a488511940b61f09803b270aa1c61b68e0Jason Samsimport static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; 229c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines 23c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.app.Notification; 24c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.app.NotificationManager; 25c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.app.PendingIntent; 26c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.content.BroadcastReceiver; 27c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.content.Context; 28c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.content.Intent; 29c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.content.IntentFilter; 30c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.net.ConnectivityManager; 31c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.net.LinkProperties; 32c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.net.LinkAddress; 33c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.net.NetworkInfo; 34c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.net.NetworkInfo.DetailedState; 35c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.net.NetworkInfo.State; 36a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Samsimport android.net.NetworkPolicyManager; 37c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.os.INetworkManagementService; 38c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.os.RemoteException; 39c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.security.Credentials; 40c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.security.KeyStore; 41c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.system.Os; 42c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.text.TextUtils; 43c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport android.util.Slog; 44c11e25c4e653124def1fb18e203b894f42106cbeTim Murray 45c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport com.android.internal.R; 46c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport com.android.internal.net.VpnConfig; 47c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport com.android.internal.net.VpnProfile; 48c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport com.android.internal.util.Preconditions; 493aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandezimport com.android.server.ConnectivityService; 503aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandezimport com.android.server.EventLogTags; 513aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandezimport com.android.server.connectivity.Vpn; 52c11e25c4e653124def1fb18e203b894f42106cbeTim Murray 53c11e25c4e653124def1fb18e203b894f42106cbeTim Murrayimport java.util.List; 543aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez 5536e612a488511940b61f09803b270aa1c61b68e0Jason Sams/** 5636e612a488511940b61f09803b270aa1c61b68e0Jason Sams * State tracker for lockdown mode. Watches for normal {@link NetworkInfo} to be 57ea84a7c51790f9ba5f2194a66d6cf4ea8d879776Jason Sams * connected and kicks off VPN connection, managing any required {@code netd} 58718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams * firewall rules. 59718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams */ 6070d4e5024298f71edb3b04867e05568f5495b4ceJason Samspublic class LockdownVpnTracker { 617d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk private static final String TAG = "LockdownVpnTracker"; 62ea84a7c51790f9ba5f2194a66d6cf4ea8d879776Jason Sams 633aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk /** Number of VPN attempts before waiting for user intervention. */ 643aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private static final int MAX_ERROR_COUNT = 4; 65718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams 66718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET"; 67718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams 68718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS"; 69718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN"; 703aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 713aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private static final int ROOT_UID = 0; 723aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 733aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private final Context mContext; 743aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private final INetworkManagementService mNetService; 753aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private final ConnectivityService mConnService; 763aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private final Vpn mVpn; 773aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private final VpnProfile mProfile; 783aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 793aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private final Object mStateLock = new Object(); 803aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 813aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private final PendingIntent mConfigIntent; 823aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private final PendingIntent mResetIntent; 833aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 843aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private String mAcceptedEgressIface; 853aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private String mAcceptedIface; 863aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private List<LinkAddress> mAcceptedSourceAddr; 873aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 883aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private int mErrorCount; 893aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 903aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk public static boolean isEnabled() { 913aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN); 923aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk } 939c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines 947d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk public LockdownVpnTracker(Context context, INetworkManagementService netService, 957d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk ConnectivityService connService, Vpn vpn, VpnProfile profile) { 96918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk mContext = Preconditions.checkNotNull(context); 97718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams mNetService = Preconditions.checkNotNull(netService); 989c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines mConnService = Preconditions.checkNotNull(connService); 99918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk mVpn = Preconditions.checkNotNull(vpn); 100918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk mProfile = Preconditions.checkNotNull(profile); 101fd79e02e0fec8620da7affaadcf275cf0518241aAlex Sakhartchouk 102fd79e02e0fec8620da7affaadcf275cf0518241aAlex Sakhartchouk final Intent configIntent = new Intent(ACTION_VPN_SETTINGS); 103fd79e02e0fec8620da7affaadcf275cf0518241aAlex Sakhartchouk configIntent.putExtra(EXTRA_PICK_LOCKDOWN, true); 104fd79e02e0fec8620da7affaadcf275cf0518241aAlex Sakhartchouk mConfigIntent = PendingIntent.getActivity(mContext, 0, configIntent, 0); 105a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams 1069c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines final Intent resetIntent = new Intent(ACTION_LOCKDOWN_RESET); 107a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams resetIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 108f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk mResetIntent = PendingIntent.getBroadcast(mContext, 0, resetIntent, 0); 109f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk } 110f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk 111f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk private BroadcastReceiver mResetReceiver = new BroadcastReceiver() { 112f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk @Override 113f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk public void onReceive(Context context, Intent intent) { 114f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk reset(); 115f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk } 116a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams }; 117a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams 118a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams /** 119a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams * Watch for state changes to both active egress network, kicking off a VPN 120a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams * connection when ready, or setting firewall rules once VPN is connected. 121a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams */ 122718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams private void handleStateChangedLocked() { 1233aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 124718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams final NetworkInfo egressInfo = mConnService.getActiveNetworkInfoUnfiltered(); 125718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams final LinkProperties egressProp = mConnService.getActiveLinkProperties(); 12602f41705199336f808ece50d81585450e7f8f61fStephen Hines 127718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams final NetworkInfo vpnInfo = mVpn.getNetworkInfo(); 128718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams final VpnConfig vpnConfig = mVpn.getLegacyVpnConfig(); 129718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams 130ef1dac28d3bf98bd61cd9874fb3ccab42105e9b6Stephen Hines // Restart VPN when egress network disconnected or changed 131718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams final boolean egressDisconnected = egressInfo == null 132718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams || State.DISCONNECTED.equals(egressInfo.getState()); 133718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams final boolean egressChanged = egressProp == null 13452d836332f6aae74ed97fda1b53681f36710af64Stephen Hines || !TextUtils.equals(mAcceptedEgressIface, egressProp.getInterfaceName()); 135718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams 136f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams final String egressTypeName = (egressInfo == null) ? 137f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams null : ConnectivityManager.getNetworkTypeName(egressInfo.getType()); 138f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams final String egressIface = (egressProp == null) ? 139f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams null : egressProp.getInterfaceName(); 140f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams Slog.d(TAG, "handleStateChanged: egress=" + egressTypeName + 141f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams " " + mAcceptedEgressIface + "->" + egressIface); 1421d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams 1431d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams if (egressDisconnected || egressChanged) { 1441d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams clearSourceRulesLocked(); 1451d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams mAcceptedEgressIface = null; 1461d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams mVpn.stopLegacyVpnPrivileged(); 1471d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams } 1481d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams if (egressDisconnected) { 1491d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams hideNotification(); 1501d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams return; 1511d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams } 1521d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams 1531d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams final int egressType = egressInfo.getType(); 1541d45c47975ab2a8cef6db5a8976276de31e1e8d0Jason Sams if (vpnInfo.getDetailedState() == DetailedState.FAILED) { 1553a2914132146f340511425d7f78540098606b512Stephen Hines EventLogTags.writeLockdownVpnError(egressType); 1563a2914132146f340511425d7f78540098606b512Stephen Hines } 157718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams 158718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams if (mErrorCount > MAX_ERROR_COUNT) { 159718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected); 160718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams 161718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams } else if (egressInfo.isConnected() && !vpnInfo.isConnectedOrConnecting()) { 162718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams if (mProfile.isValidLockdownProfile()) { 163718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams Slog.d(TAG, "Active network connected; starting VPN"); 164768bc02d815a94ad29146f1ed60c847d1af118ccJason Sams EventLogTags.writeLockdownVpnConnecting(egressType); 165768bc02d815a94ad29146f1ed60c847d1af118ccJason Sams showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected); 1669c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines 167a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams mAcceptedEgressIface = egressProp.getInterfaceName(); 168a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams try { 169a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams // Use the privileged method because Lockdown VPN is initiated by the system, so 170a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams // no additional permission checks are necessary. 171a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp); 172718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams } catch (IllegalStateException e) { 173718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams mAcceptedEgressIface = null; 174718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams Slog.e(TAG, "Failed to start VPN", e); 175718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected); 176718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams } 177718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams } else { 178718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams Slog.e(TAG, "Invalid VPN profile; requires IP-based server and DNS"); 1798e90f2bc1fa35a2dc7bd2aab8b8241b628800218Alex Sakhartchouk showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected); 1808140d7b0f62a6e5b54e318c959f2d501f7ee6784Jason Sams } 1818140d7b0f62a6e5b54e318c959f2d501f7ee6784Jason Sams 182718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams } else if (vpnInfo.isConnected() && vpnConfig != null) { 183718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams final String iface = vpnConfig.interfaze; 184718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams final List<LinkAddress> sourceAddrs = vpnConfig.addresses; 185718cd1f322ee5b62b6a49cb36195bcb18a5ab711Jason Sams 186ea84a7c51790f9ba5f2194a66d6cf4ea8d879776Jason Sams if (TextUtils.equals(iface, mAcceptedIface) 18736e612a488511940b61f09803b270aa1c61b68e0Jason Sams && sourceAddrs.equals(mAcceptedSourceAddr)) { 18836e612a488511940b61f09803b270aa1c61b68e0Jason Sams return; 1899c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines } 190a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams 191a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams Slog.d(TAG, "VPN connected using iface=" + iface + 192a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams ", sourceAddr=" + sourceAddrs.toString()); 193a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams EventLogTags.writeLockdownVpnConnected(egressType); 194a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected); 195c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams 196c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams try { 197c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams clearSourceRulesLocked(); 198c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams 199c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams mNetService.setFirewallInterfaceRule(iface, true); 200c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams for (LinkAddress addr : sourceAddrs) { 201c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams setFirewallEgressSourceRule(addr, true); 202c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams } 203c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams 204c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_ALLOW); 205c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_ALLOW); 206c1d6210fb5cc558ccea95a59a2b33bb9015fc7deJason Sams 2079c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines mErrorCount = 0; 208918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk mAcceptedIface = iface; 209918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk mAcceptedSourceAddr = sourceAddrs; 210918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk } catch (RemoteException e) { 211918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk throw new RuntimeException("Problem setting firewall rules", e); 2127d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk } 2137d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2147d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mConnService.sendConnectedBroadcast(augmentNetworkInfo(egressInfo)); 2153aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk } 2167d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk } 2177d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2183aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk public void init() { 2197d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk synchronized (mStateLock) { 2207d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk initLocked(); 2219c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines } 222918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk } 223918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk 2247d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk private void initLocked() { 2257d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk Slog.d(TAG, "initLocked()"); 2267d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2277d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mVpn.setEnableTeardown(false); 2283aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 2297d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET); 2307d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mContext.registerReceiver(mResetReceiver, resetFilter, CONNECTIVITY_INTERNAL, null); 2313aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk 2327d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk try { 2337d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk // TODO: support non-standard port numbers 2343aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk mNetService.setFirewallEgressDestRule(mProfile.server, 500, true); 2357d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mNetService.setFirewallEgressDestRule(mProfile.server, 4500, true); 2367d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mNetService.setFirewallEgressDestRule(mProfile.server, 1701, true); 2379c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines } catch (RemoteException e) { 238918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk throw new RuntimeException("Problem setting firewall rules", e); 239918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk } 2407d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2417d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk synchronized (mStateLock) { 2427d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk handleStateChangedLocked(); 2437d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk } 2443aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk } 2457d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2467d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk public void shutdown() { 2473aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk synchronized (mStateLock) { 2487d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk shutdownLocked(); 2497d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk } 2503aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk } 2517d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2527d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk private void shutdownLocked() { 2539c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines Slog.d(TAG, "shutdownLocked()"); 254918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk 255918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk mAcceptedEgressIface = null; 256918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk mErrorCount = 0; 2577d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2587d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mVpn.stopLegacyVpnPrivileged(); 2597d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk try { 2607d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mNetService.setFirewallEgressDestRule(mProfile.server, 500, false); 2613aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk mNetService.setFirewallEgressDestRule(mProfile.server, 4500, false); 2627d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mNetService.setFirewallEgressDestRule(mProfile.server, 1701, false); 2637d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk } catch (RemoteException e) { 2643aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk throw new RuntimeException("Problem setting firewall rules", e); 2657d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk } 2667d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk clearSourceRulesLocked(); 2673aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk hideNotification(); 2687d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2697d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk mContext.unregisterReceiver(mResetReceiver); 2709c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines mVpn.setEnableTeardown(true); 271918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk } 272918e840628a0b40a95fd42618f604ea5a44aebaeAlex Sakhartchouk 2737d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk public void reset() { 2747d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk Slog.d(TAG, "reset()"); 2757d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk synchronized (mStateLock) { 2767d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk // cycle tracker, reset error count, and trigger retry 2773aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk shutdownLocked(); 2787d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk initLocked(); 2797d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk handleStateChangedLocked(); 2803aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk } 2817d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk } 2827d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk 2833aac0abe7965ce9e2078c7d5796805d83e39df7cAlex Sakhartchouk private void clearSourceRulesLocked() { 2847d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk try { 2857d5f5e7c8943e043a422ad51c85d4e1684c37e28Alex Sakhartchouk if (mAcceptedIface != null) { 2869c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines mNetService.setFirewallInterfaceRule(mAcceptedIface, false); 287f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk mAcceptedIface = null; 288f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk } 289f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk if (mAcceptedSourceAddr != null) { 290f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk for (LinkAddress addr : mAcceptedSourceAddr) { 291f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk setFirewallEgressSourceRule(addr, false); 292f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk } 2939c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines 294f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_DEFAULT); 295f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_DEFAULT); 296f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk 297f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk mAcceptedSourceAddr = null; 298f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk } 299f5d8ac7cc35747ef7285ccc196f616b96229def9Alex Sakhartchouk } catch (RemoteException e) { 3009c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines throw new RuntimeException("Problem setting firewall rules", e); 301a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams } 302a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams } 303a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams 304a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams private void setFirewallEgressSourceRule( 305a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams LinkAddress address, boolean allow) throws RemoteException { 306a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams // Our source address based firewall rules must only cover our own source address, not the 307f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams // whole subnet 308f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams final String addrString = address.getAddress().getHostAddress(); 309f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams mNetService.setFirewallEgressSourceRule(addrString, allow); 310f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams } 311f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams 312f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams public void onNetworkInfoChanged() { 313f110d4b787b91dabe968a812e76e5c1f8d953487Jason Sams synchronized (mStateLock) { 3149c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines handleStateChangedLocked(); 315a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams } 316a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams } 317a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams 318a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams public void onVpnStateChanged(NetworkInfo info) { 319a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams if (info.getDetailedState() == DetailedState.FAILED) { 320a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams mErrorCount++; 3218cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams } 3228cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams synchronized (mStateLock) { 3238cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams handleStateChangedLocked(); 3243c0dfbab807a459622aeade4940daddf482dec66Jason Sams } 3258cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams } 3263c0dfbab807a459622aeade4940daddf482dec66Jason Sams 327ea84a7c51790f9ba5f2194a66d6cf4ea8d879776Jason Sams public NetworkInfo augmentNetworkInfo(NetworkInfo info) { 3289c9ad3f8c218954e46aab81f9af7834cea5675caStephen Hines if (info.isConnected()) { 329a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams final NetworkInfo vpnInfo = mVpn.getNetworkInfo(); 330a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams info = new NetworkInfo(info); 331a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null); 332a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams } 333a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams return info; 334a1b13ed0912a7e08f9848196b4ca64dcb5db9d0bJason Sams } 3358cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams 3368cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams private void showNotification(int titleRes, int iconRes) { 3378cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams final Notification.Builder builder = new Notification.Builder(mContext) 3383c0dfbab807a459622aeade4940daddf482dec66Jason Sams .setWhen(0) 3398cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams .setSmallIcon(iconRes) 3403c0dfbab807a459622aeade4940daddf482dec66Jason Sams .setContentTitle(mContext.getString(titleRes)) 3413c0dfbab807a459622aeade4940daddf482dec66Jason Sams .setContentText(mContext.getString(R.string.vpn_lockdown_config)) 342e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams .setContentIntent(mConfigIntent) 343e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams .setPriority(Notification.PRIORITY_LOW) 344e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams .setOngoing(true) 345e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset), 346e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams mResetIntent) 347e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams .setColor(mContext.getColor( 348e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams com.android.internal.R.color.system_notification_accent_color)); 349e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams 350e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams NotificationManager.from(mContext).notify(TAG, 0, builder.build()); 351e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams } 352e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams 353e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams private void hideNotification() { 354e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams NotificationManager.from(mContext).cancel(TAG, 0); 355e29f3e74f71ea730519ff8ae1d8dd4c1630bbaf9Jason Sams } 3568cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams} 3578cb39de03aef6097a90033600d11a60ae000a6e4Jason Sams