From 143e89c2f19be3c06a6e87cb66d5e8597799eb24 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Mon, 20 Oct 2014 19:46:56 +0900 Subject: [PATCH] Treat optimistic addresses as global preferred. If the kernel sends notification of an optimistic address then treat is a useable address (isGlobalPreferred()). Note that addresses flagged as IFA_F_OPTIMISTIC are simultaneously flagged as IFA_F_TENTATIVE (when the tentative state has cleared either DAD has succeeded or failed, and both flags are cleared regardless). Additionally: do not consider RFC 4193 ULA addresses sufficient for "global preffered". They are, by definition, of global scope but not sufficient for global reachability. Bug: 17769720 Change-Id: I759623b28fd52758f2d4d76d167f3cafd9319d6a --- core/java/android/net/LinkAddress.java | 26 ++++++- .../src/android/net/LinkAddressTest.java | 72 +++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index c387055741..384ab1c8f5 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -21,12 +21,14 @@ import android.os.Parcelable; import android.util.Pair; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.UnknownHostException; import static android.system.OsConstants.IFA_F_DADFAILED; import static android.system.OsConstants.IFA_F_DEPRECATED; +import static android.system.OsConstants.IFA_F_OPTIMISTIC; import static android.system.OsConstants.IFA_F_TENTATIVE; import static android.system.OsConstants.RT_SCOPE_HOST; import static android.system.OsConstants.RT_SCOPE_LINK; @@ -92,6 +94,20 @@ public class LinkAddress implements Parcelable { return RT_SCOPE_UNIVERSE; } + /** + * Utility function to check if |address| is a Unique Local IPv6 Unicast Address + * (a.k.a. "ULA"; RFC 4193). + * + * Per RFC 4193 section 8, fc00::/7 identifies these addresses. + */ + private boolean isIPv6ULA() { + if (address != null && address instanceof Inet6Address) { + byte[] bytes = address.getAddress(); + return ((bytes[0] & (byte)0xfc) == (byte)0xfc); + } + return false; + } + /** * Utility function for the constructors. */ @@ -268,8 +284,16 @@ public class LinkAddress implements Parcelable { * @hide */ public boolean isGlobalPreferred() { + /** + * Note that addresses flagged as IFA_F_OPTIMISTIC are + * simultaneously flagged as IFA_F_TENTATIVE (when the tentative + * state has cleared either DAD has succeeded or failed, and both + * flags are cleared regardless). + */ return (scope == RT_SCOPE_UNIVERSE && - (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0L); + !isIPv6ULA() && + (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L && + ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L)); } /** diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java index 7bc39744d3..adf8d95c0b 100644 --- a/core/tests/coretests/src/android/net/LinkAddressTest.java +++ b/core/tests/coretests/src/android/net/LinkAddressTest.java @@ -33,8 +33,11 @@ import android.test.AndroidTestCase; import static android.test.MoreAsserts.assertNotEqual; import android.test.suitebuilder.annotation.SmallTest; +import static android.system.OsConstants.IFA_F_DADFAILED; import static android.system.OsConstants.IFA_F_DEPRECATED; +import static android.system.OsConstants.IFA_F_OPTIMISTIC; import static android.system.OsConstants.IFA_F_PERMANENT; +import static android.system.OsConstants.IFA_F_TEMPORARY; import static android.system.OsConstants.IFA_F_TENTATIVE; import static android.system.OsConstants.RT_SCOPE_HOST; import static android.system.OsConstants.RT_SCOPE_LINK; @@ -340,4 +343,73 @@ public class LinkAddressTest extends AndroidTestCase { l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK); assertParcelingIsLossless(l); } + + private void assertGlobalPreferred(LinkAddress l, String msg) { + assertTrue(msg, l.isGlobalPreferred()); + } + + private void assertNotGlobalPreferred(LinkAddress l, String msg) { + assertFalse(msg, l.isGlobalPreferred()); + } + + public void testIsGlobalPreferred() { + LinkAddress l; + + l = new LinkAddress(V4_ADDRESS, 32, 0, RT_SCOPE_UNIVERSE); + assertGlobalPreferred(l, "v4,global,noflags"); + + l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_UNIVERSE); + assertGlobalPreferred(l, "v4-rfc1918,global,noflags"); + + l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_SITE); + assertNotGlobalPreferred(l, "v4-rfc1918,site-local,noflags"); + + l = new LinkAddress("127.0.0.7/8", 0, RT_SCOPE_HOST); + assertNotGlobalPreferred(l, "v4-localhost,node-local,noflags"); + + l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE); + assertGlobalPreferred(l, "v6,global,noflags"); + + l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); + assertGlobalPreferred(l, "v6,global,permanent"); + + // IPv6 ULAs are not acceptable "global preferred" addresses. + l = new LinkAddress("fc12::1/64", 0, RT_SCOPE_UNIVERSE); + assertNotGlobalPreferred(l, "v6,ula1,noflags"); + + l = new LinkAddress("fd34::1/64", 0, RT_SCOPE_UNIVERSE); + assertNotGlobalPreferred(l, "v6,ula2,noflags"); + + l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_UNIVERSE); + assertGlobalPreferred(l, "v6,global,tempaddr"); + + l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DADFAILED), + RT_SCOPE_UNIVERSE); + assertNotGlobalPreferred(l, "v6,global,tempaddr+dadfailed"); + + l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DEPRECATED), + RT_SCOPE_UNIVERSE); + assertNotGlobalPreferred(l, "v6,global,tempaddr+deprecated"); + + l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_SITE); + assertNotGlobalPreferred(l, "v6,site-local,tempaddr"); + + l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_LINK); + assertNotGlobalPreferred(l, "v6,link-local,tempaddr"); + + l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_HOST); + assertNotGlobalPreferred(l, "v6,node-local,tempaddr"); + + l = new LinkAddress("::1/128", IFA_F_PERMANENT, RT_SCOPE_HOST); + assertNotGlobalPreferred(l, "v6-localhost,node-local,permanent"); + + l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_TENTATIVE), + RT_SCOPE_UNIVERSE); + assertNotGlobalPreferred(l, "v6,global,tempaddr+tentative"); + + l = new LinkAddress(V6_ADDRESS, 64, + (IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC), + RT_SCOPE_UNIVERSE); + assertGlobalPreferred(l, "v6,global,tempaddr+optimistic"); + } }