This is an automated email from the ASF dual-hosted git repository. gabriel pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/master by this push: new f967944 ipv6: Do not allow Secondary IPv6 addresses to be EUI-64 (#3136) f967944 is described below commit f967944d900847c9a2020f9aa81f5db09ee78a1c Author: Wido den Hollander <w...@widodh.nl> AuthorDate: Mon Jan 21 12:20:27 2019 +0100 ipv6: Do not allow Secondary IPv6 addresses to be EUI-64 (#3136) * netutils: Add method to verify if IPv6 Address is EUI-64 By checking if ff:fe is present in the address we can see if an IPv6 Address is EUI-64 or not. Signed-off-by: Wido den Hollander <w...@widodh.nl> * ipv6: Do not allow a Secondary IPv6 address to be EUI-64 EUI-64 addresses should not be allowed as they can be used in the future by a to be deployed Instance which has to obtain this address because it matches it's MAC. In a /64 subnet there are more then enough other IPs available to be allocated to Instances, therefor we can safely disallow the allocation of EUI-64 addresses. Signed-off-by: Wido den Hollander <w...@widodh.nl> --- .../com/cloud/network/Ipv6AddressManagerImpl.java | 5 ++++ .../com/cloud/network/Ipv6AddressManagerTest.java | 7 ++++++ .../main/java/com/cloud/utils/net/NetUtils.java | 27 ++++++++++++++++++++++ .../java/com/cloud/utils/net/NetUtilsTest.java | 8 +++++++ 4 files changed, 47 insertions(+) diff --git a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java index 0371833..adfc3d2 100644 --- a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java @@ -104,6 +104,11 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa network.getDataCenterId()); } + if (NetUtils.isIPv6EUI64(requestedIpv6)) { + throw new InsufficientAddressCapacityException(String.format("Requested IPv6 address [%s] may not be a EUI-64 address", requestedIpv6), DataCenter.class, + network.getDataCenterId()); + } + checkIfCanAllocateIpv6Address(network, requestedIpv6); IpAddresses requestedIpPair = new IpAddresses(null, requestedIpv6); diff --git a/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java b/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java index 827f533..3f082d5 100644 --- a/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java +++ b/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java @@ -248,4 +248,11 @@ public class Ipv6AddressManagerTest { Assert.assertEquals(expected, nic.getIPv6Address()); } + + @Test(expected = InsufficientAddressCapacityException.class) + public void acquireGuestIpv6AddressEUI64Test() throws InsufficientAddressCapacityException { + setAcquireGuestIpv6AddressTest(true, State.Free); + String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8:13f::1c00:4aff:fe00:fe", false, false); + ip6Manager.acquireGuestIpv6Address(network, requestedIpv6); + } } diff --git a/utils/src/main/java/com/cloud/utils/net/NetUtils.java b/utils/src/main/java/com/cloud/utils/net/NetUtils.java index 958dfc6..72f6583b 100644 --- a/utils/src/main/java/com/cloud/utils/net/NetUtils.java +++ b/utils/src/main/java/com/cloud/utils/net/NetUtils.java @@ -88,6 +88,10 @@ public class NetUtils { private final static Random s_rand = new Random(System.currentTimeMillis()); private final static long prefix = 0x1e; + // RFC4291 IPv6 EUI-64 + public final static int IPV6_EUI64_11TH_BYTE = -1; + public final static int IPV6_EUI64_12TH_BYTE = -2; + public static long createSequenceBasedMacAddress(final long macAddress, long globalConfig) { /* Logic for generating MAC address: @@ -1583,6 +1587,29 @@ public class NetUtils { } /** + * When using StateLess Address AutoConfiguration (SLAAC) for IPv6 the addresses + * choosen by hosts in a network are based on the 48-bit MAC address and this is expanded to 64-bits + * with EUI-64 + * FFFE is inserted into the address and these can be identified + * + * By converting the IPv6 Address to a byte array we can check the 11th and 12th byte to see if the + * address is EUI064. + * + * See RFC4291 for more information + * + * @param address IPv6Address to be checked + * @return True if Address is EUI-64 IPv6 + */ + public static boolean isIPv6EUI64(final IPv6Address address) { + byte[] bytes = address.toByteArray(); + return (bytes[11] == IPV6_EUI64_11TH_BYTE && bytes[12] == IPV6_EUI64_12TH_BYTE); + } + + public static boolean isIPv6EUI64(final String address) { + return NetUtils.isIPv6EUI64(IPv6Address.fromString(address)); + } + + /** * Returns true if the given IP address is IPv4 or false if it is an IPv6. If it is an invalid IP address it throws an exception. */ public static boolean isIpv4(String ipAddr) { diff --git a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java index bb8ba12..173704a 100644 --- a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java @@ -701,4 +701,12 @@ public class NetUtilsTest { assertTrue(NetUtils.getAllDefaultNicIps().stream().anyMatch(defaultHostIp::contains)); } } + + @Test + public void testIsIPv6EUI64() { + assertTrue(NetUtils.isIPv6EUI64("fe80::5054:8fff:fe9f:af61")); + assertTrue(NetUtils.isIPv6EUI64("2a00:f10:305:0:464:64ff:fe00:4e0")); + assertFalse(NetUtils.isIPv6EUI64("2001:db8::100:1")); + assertFalse(NetUtils.isIPv6EUI64("2a01:4f9:2a:185f::2")); + } }