IPv6: CLOUDSTACK-1153: Fix integer overflow on IPv6 address calcuation

Use BigInteger, which is 128 bits long.
This commit is contained in:
Sheng Yang 2013-02-05 17:32:40 -08:00
parent e81389a23e
commit fda8ec3c59
3 changed files with 52 additions and 23 deletions

View File

@ -17,6 +17,7 @@
package com.cloud.network;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
@ -556,8 +557,9 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel {
}
Vlan vlan = getVlanForNetwork(network.getId());
long existedCount = _ipv6Dao.countExistedIpsInNetwork(network.getId());
long rangeCount = NetUtils.countIp6InRange(vlan.getIp6Range());
return (existedCount < rangeCount);
BigInteger existedInt = BigInteger.valueOf(existedCount);
BigInteger rangeInt = NetUtils.countIp6InRange(vlan.getIp6Range());
return (existedInt.compareTo(rangeInt) < 0);
}
@Override

View File

@ -19,6 +19,7 @@ package com.cloud.utils.net;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Array;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
@ -1151,19 +1152,25 @@ public class NetUtils {
return network.getNetmask().asPrefixLength();
}
//FIXME: only able to cover lower 32 bits
// Can cover 127 bits
public static String getIp6FromRange(String ip6Range) {
String[] ips = ip6Range.split("-");
String startIp = ips[0];
IPv6Address start = IPv6Address.fromString(startIp);
// Find a random number based on lower 32 bits
long gap = countIp6InRange(ip6Range);
if (gap > Integer.MAX_VALUE) {
gap = Integer.MAX_VALUE;
BigInteger gap = countIp6InRange(ip6Range);
BigInteger next = new BigInteger(gap.bitLength(), _rand);
while (next.compareTo(gap) >= 0) {
next = new BigInteger(gap.bitLength(), _rand);
}
int next = _rand.nextInt((int)(gap));
// And a number based on the difference of lower 32 bits
IPv6Address ip = start.add(next);
BigInteger startInt = convertIPv6AddressToBigInteger(start);
BigInteger resultInt = startInt.add(next);
InetAddress resultAddr;
try {
resultAddr = InetAddress.getByAddress(resultInt.toByteArray());
} catch (UnknownHostException e) {
return null;
}
IPv6Address ip = IPv6Address.fromInetAddress(resultAddr);
return ip.toString();
}
@ -1173,11 +1180,21 @@ public class NetUtils {
return duid;
}
//FIXME: only able to cover lower 64 bits
public static long countIp6InRange(String ip6Range) {
private static BigInteger convertIPv6AddressToBigInteger(IPv6Address addr) {
InetAddress inetAddr;
try {
inetAddr = addr.toInetAddress();
} catch (UnknownHostException e) {
return null;
}
return new BigInteger(inetAddr.getAddress());
}
// Can cover 127 bits
public static BigInteger countIp6InRange(String ip6Range) {
String[] ips = ip6Range.split("-");
String startIp = ips[0];
String endIp = null;
String endIp = ips[0];
if (ips.length > 1) {
endIp = ips[1];
}
@ -1186,13 +1203,14 @@ public class NetUtils {
start = IPv6Address.fromString(startIp);
end = IPv6Address.fromString(endIp);
} catch (IllegalArgumentException ex) {
return 0;
return null;
}
long startLow = start.getLowBits(), endLow = end.getLowBits();
if (startLow > endLow) {
return 0;
BigInteger startInt = convertIPv6AddressToBigInteger(start);
BigInteger endInt = convertIPv6AddressToBigInteger(end);
if (startInt.compareTo(endInt) > 0) {
return null;
}
return endLow - startLow + 1;
return endInt.subtract(startInt).add(BigInteger.ONE);
}
public static boolean isIp6InRange(String ip6, String ip6Range) {

View File

@ -16,6 +16,7 @@
// under the License.
package com.cloud.utils.net;
import java.math.BigInteger;
import java.util.SortedSet;
import java.util.TreeSet;
@ -84,13 +85,18 @@ public class NetUtilsTest extends TestCase {
assertFalse(NetUtils.isValidIp6Cidr("1234:5678::1"));
assertEquals(NetUtils.getIp6CidrSize("1234:5678::1/32"), 32);
assertEquals(NetUtils.getIp6CidrSize("1234:5678::1"), 0);
assertEquals(NetUtils.countIp6InRange("1234:5678::1-1234:5678::2"), 2);
assertEquals(NetUtils.countIp6InRange("1234:5678::2-1234:5678::0"), 0);
BigInteger two = new BigInteger("2");
assertEquals(NetUtils.countIp6InRange("1234:5678::1-1234:5678::2"), two);
assertEquals(NetUtils.countIp6InRange("1234:5678::2-1234:5678::0"), null);
assertEquals(NetUtils.getIp6FromRange("1234:5678::1-1234:5678::1"), "1234:5678::1");
for (int i = 0; i < 5; i ++) {
String ip = NetUtils.getIp6FromRange("1234:5678::1-1234:5678::2");
assertTrue(ip.equals("1234:5678::1") || ip.equals("1234:5678::2"));
s_logger.info("IP is " + ip);
}
String ipString = null;
String range = "1234:5678::1-1234:5678::8000:0000";
IPv6Address ipStart = IPv6Address.fromString("1234:5678::1");
IPv6Address ipEnd = IPv6Address.fromString("1234:5678::8000:0000");
IPv6Address ipEnd = IPv6Address.fromString("1234:5678::ffff:ffff:ffff:ffff");
for (int i = 0; i < 10; i ++) {
ipString = NetUtils.getIp6FromRange(ipStart.toString() + "-" + ipEnd.toString());
s_logger.info("IP is " + ipString);
@ -105,9 +111,12 @@ public class NetUtilsTest extends TestCase {
assertFalse(NetUtils.isIp6RangeOverlap("1234:5678::f-1234:5678::ffff", "1234:5678::2-1234:5678::e"));
assertFalse(NetUtils.isIp6RangeOverlap("1234:5678::f-1234:5678::f", "1234:5678::2-1234:5678::e"));
//Test getNextIp6InRange
assertEquals(NetUtils.getNextIp6InRange("1234:5678::8000:0000", range), "1234:5678::1");
String range = "1234:5678::1-1234:5678::8000:0000";
assertEquals(NetUtils.getNextIp6InRange("1234:5678::8000:0", range), "1234:5678::1");
assertEquals(NetUtils.getNextIp6InRange("1234:5678::7fff:ffff", range), "1234:5678::8000:0");
assertEquals(NetUtils.getNextIp6InRange("1234:5678::1", range), "1234:5678::2");
range = "1234:5678::1-1234:5678::ffff:ffff:ffff:ffff";
assertEquals(NetUtils.getNextIp6InRange("1234:5678::ffff:ffff:ffff:ffff", range), "1234:5678::1");
//Test isIp6InNetwork
assertFalse(NetUtils.isIp6InNetwork("1234:5678:abcd::1", "1234:5678::/64"));
assertTrue(NetUtils.isIp6InNetwork("1234:5678::1", "1234:5678::/64"));