From 2d3f03d7fb5d955cd16d4152c8767c7974ebb54e Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 7 Feb 2014 03:52:12 -0800 Subject: [PATCH 1/8] DO NOT MERGE Sanitize WifiConfigs Do this both on input from apps (giving error) and between wifi and ConnectivityService (ignoring bad data). This means removing all addresses beyond the first and all routes but the first default and the implied direct-connect routes. We do this because the user can't monitor the others (no UI), their support wasn't intended, they allow redirection of all traffic without user knowledge and they allow circumvention of legacy VPNs. This should not move forward from JB as it breaks IPv6 and K has a more resilient VPN. Bug:12663469 Change-Id: I0d92db7efc30a1bb3e5b8c6e5595bdb9793a16f2 Conflicts: core/java/android/net/LinkProperties.java services/java/com/android/server/WifiService.java wifi/java/android/net/wifi/WifiStateMachine.java --- core/java/android/net/LinkProperties.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 75f8b5948b..dc9a54f8ea 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -144,6 +144,16 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(mLinkAddresses); } + /** + * Replaces the LinkAddresses on this link with the given collection of addresses + */ + public void setLinkAddresses(Collection addresses) { + mLinkAddresses.clear(); + for (LinkAddress address: addresses) { + addLinkAddress(address); + } + } + public void addDns(InetAddress dns) { if (dns != null) mDnses.add(dns); } @@ -198,6 +208,16 @@ public class LinkProperties implements Parcelable { return routes; } + /** + * Replaces the RouteInfos on this link with the given collection of RouteInfos. + */ + public void setRoutes(Collection routes) { + mRoutes.clear(); + for (RouteInfo route : routes) { + addRoute(route); + } + } + public void setHttpProxy(ProxyProperties proxy) { mHttpProxy = proxy; } From eace8d566943ab09527ee6a2bfd2e31c60840403 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 28 Feb 2014 16:44:00 -0800 Subject: [PATCH 2/8] Only apply tcp buffer sizes for default net This may mean that secondary networks have bad network settings, but currently default settings are overriden by secondary nets which seems worse. bug:13211589 Change-Id: I08d56e618208781bf6b21a88663c2b8503a4f226 --- services/java/com/android/server/ConnectivityService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index baff661170..2d0c2856f8 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2305,9 +2305,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mInetConditionChangeInFlight = false; // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); + updateNetworkSettings(thisNet); } thisNet.setTeardownRequested(false); - updateNetworkSettings(thisNet); updateMtuSizeSettings(thisNet); handleConnectivityChange(newNetType, false); sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); @@ -3034,7 +3034,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { info = (NetworkInfo) msg.obj; int type = info.getType(); - updateNetworkSettings(mNetTrackers[type]); + if (mNetConfigs[type].isDefault()) updateNetworkSettings(mNetTrackers[type]); break; } } From edf0ac7298f0c765bfdf4e57eaf66bcf70540ae7 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 14 Feb 2014 13:22:34 -0800 Subject: [PATCH 3/8] Add the calling package name to requestRouteToHost The calling package name will be used to check if an application is a system application when deciding if a route should be exempt from VPN routing rules. Bug: 12937545 Change-Id: I2c09c875fe9bb9685871a0a801ddcbb32fc17405 --- core/java/android/net/ConnectivityManager.java | 7 +++++-- core/java/android/net/IConnectivityManager.aidl | 4 ++-- .../java/com/android/server/ConnectivityService.java | 9 +++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index c78a973cee..70c8750623 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -395,6 +395,8 @@ public class ConnectivityManager { private final IConnectivityManager mService; + private final String mPackageName; + /** * Tests if a given integer represents a valid network type. * @param networkType the type to be tested @@ -802,7 +804,7 @@ public class ConnectivityManager { public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { byte[] address = hostAddress.getAddress(); try { - return mService.requestRouteToHostAddress(networkType, address); + return mService.requestRouteToHostAddress(networkType, address, mPackageName); } catch (RemoteException e) { return false; } @@ -898,8 +900,9 @@ public class ConnectivityManager { /** * {@hide} */ - public ConnectivityManager(IConnectivityManager service) { + public ConnectivityManager(IConnectivityManager service, String packageName) { mService = checkNotNull(service, "missing IConnectivityManager"); + mPackageName = checkNotNull(packageName, "missing package name"); } /** {@hide} */ diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index c1da2e32aa..4bca7fefbc 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -71,9 +71,9 @@ interface IConnectivityManager int stopUsingNetworkFeature(int networkType, in String feature); - boolean requestRouteToHost(int networkType, int hostAddress); + boolean requestRouteToHost(int networkType, int hostAddress, String packageName); - boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); + boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName); boolean getMobileDataEnabled(); void setMobileDataEnabled(boolean enabled); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 2d0c2856f8..af6433a75b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1537,14 +1537,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { * desired * @return {@code true} on success, {@code false} on failure */ - public boolean requestRouteToHost(int networkType, int hostAddress) { + public boolean requestRouteToHost(int networkType, int hostAddress, String packageName) { InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); if (inetAddress == null) { return false; } - return requestRouteToHostAddress(networkType, inetAddress.getAddress()); + return requestRouteToHostAddress(networkType, inetAddress.getAddress(), packageName); } /** @@ -1556,7 +1556,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { * desired * @return {@code true} on success, {@code false} on failure */ - public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) { + public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress, + String packageName) { enforceChangePermission(); if (mProtectedNetworks.contains(networkType)) { enforceConnectivityInternalPermission(); @@ -4351,7 +4352,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Make a route to host so we check the specific interface. if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI, - hostAddr.getAddress())) { + hostAddr.getAddress(), null)) { // Wait a short time to be sure the route is established ?? log("isMobileOk:" + " wait to establish route to hostAddr=" + hostAddr); From 342cd4d21482897f7f28580c191d48385497fc2f Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 14 Feb 2014 13:24:29 -0800 Subject: [PATCH 4/8] Only allow System apps to make VPN exempt routes requestRouteToHost will only allow system applications to make routes exempt from the VPN's routing rules. If a VPN is currently running and a non-system app requests a route it will only succeed if that host is currently covered by a VPN exempt routing rule. Otherwise it will fail. For example, if a VPN is running and the MMS network is brought online those routes will be added as VPN exempt. If an application then tries to request a route to a MMS endpoint it will succeed because the routes already exist. If an application tries to request a route to a host covered by the VPN the call will fail. Bug: 12937545 Change-Id: If7bcec91bbb96c62c8fb69748c975847e6c00b6f --- .../android/server/ConnectivityService.java | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index af6433a75b..83a3bfd05f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -32,6 +32,7 @@ import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import android.app.AlarmManager; +import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -43,7 +44,9 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; @@ -412,6 +415,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private SettingsObserver mSettingsObserver; + private AppOpsManager mAppOpsManager; + NetworkConfig[] mNetConfigs; int mNetworksDefined; @@ -695,6 +700,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { filter = new IntentFilter(); filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); mContext.registerReceiver(mProvisioningReceiver, filter); + + mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); } /** @@ -1526,6 +1533,40 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * Check if the address falls into any of currently running VPN's route's. + */ + private boolean isAddressUnderVpn(InetAddress address) { + synchronized (mVpns) { + synchronized (mRoutesLock) { + int uid = UserHandle.getCallingUserId(); + Vpn vpn = mVpns.get(uid); + if (vpn == null) { + return false; + } + + // Check if an exemption exists for this address. + for (LinkAddress destination : mExemptAddresses) { + if (!NetworkUtils.addressTypeMatches(address, destination.getAddress())) { + continue; + } + + int prefix = destination.getNetworkPrefixLength(); + InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix); + InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(), + prefix); + + if (addrMasked.equals(destMasked)) { + return false; + } + } + + // Finally check if the address is covered by the VPN. + return vpn.isAddressCovered(address); + } + } + } + /** * @deprecated use requestRouteToHostAddress instead * @@ -1562,6 +1603,34 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mProtectedNetworks.contains(networkType)) { enforceConnectivityInternalPermission(); } + boolean exempt; + InetAddress addr; + try { + addr = InetAddress.getByAddress(hostAddress); + } catch (UnknownHostException e) { + if (DBG) log("requestRouteToHostAddress got " + e.toString()); + return false; + } + // System apps may request routes bypassing the VPN to keep other networks working. + if (Binder.getCallingUid() == Process.SYSTEM_UID) { + exempt = true; + } else { + mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); + try { + ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName, + 0); + exempt = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } catch (NameNotFoundException e) { + throw new IllegalArgumentException("Failed to find calling package details", e); + } + } + + // Non-exempt routeToHost's can only be added if the host is not covered by the VPN. + // This can be either because the VPN's routes do not cover the destination or a + // system application added an exemption that covers this destination. + if (!exempt && isAddressUnderVpn(addr)) { + return false; + } if (!ConnectivityManager.isNetworkTypeValid(networkType)) { if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType); @@ -1585,18 +1654,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } final long token = Binder.clearCallingIdentity(); try { - InetAddress addr = InetAddress.getByAddress(hostAddress); LinkProperties lp = tracker.getLinkProperties(); - boolean ok = addRouteToAddress(lp, addr, EXEMPT); + boolean ok = addRouteToAddress(lp, addr, exempt); if (DBG) log("requestRouteToHostAddress ok=" + ok); return ok; - } catch (UnknownHostException e) { - if (DBG) log("requestRouteToHostAddress got " + e.toString()); } finally { Binder.restoreCallingIdentity(token); } - if (DBG) log("requestRouteToHostAddress X bottom return false"); - return false; } private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, From 41236f1dff1f79651b3f77058d74625b96f1d107 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 11 Feb 2014 14:18:56 -0800 Subject: [PATCH 5/8] Remove SO_BINDTODEVICE from VPN protect SO_BINDTODEVICE is not needed with policy routing. SO_BINDTODEVICE was also used on the default iface which causes problems when the default iface is IPv6 only and the socket tries to connect to a IPv4 address. Bug: 12940882 Change-Id: I5b2bde0ac5459433fc5749f509072a548532f730 --- services/java/com/android/server/ConnectivityService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 83a3bfd05f..df2fd5ef65 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3658,8 +3658,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int user = UserHandle.getUserId(Binder.getCallingUid()); if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) { synchronized(mVpns) { - mVpns.get(user).protect(socket, - mNetTrackers[type].getLinkProperties().getInterfaceName()); + mVpns.get(user).protect(socket); } return true; } From af3781c98312d561ecdbf8ec54803c570462fdf2 Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Fri, 21 Feb 2014 12:05:20 -0800 Subject: [PATCH 6/8] ConnectivityService: add support to set TCP initial rwnd The value for the TCP initial receive window comes from, in order, kernel /proc/sys/net/ipv4/tcp_default_init_rwnd init.rc (via properties) net.tcp.default_init_rwnd properties net.tcp.default_init_rwnd gservices Settings.Global.TCP_DEFAULT_INIT_RWND Bug: 12020135 Change-Id: I0e271be19472900fa9f3bab037d53383ec014a9e --- .../java/com/android/server/ConnectivityService.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 83a3bfd05f..6a28fd67bb 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2757,6 +2757,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { } setBufferSize(bufferSizes); } + + final String defaultRwndKey = "net.tcp.default_init_rwnd"; + int defaultRwndValue = SystemProperties.getInt(defaultRwndKey, 0); + Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.TCP_DEFAULT_INIT_RWND, defaultRwndValue); + final String sysctlKey = "sys.sysctl.tcp_def_init_rwnd"; + if (rwndValue != 0) { + SystemProperties.set(sysctlKey, rwndValue.toString()); + } } /** From 11ca0a104d1a256dfd6378195dca59697db1f377 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Thu, 20 Feb 2014 14:46:33 -0800 Subject: [PATCH 7/8] Include the interface for clearDnsInterfaceForUidRange With netd allowing overlapping rules for uid range rules the interface name is needed to make sure only the correct rule is removed. Bug: 12134439 Change-Id: I94f77f154f49ca8d5f6cf49683a4473cc92c3eb7 --- services/java/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index df2fd5ef65..5c7951a55d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3898,7 +3898,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean forwardDns) { try { mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd); - if (forwardDns) mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd); + if (forwardDns) mNetd.clearDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); } catch (RemoteException e) { } From 98fee2c93b7c721f2aa5c12093b4efe2ead35811 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 13 Mar 2014 06:54:59 -0700 Subject: [PATCH 8/8] Handle provisioning APN by turning off/on data. This is a start and two tests succeed: Tested expired AT&T SIM and waiting 15min for alarm to fire. Tested a provisioned Verizon SIM and works normally. I've NOT tested AT&T where I've properly completed the provisioning. I've NOT tested T-Mobile SIM either provisioned or not-provisioned. I've NOT tested provisioning over WiFi. I've NOT tested that WiFi <-> Mobile works I've NOT tested voice calls, SMS, MMS ... The current bug is below, but it is poorly named either it should be renamed or a new bug created. Bug: 13190133 Change-Id: I0a09f642614cd27a8655e9dae764b8999ce485b8 --- .../android/server/ConnectivityService.java | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 594f6831be..47b8b518c6 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3975,6 +3975,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + /** + * The mobile network is provisioning + */ + private static final int CMP_RESULT_CODE_IS_PROVISIONING = 6; + + private AtomicBoolean mIsProvisioningNetwork = new AtomicBoolean(false); + private AtomicBoolean mIsStartingProvisioning = new AtomicBoolean(false); + private AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); @Override @@ -4045,11 +4053,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { setProvNotificationVisible(true, ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(), url); + // Mark that we've got a provisioning network and + // Disable Mobile Data until user actually starts provisioning. + mIsProvisioningNetwork.set(true); + MobileDataStateTracker mdst = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.setInternalDataEnable(false); } else { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); } break; } + case CMP_RESULT_CODE_IS_PROVISIONING: { + // FIXME: Need to know when provisioning is done. Probably we can + // check the completion status if successful we're done if we + // "timedout" or still connected to provisioning APN turn off data? + if (DBG) log("CheckMp.onComplete: provisioning started"); + mIsStartingProvisioning.set(false); + break; + } default: { loge("CheckMp.onComplete: ignore unexpected result=" + result); break; @@ -4199,6 +4221,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { return result; } + if (mCs.mIsStartingProvisioning.get()) { + result = CMP_RESULT_CODE_IS_PROVISIONING; + log("isMobileOk: X is provisioning result=" + result); + return result; + } + // See if we've already determined we've got a provisioning connection, // if so we don't need to do anything active. MobileDataStateTracker mdstDefault = (MobileDataStateTracker) @@ -4533,19 +4561,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; private void handleMobileProvisioningAction(String url) { - // Notication mark notification as not visible + // Mark notification as not visible setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); // If provisioning network handle as a special case, // otherwise launch browser with the intent directly. - NetworkInfo ni = getProvisioningNetworkInfo(); - if ((ni != null) && ni.isConnectedToProvisioningNetwork()) { - if (DBG) log("handleMobileProvisioningAction: on provisioning network"); + if (mIsProvisioningNetwork.get()) { + if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch"); + mIsStartingProvisioning.set(true); MobileDataStateTracker mdst = (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.setEnableFailFastMobileData(DctConstants.ENABLED); mdst.enableMobileProvisioning(url); } else { - if (DBG) log("handleMobileProvisioningAction: on default network"); + if (DBG) log("handleMobileProvisioningAction: not prov network, launch browser directly"); Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_BROWSER); newIntent.setData(Uri.parse(url));