Loading common/captiveportal/src/android/net/captiveportal/CaptivePortalProbeResult.java +5 −4 Original line number Diff line number Diff line Loading @@ -36,10 +36,11 @@ public final class CaptivePortalProbeResult { */ public static final int PARTIAL_CODE = -1; // DNS response with private IP on the probe URL means the network, especially Wi-Fi network is // not connected to the Internet. This code represents the result of a single probe, for correct // logging of the probe results. The result of the whole evaluation would typically be FAILED if // one of the probes returns this status. // DNS response with private IP on the probe URL suggests that the network, especially Wi-Fi // network is not connected to the Internet. This code represents the result of a single probe, // for correct logging of the probe results. The result of the whole evaluation would typically // be FAILED if one of the probes returns this status. // This logic is only used if the config_force_dns_probe_private_ip_no_internet flag is set. public static final int DNS_PRIVATE_IP_RESPONSE_CODE = -2; @NonNull Loading src/android/net/util/NetworkStackUtils.java +8 −0 Original line number Diff line number Diff line Loading @@ -385,4 +385,12 @@ public class NetworkStackUtils { (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d", address.getHostAddress(), port); } /** * Return true if the provided address is non-null and an IPv6 Unique Local Address (RFC4193). */ public static boolean isIPv6ULA(@Nullable InetAddress addr) { return addr instanceof Inet6Address && ((addr.getAddress()[0] & 0xfe) == 0xfc); } } src/com/android/server/connectivity/NetworkMonitor.java +13 −11 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ import static android.net.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_HTTP_URL import static android.net.util.NetworkStackUtils.DISMISS_PORTAL_IN_VALIDATED_NETWORK; import static android.net.util.NetworkStackUtils.DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION; import static android.net.util.NetworkStackUtils.isEmpty; import static android.net.util.NetworkStackUtils.isIPv6ULA; import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static com.android.networkstack.apishim.ConstantsShim.DETECTION_METHOD_DNS_EVENTS; Loading Loading @@ -427,7 +428,7 @@ public class NetworkMonitor extends StateMachine { private boolean mAcceptPartialConnectivity = false; private final EvaluationState mEvaluationState = new EvaluationState(); private final boolean mPrivateIpNotPortalEnabled; private final boolean mPrivateIpNoInternetEnabled; private int getCallbackVersion(INetworkMonitorCallbacks cb) { int version; Loading Loading @@ -490,7 +491,7 @@ public class NetworkMonitor extends StateMachine { // CHECKSTYLE:ON IndentationCheck mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled(); mPrivateIpNotPortalEnabled = getIsPrivateIpNotPortalEnabled(); mPrivateIpNoInternetEnabled = getIsPrivateIpNoInternetEnabled(); mUseHttps = getUseHttpsValidation(); mCaptivePortalUserAgent = getCaptivePortalUserAgent(); mCaptivePortalHttpsUrls = makeCaptivePortalHttpsUrls(); Loading Loading @@ -1441,7 +1442,7 @@ public class NetworkMonitor extends StateMachine { return mode != CAPTIVE_PORTAL_MODE_IGNORE; } private boolean getIsPrivateIpNotPortalEnabled() { private boolean getIsPrivateIpNoInternetEnabled() { return mDependencies.isFeatureEnabled(mContext, DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION) || mContext.getResources().getBoolean( R.bool.config_force_dns_probe_private_ip_no_internet); Loading Loading @@ -1919,9 +1920,9 @@ public class NetworkMonitor extends StateMachine { // information to callers that does not make sense because the state machine has already // changed state. final InetAddress[] resolvedAddr = sendDnsProbe(host); // The private IP logic only applies to the HTTP probe, not the HTTPS probe (which would // fail anyway) or the PAC probe. if (mPrivateIpNotPortalEnabled && probeType == ValidationProbeEvent.PROBE_HTTP // The private IP logic only applies to captive portal detection (the HTTP probe), not // network validation (the HTTPS probe, which would likely fail anyway) or the PAC probe. if (mPrivateIpNoInternetEnabled && probeType == ValidationProbeEvent.PROBE_HTTP && (proxy == null) && hasPrivateIpAddress(resolvedAddr)) { return CaptivePortalProbeResult.PRIVATE_IP; } Loading Loading @@ -1959,8 +1960,7 @@ public class NetworkMonitor extends StateMachine { } /** * Check if any of the provided IP addresses include a private IP, as defined by * {@link com.android.server.util.NetworkStackConstants#PRIVATE_IPV4_RANGES}. * Check if any of the provided IP addresses include a private IP. * @return true if an IP address is private. */ private static boolean hasPrivateIpAddress(@Nullable InetAddress[] addresses) { Loading @@ -1968,7 +1968,8 @@ public class NetworkMonitor extends StateMachine { return false; } for (InetAddress address : addresses) { if (address.isLinkLocalAddress() || address.isSiteLocalAddress()) { if (address.isLinkLocalAddress() || address.isSiteLocalAddress() || isIPv6ULA(address)) { return true; } } Loading Loading @@ -2343,10 +2344,11 @@ public class NetworkMonitor extends StateMachine { } // Consider a DNS response with a private IP address on the HTTP probe as an indication that // the network is not connected to the Internet, and have the whole evaluation fail in that // case. // case, instead of potentially detecting a captive portal. This logic only affects portal // detection, not network validation. // This only applies if the DNS probe completed within PROBE_TIMEOUT_MS, as the fallback // probe should not be delayed by this check. if (mPrivateIpNotPortalEnabled && (httpResult.isDnsPrivateIpResponse())) { if (mPrivateIpNoInternetEnabled && (httpResult.isDnsPrivateIpResponse())) { validationLog("DNS response to the URL is private IP"); return CaptivePortalProbeResult.FAILED; } Loading tests/unit/src/android/net/util/NetworkStackUtilsTest.java +15 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.net.util; import static android.net.InetAddresses.parseNumericAddress; import static android.net.util.NetworkStackUtils.isIPv6ULA; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; Loading Loading @@ -185,4 +188,15 @@ public class NetworkStackUtilsTest { assertFalse(NetworkStackUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); } @Test public void testIsIPv6ULA() { assertTrue(isIPv6ULA(parseNumericAddress("fc00::"))); assertTrue(isIPv6ULA(parseNumericAddress("fc00::1"))); assertTrue(isIPv6ULA(parseNumericAddress("fc00:1234::5678"))); assertTrue(isIPv6ULA(parseNumericAddress("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); assertFalse(isIPv6ULA(parseNumericAddress("fe00::"))); assertFalse(isIPv6ULA(parseNumericAddress("2480:1248::123:456"))); } } No newline at end of file Loading
common/captiveportal/src/android/net/captiveportal/CaptivePortalProbeResult.java +5 −4 Original line number Diff line number Diff line Loading @@ -36,10 +36,11 @@ public final class CaptivePortalProbeResult { */ public static final int PARTIAL_CODE = -1; // DNS response with private IP on the probe URL means the network, especially Wi-Fi network is // not connected to the Internet. This code represents the result of a single probe, for correct // logging of the probe results. The result of the whole evaluation would typically be FAILED if // one of the probes returns this status. // DNS response with private IP on the probe URL suggests that the network, especially Wi-Fi // network is not connected to the Internet. This code represents the result of a single probe, // for correct logging of the probe results. The result of the whole evaluation would typically // be FAILED if one of the probes returns this status. // This logic is only used if the config_force_dns_probe_private_ip_no_internet flag is set. public static final int DNS_PRIVATE_IP_RESPONSE_CODE = -2; @NonNull Loading
src/android/net/util/NetworkStackUtils.java +8 −0 Original line number Diff line number Diff line Loading @@ -385,4 +385,12 @@ public class NetworkStackUtils { (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d", address.getHostAddress(), port); } /** * Return true if the provided address is non-null and an IPv6 Unique Local Address (RFC4193). */ public static boolean isIPv6ULA(@Nullable InetAddress addr) { return addr instanceof Inet6Address && ((addr.getAddress()[0] & 0xfe) == 0xfc); } }
src/com/android/server/connectivity/NetworkMonitor.java +13 −11 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ import static android.net.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_HTTP_URL import static android.net.util.NetworkStackUtils.DISMISS_PORTAL_IN_VALIDATED_NETWORK; import static android.net.util.NetworkStackUtils.DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION; import static android.net.util.NetworkStackUtils.isEmpty; import static android.net.util.NetworkStackUtils.isIPv6ULA; import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static com.android.networkstack.apishim.ConstantsShim.DETECTION_METHOD_DNS_EVENTS; Loading Loading @@ -427,7 +428,7 @@ public class NetworkMonitor extends StateMachine { private boolean mAcceptPartialConnectivity = false; private final EvaluationState mEvaluationState = new EvaluationState(); private final boolean mPrivateIpNotPortalEnabled; private final boolean mPrivateIpNoInternetEnabled; private int getCallbackVersion(INetworkMonitorCallbacks cb) { int version; Loading Loading @@ -490,7 +491,7 @@ public class NetworkMonitor extends StateMachine { // CHECKSTYLE:ON IndentationCheck mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled(); mPrivateIpNotPortalEnabled = getIsPrivateIpNotPortalEnabled(); mPrivateIpNoInternetEnabled = getIsPrivateIpNoInternetEnabled(); mUseHttps = getUseHttpsValidation(); mCaptivePortalUserAgent = getCaptivePortalUserAgent(); mCaptivePortalHttpsUrls = makeCaptivePortalHttpsUrls(); Loading Loading @@ -1441,7 +1442,7 @@ public class NetworkMonitor extends StateMachine { return mode != CAPTIVE_PORTAL_MODE_IGNORE; } private boolean getIsPrivateIpNotPortalEnabled() { private boolean getIsPrivateIpNoInternetEnabled() { return mDependencies.isFeatureEnabled(mContext, DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION) || mContext.getResources().getBoolean( R.bool.config_force_dns_probe_private_ip_no_internet); Loading Loading @@ -1919,9 +1920,9 @@ public class NetworkMonitor extends StateMachine { // information to callers that does not make sense because the state machine has already // changed state. final InetAddress[] resolvedAddr = sendDnsProbe(host); // The private IP logic only applies to the HTTP probe, not the HTTPS probe (which would // fail anyway) or the PAC probe. if (mPrivateIpNotPortalEnabled && probeType == ValidationProbeEvent.PROBE_HTTP // The private IP logic only applies to captive portal detection (the HTTP probe), not // network validation (the HTTPS probe, which would likely fail anyway) or the PAC probe. if (mPrivateIpNoInternetEnabled && probeType == ValidationProbeEvent.PROBE_HTTP && (proxy == null) && hasPrivateIpAddress(resolvedAddr)) { return CaptivePortalProbeResult.PRIVATE_IP; } Loading Loading @@ -1959,8 +1960,7 @@ public class NetworkMonitor extends StateMachine { } /** * Check if any of the provided IP addresses include a private IP, as defined by * {@link com.android.server.util.NetworkStackConstants#PRIVATE_IPV4_RANGES}. * Check if any of the provided IP addresses include a private IP. * @return true if an IP address is private. */ private static boolean hasPrivateIpAddress(@Nullable InetAddress[] addresses) { Loading @@ -1968,7 +1968,8 @@ public class NetworkMonitor extends StateMachine { return false; } for (InetAddress address : addresses) { if (address.isLinkLocalAddress() || address.isSiteLocalAddress()) { if (address.isLinkLocalAddress() || address.isSiteLocalAddress() || isIPv6ULA(address)) { return true; } } Loading Loading @@ -2343,10 +2344,11 @@ public class NetworkMonitor extends StateMachine { } // Consider a DNS response with a private IP address on the HTTP probe as an indication that // the network is not connected to the Internet, and have the whole evaluation fail in that // case. // case, instead of potentially detecting a captive portal. This logic only affects portal // detection, not network validation. // This only applies if the DNS probe completed within PROBE_TIMEOUT_MS, as the fallback // probe should not be delayed by this check. if (mPrivateIpNotPortalEnabled && (httpResult.isDnsPrivateIpResponse())) { if (mPrivateIpNoInternetEnabled && (httpResult.isDnsPrivateIpResponse())) { validationLog("DNS response to the URL is private IP"); return CaptivePortalProbeResult.FAILED; } Loading
tests/unit/src/android/net/util/NetworkStackUtilsTest.java +15 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.net.util; import static android.net.InetAddresses.parseNumericAddress; import static android.net.util.NetworkStackUtils.isIPv6ULA; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; Loading Loading @@ -185,4 +188,15 @@ public class NetworkStackUtilsTest { assertFalse(NetworkStackUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); } @Test public void testIsIPv6ULA() { assertTrue(isIPv6ULA(parseNumericAddress("fc00::"))); assertTrue(isIPv6ULA(parseNumericAddress("fc00::1"))); assertTrue(isIPv6ULA(parseNumericAddress("fc00:1234::5678"))); assertTrue(isIPv6ULA(parseNumericAddress("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); assertFalse(isIPv6ULA(parseNumericAddress("fe00::"))); assertFalse(isIPv6ULA(parseNumericAddress("2480:1248::123:456"))); } } No newline at end of file