169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey/* 269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * Copyright (C) 2012 The Android Open Source Project 369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * 469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * you may not use this file except in compliance with the License. 669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * You may obtain a copy of the License at 769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * 869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * 1069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 1169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 1269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * See the License for the specific language governing permissions and 1469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * limitations under the License. 1569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey */ 1669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 1769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeypackage com.android.server.net; 1869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 1969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport static android.Manifest.permission.CONNECTIVITY_INTERNAL; 2069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 2169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.app.Notification; 2269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.app.NotificationManager; 2369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.app.PendingIntent; 2469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.content.BroadcastReceiver; 2569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.content.Context; 2669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.content.Intent; 2769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.content.IntentFilter; 2869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.net.LinkProperties; 294ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubakerimport android.net.LinkAddress; 3069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.net.NetworkInfo; 3169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.net.NetworkInfo.DetailedState; 3269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.net.NetworkInfo.State; 3369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.os.INetworkManagementService; 3469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.os.RemoteException; 3569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.security.Credentials; 3669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.security.KeyStore; 3769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.text.TextUtils; 3869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.util.Slog; 3969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 4069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport com.android.internal.R; 4169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport com.android.internal.net.VpnConfig; 4269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport com.android.internal.net.VpnProfile; 4369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport com.android.internal.util.Preconditions; 4469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport com.android.server.ConnectivityService; 4591c6a64a04c2d8b27b886d96a56800ae24efb7a9Jeff Sharkeyimport com.android.server.EventLogTags; 4669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport com.android.server.connectivity.Vpn; 4769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 484ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubakerimport java.util.List; 494ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 5069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey/** 5169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * State tracker for lockdown mode. Watches for normal {@link NetworkInfo} to be 5269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * connected and kicks off VPN connection, managing any required {@code netd} 5369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * firewall rules. 5469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey */ 5569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeypublic class LockdownVpnTracker { 5669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private static final String TAG = "LockdownVpnTracker"; 5769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 5869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey /** Number of VPN attempts before waiting for user intervention. */ 5969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private static final int MAX_ERROR_COUNT = 4; 6069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 6169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET"; 624fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey 63580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS"; 644fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN"; 6569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 6669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private final Context mContext; 6769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private final INetworkManagementService mNetService; 6869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private final ConnectivityService mConnService; 6969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private final Vpn mVpn; 7069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private final VpnProfile mProfile; 7169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 7269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private final Object mStateLock = new Object(); 7369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 744fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey private final PendingIntent mConfigIntent; 754fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey private final PendingIntent mResetIntent; 7669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 7769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private String mAcceptedEgressIface; 7869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private String mAcceptedIface; 794ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker private List<LinkAddress> mAcceptedSourceAddr; 8069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 8169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private int mErrorCount; 8269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 8369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public static boolean isEnabled() { 8469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN); 8569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 8669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 8769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public LockdownVpnTracker(Context context, INetworkManagementService netService, 8869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey ConnectivityService connService, Vpn vpn, VpnProfile profile) { 8969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mContext = Preconditions.checkNotNull(context); 9069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mNetService = Preconditions.checkNotNull(netService); 9169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mConnService = Preconditions.checkNotNull(connService); 9269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mVpn = Preconditions.checkNotNull(vpn); 9369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mProfile = Preconditions.checkNotNull(profile); 9469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 954fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey final Intent configIntent = new Intent(ACTION_VPN_SETTINGS); 964fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey configIntent.putExtra(EXTRA_PICK_LOCKDOWN, true); 974fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey mConfigIntent = PendingIntent.getActivity(mContext, 0, configIntent, 0); 984fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey 99580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey final Intent resetIntent = new Intent(ACTION_LOCKDOWN_RESET); 100580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey resetIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 101580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey mResetIntent = PendingIntent.getBroadcast(mContext, 0, resetIntent, 0); 10269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 10369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 10469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private BroadcastReceiver mResetReceiver = new BroadcastReceiver() { 10569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey @Override 10669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public void onReceive(Context context, Intent intent) { 10769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey reset(); 10869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 10969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey }; 11069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 11169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey /** 11269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * Watch for state changes to both active egress network, kicking off a VPN 11369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * connection when ready, or setting firewall rules once VPN is connected. 11469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey */ 11569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private void handleStateChangedLocked() { 11669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey Slog.d(TAG, "handleStateChanged()"); 11769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 11869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final NetworkInfo egressInfo = mConnService.getActiveNetworkInfoUnfiltered(); 11969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final LinkProperties egressProp = mConnService.getActiveLinkProperties(); 12069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 12169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final NetworkInfo vpnInfo = mVpn.getNetworkInfo(); 12269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final VpnConfig vpnConfig = mVpn.getLegacyVpnConfig(); 12369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 12469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey // Restart VPN when egress network disconnected or changed 12569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final boolean egressDisconnected = egressInfo == null 12669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey || State.DISCONNECTED.equals(egressInfo.getState()); 12769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final boolean egressChanged = egressProp == null 12869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey || !TextUtils.equals(mAcceptedEgressIface, egressProp.getInterfaceName()); 12969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (egressDisconnected || egressChanged) { 130580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey clearSourceRulesLocked(); 13169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mAcceptedEgressIface = null; 13269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mVpn.stopLegacyVpn(); 13369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 13457666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey if (egressDisconnected) { 13557666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey hideNotification(); 13657666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey return; 13757666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey } 13869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 13991c6a64a04c2d8b27b886d96a56800ae24efb7a9Jeff Sharkey final int egressType = egressInfo.getType(); 14091c6a64a04c2d8b27b886d96a56800ae24efb7a9Jeff Sharkey if (vpnInfo.getDetailedState() == DetailedState.FAILED) { 14191c6a64a04c2d8b27b886d96a56800ae24efb7a9Jeff Sharkey EventLogTags.writeLockdownVpnError(egressType); 14291c6a64a04c2d8b27b886d96a56800ae24efb7a9Jeff Sharkey } 14391c6a64a04c2d8b27b886d96a56800ae24efb7a9Jeff Sharkey 14469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (mErrorCount > MAX_ERROR_COUNT) { 14569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected); 14669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 14769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } else if (egressInfo.isConnected() && !vpnInfo.isConnectedOrConnecting()) { 14869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (mProfile.isValidLockdownProfile()) { 14969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey Slog.d(TAG, "Active network connected; starting VPN"); 15091c6a64a04c2d8b27b886d96a56800ae24efb7a9Jeff Sharkey EventLogTags.writeLockdownVpnConnecting(egressType); 15169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected); 15269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 15369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mAcceptedEgressIface = egressProp.getInterfaceName(); 154421fab8a7b429073512967e54a469ce440772e15Jeff Sharkey try { 155421fab8a7b429073512967e54a469ce440772e15Jeff Sharkey mVpn.startLegacyVpn(mProfile, KeyStore.getInstance(), egressProp); 156421fab8a7b429073512967e54a469ce440772e15Jeff Sharkey } catch (IllegalStateException e) { 157421fab8a7b429073512967e54a469ce440772e15Jeff Sharkey mAcceptedEgressIface = null; 158421fab8a7b429073512967e54a469ce440772e15Jeff Sharkey Slog.e(TAG, "Failed to start VPN", e); 159421fab8a7b429073512967e54a469ce440772e15Jeff Sharkey showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected); 160421fab8a7b429073512967e54a469ce440772e15Jeff Sharkey } 16169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } else { 16269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey Slog.e(TAG, "Invalid VPN profile; requires IP-based server and DNS"); 16369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected); 16469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 16569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 16669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } else if (vpnInfo.isConnected() && vpnConfig != null) { 16769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final String iface = vpnConfig.interfaze; 1684ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker final List<LinkAddress> sourceAddrs = vpnConfig.addresses; 16969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 17069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (TextUtils.equals(iface, mAcceptedIface) 1714ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker && sourceAddrs.equals(mAcceptedSourceAddr)) { 17269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return; 17369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 17469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 1754ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker Slog.d(TAG, "VPN connected using iface=" + iface + 1764ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker ", sourceAddr=" + sourceAddrs.toString()); 17791c6a64a04c2d8b27b886d96a56800ae24efb7a9Jeff Sharkey EventLogTags.writeLockdownVpnConnected(egressType); 17869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected); 17969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 18069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey try { 181580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey clearSourceRulesLocked(); 18269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 18369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mNetService.setFirewallInterfaceRule(iface, true); 1844ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker for (LinkAddress addr : sourceAddrs) { 1854ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mNetService.setFirewallEgressSourceRule(addr.toString(), true); 1864ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 18769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 18869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mErrorCount = 0; 18969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mAcceptedIface = iface; 1904ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mAcceptedSourceAddr = sourceAddrs; 19169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } catch (RemoteException e) { 19269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey throw new RuntimeException("Problem setting firewall rules", e); 19369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 19469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 19569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mConnService.sendConnectedBroadcast(augmentNetworkInfo(egressInfo)); 19669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 19769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 19869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 19969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public void init() { 200580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey synchronized (mStateLock) { 201580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey initLocked(); 202580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey } 203580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey } 204580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey 205580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey private void initLocked() { 206580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey Slog.d(TAG, "initLocked()"); 20769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 20869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mVpn.setEnableNotifications(false); 20957666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey mVpn.setEnableTeardown(false); 21069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 21169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET); 21269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mContext.registerReceiver(mResetReceiver, resetFilter, CONNECTIVITY_INTERNAL, null); 21369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 21469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey try { 21569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey // TODO: support non-standard port numbers 21669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mNetService.setFirewallEgressDestRule(mProfile.server, 500, true); 21769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mNetService.setFirewallEgressDestRule(mProfile.server, 4500, true); 21842c0c9f35a8efa71703f810ce2bff6d86bb5b30eJeff Sharkey mNetService.setFirewallEgressDestRule(mProfile.server, 1701, true); 21969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } catch (RemoteException e) { 22069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey throw new RuntimeException("Problem setting firewall rules", e); 22169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 22269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 22369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey synchronized (mStateLock) { 22469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey handleStateChangedLocked(); 22569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 22669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 22769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 22869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public void shutdown() { 229580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey synchronized (mStateLock) { 230580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey shutdownLocked(); 231580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey } 232580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey } 233580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey 234580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey private void shutdownLocked() { 235580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey Slog.d(TAG, "shutdownLocked()"); 23669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 23769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mAcceptedEgressIface = null; 23869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mErrorCount = 0; 23969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 24069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mVpn.stopLegacyVpn(); 24169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey try { 24269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mNetService.setFirewallEgressDestRule(mProfile.server, 500, false); 24369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mNetService.setFirewallEgressDestRule(mProfile.server, 4500, false); 24442c0c9f35a8efa71703f810ce2bff6d86bb5b30eJeff Sharkey mNetService.setFirewallEgressDestRule(mProfile.server, 1701, false); 24569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } catch (RemoteException e) { 24669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey throw new RuntimeException("Problem setting firewall rules", e); 24769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 248580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey clearSourceRulesLocked(); 24969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey hideNotification(); 25069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 25169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mContext.unregisterReceiver(mResetReceiver); 25269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mVpn.setEnableNotifications(true); 25357666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey mVpn.setEnableTeardown(true); 25469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 25569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 25669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public void reset() { 25769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey synchronized (mStateLock) { 258580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey // cycle tracker, reset error count, and trigger retry 259580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey shutdownLocked(); 260580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey initLocked(); 26169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey handleStateChangedLocked(); 26269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 26369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 26469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 265580dd31a68c65b4af68147d52d57f60e0bd52dbeJeff Sharkey private void clearSourceRulesLocked() { 26669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey try { 26769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (mAcceptedIface != null) { 26869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mNetService.setFirewallInterfaceRule(mAcceptedIface, false); 26969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mAcceptedIface = null; 27069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 27169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (mAcceptedSourceAddr != null) { 2724ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker for (LinkAddress addr : mAcceptedSourceAddr) { 2734ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mNetService.setFirewallEgressSourceRule(addr.toString(), false); 2744ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 27569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mAcceptedSourceAddr = null; 27669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 27769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } catch (RemoteException e) { 27869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey throw new RuntimeException("Problem setting firewall rules", e); 27969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 28069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 28169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 28269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public void onNetworkInfoChanged(NetworkInfo info) { 28369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey synchronized (mStateLock) { 28469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey handleStateChangedLocked(); 28569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 28669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 28769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 28869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public void onVpnStateChanged(NetworkInfo info) { 28969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (info.getDetailedState() == DetailedState.FAILED) { 29069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey mErrorCount++; 29169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 29269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey synchronized (mStateLock) { 29369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey handleStateChangedLocked(); 29469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 29569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 29669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 29769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public NetworkInfo augmentNetworkInfo(NetworkInfo info) { 2980b81be6f79ec3d1b9441c21a3cefc629be1450c8Jeff Sharkey if (info.isConnected()) { 2990b81be6f79ec3d1b9441c21a3cefc629be1450c8Jeff Sharkey final NetworkInfo vpnInfo = mVpn.getNetworkInfo(); 3000b81be6f79ec3d1b9441c21a3cefc629be1450c8Jeff Sharkey info = new NetworkInfo(info); 3010b81be6f79ec3d1b9441c21a3cefc629be1450c8Jeff Sharkey info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null); 3020b81be6f79ec3d1b9441c21a3cefc629be1450c8Jeff Sharkey } 30369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return info; 30469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 30569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 30669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private void showNotification(int titleRes, int iconRes) { 30769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey final Notification.Builder builder = new Notification.Builder(mContext); 30869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey builder.setWhen(0); 30969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey builder.setSmallIcon(iconRes); 31069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey builder.setContentTitle(mContext.getString(titleRes)); 3114fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey builder.setContentText(mContext.getString(R.string.vpn_lockdown_config)); 3124fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey builder.setContentIntent(mConfigIntent); 31369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey builder.setPriority(Notification.PRIORITY_LOW); 31469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey builder.setOngoing(true); 3154fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey builder.addAction( 3164fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey R.drawable.ic_menu_refresh, mContext.getString(R.string.reset), mResetIntent); 3174fa63b2d5e3b2e2a85bf17a9bf056cbdfb7046f0Jeff Sharkey 31869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey NotificationManager.from(mContext).notify(TAG, 0, builder.build()); 31969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 32069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 32169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private void hideNotification() { 32269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey NotificationManager.from(mContext).cancel(TAG, 0); 32369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 32469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey} 325