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
This commit is contained in:
Erik Kline
2014-10-20 19:46:56 +09:00
parent 67118eb4df
commit 143e89c2f1
2 changed files with 97 additions and 1 deletions

View File

@@ -21,12 +21,14 @@ import android.os.Parcelable;
import android.util.Pair; import android.util.Pair;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InterfaceAddress; import java.net.InterfaceAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import static android.system.OsConstants.IFA_F_DADFAILED; import static android.system.OsConstants.IFA_F_DADFAILED;
import static android.system.OsConstants.IFA_F_DEPRECATED; 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.IFA_F_TENTATIVE;
import static android.system.OsConstants.RT_SCOPE_HOST; import static android.system.OsConstants.RT_SCOPE_HOST;
import static android.system.OsConstants.RT_SCOPE_LINK; import static android.system.OsConstants.RT_SCOPE_LINK;
@@ -92,6 +94,20 @@ public class LinkAddress implements Parcelable {
return RT_SCOPE_UNIVERSE; 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. * Utility function for the constructors.
*/ */
@@ -268,8 +284,16 @@ public class LinkAddress implements Parcelable {
* @hide * @hide
*/ */
public boolean isGlobalPreferred() { 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 && 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));
} }
/** /**

View File

@@ -33,8 +33,11 @@ import android.test.AndroidTestCase;
import static android.test.MoreAsserts.assertNotEqual; import static android.test.MoreAsserts.assertNotEqual;
import android.test.suitebuilder.annotation.SmallTest; 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_DEPRECATED;
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
import static android.system.OsConstants.IFA_F_PERMANENT; 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.IFA_F_TENTATIVE;
import static android.system.OsConstants.RT_SCOPE_HOST; import static android.system.OsConstants.RT_SCOPE_HOST;
import static android.system.OsConstants.RT_SCOPE_LINK; 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); l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
assertParcelingIsLossless(l); 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");
}
} }