Skip to content

Commit fda8ec3

Browse files
author
Sheng Yang
committed
IPv6: CLOUDSTACK-1153: Fix integer overflow on IPv6 address calcuation
Use BigInteger, which is 128 bits long.
1 parent e81389a commit fda8ec3

3 files changed

Lines changed: 52 additions & 23 deletions

File tree

server/src/com/cloud/network/NetworkModelImpl.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package com.cloud.network;
1919

20+
import java.math.BigInteger;
2021
import java.security.InvalidParameterException;
2122
import java.util.ArrayList;
2223
import java.util.HashMap;
@@ -556,8 +557,9 @@ public boolean isIP6AddressAvailable(long networkId) {
556557
}
557558
Vlan vlan = getVlanForNetwork(network.getId());
558559
long existedCount = _ipv6Dao.countExistedIpsInNetwork(network.getId());
559-
long rangeCount = NetUtils.countIp6InRange(vlan.getIp6Range());
560-
return (existedCount < rangeCount);
560+
BigInteger existedInt = BigInteger.valueOf(existedCount);
561+
BigInteger rangeInt = NetUtils.countIp6InRange(vlan.getIp6Range());
562+
return (existedInt.compareTo(rangeInt) < 0);
561563
}
562564

563565
@Override

utils/src/com/cloud/utils/net/NetUtils.java

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.BufferedReader;
2020
import java.io.InputStreamReader;
2121
import java.lang.reflect.Array;
22+
import java.math.BigInteger;
2223
import java.net.InetAddress;
2324
import java.net.InterfaceAddress;
2425
import java.net.NetworkInterface;
@@ -1151,19 +1152,25 @@ public static int getIp6CidrSize(String ip6Cidr) {
11511152
return network.getNetmask().asPrefixLength();
11521153
}
11531154

1154-
//FIXME: only able to cover lower 32 bits
1155+
// Can cover 127 bits
11551156
public static String getIp6FromRange(String ip6Range) {
11561157
String[] ips = ip6Range.split("-");
11571158
String startIp = ips[0];
11581159
IPv6Address start = IPv6Address.fromString(startIp);
1159-
// Find a random number based on lower 32 bits
1160-
long gap = countIp6InRange(ip6Range);
1161-
if (gap > Integer.MAX_VALUE) {
1162-
gap = Integer.MAX_VALUE;
1160+
BigInteger gap = countIp6InRange(ip6Range);
1161+
BigInteger next = new BigInteger(gap.bitLength(), _rand);
1162+
while (next.compareTo(gap) >= 0) {
1163+
next = new BigInteger(gap.bitLength(), _rand);
11631164
}
1164-
int next = _rand.nextInt((int)(gap));
1165-
// And a number based on the difference of lower 32 bits
1166-
IPv6Address ip = start.add(next);
1165+
BigInteger startInt = convertIPv6AddressToBigInteger(start);
1166+
BigInteger resultInt = startInt.add(next);
1167+
InetAddress resultAddr;
1168+
try {
1169+
resultAddr = InetAddress.getByAddress(resultInt.toByteArray());
1170+
} catch (UnknownHostException e) {
1171+
return null;
1172+
}
1173+
IPv6Address ip = IPv6Address.fromInetAddress(resultAddr);
11671174
return ip.toString();
11681175
}
11691176

@@ -1173,11 +1180,21 @@ public static String getDuidLL(String macAddress) {
11731180
return duid;
11741181
}
11751182

1176-
//FIXME: only able to cover lower 64 bits
1177-
public static long countIp6InRange(String ip6Range) {
1183+
private static BigInteger convertIPv6AddressToBigInteger(IPv6Address addr) {
1184+
InetAddress inetAddr;
1185+
try {
1186+
inetAddr = addr.toInetAddress();
1187+
} catch (UnknownHostException e) {
1188+
return null;
1189+
}
1190+
return new BigInteger(inetAddr.getAddress());
1191+
}
1192+
1193+
// Can cover 127 bits
1194+
public static BigInteger countIp6InRange(String ip6Range) {
11781195
String[] ips = ip6Range.split("-");
11791196
String startIp = ips[0];
1180-
String endIp = null;
1197+
String endIp = ips[0];
11811198
if (ips.length > 1) {
11821199
endIp = ips[1];
11831200
}
@@ -1186,13 +1203,14 @@ public static long countIp6InRange(String ip6Range) {
11861203
start = IPv6Address.fromString(startIp);
11871204
end = IPv6Address.fromString(endIp);
11881205
} catch (IllegalArgumentException ex) {
1189-
return 0;
1206+
return null;
11901207
}
1191-
long startLow = start.getLowBits(), endLow = end.getLowBits();
1192-
if (startLow > endLow) {
1193-
return 0;
1208+
BigInteger startInt = convertIPv6AddressToBigInteger(start);
1209+
BigInteger endInt = convertIPv6AddressToBigInteger(end);
1210+
if (startInt.compareTo(endInt) > 0) {
1211+
return null;
11941212
}
1195-
return endLow - startLow + 1;
1213+
return endInt.subtract(startInt).add(BigInteger.ONE);
11961214
}
11971215

11981216
public static boolean isIp6InRange(String ip6, String ip6Range) {

utils/test/com/cloud/utils/net/NetUtilsTest.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package com.cloud.utils.net;
1818

19+
import java.math.BigInteger;
1920
import java.util.SortedSet;
2021
import java.util.TreeSet;
2122

@@ -84,13 +85,18 @@ public void testIpv6() {
8485
assertFalse(NetUtils.isValidIp6Cidr("1234:5678::1"));
8586
assertEquals(NetUtils.getIp6CidrSize("1234:5678::1/32"), 32);
8687
assertEquals(NetUtils.getIp6CidrSize("1234:5678::1"), 0);
87-
assertEquals(NetUtils.countIp6InRange("1234:5678::1-1234:5678::2"), 2);
88-
assertEquals(NetUtils.countIp6InRange("1234:5678::2-1234:5678::0"), 0);
88+
BigInteger two = new BigInteger("2");
89+
assertEquals(NetUtils.countIp6InRange("1234:5678::1-1234:5678::2"), two);
90+
assertEquals(NetUtils.countIp6InRange("1234:5678::2-1234:5678::0"), null);
8991
assertEquals(NetUtils.getIp6FromRange("1234:5678::1-1234:5678::1"), "1234:5678::1");
92+
for (int i = 0; i < 5; i ++) {
93+
String ip = NetUtils.getIp6FromRange("1234:5678::1-1234:5678::2");
94+
assertTrue(ip.equals("1234:5678::1") || ip.equals("1234:5678::2"));
95+
s_logger.info("IP is " + ip);
96+
}
9097
String ipString = null;
91-
String range = "1234:5678::1-1234:5678::8000:0000";
9298
IPv6Address ipStart = IPv6Address.fromString("1234:5678::1");
93-
IPv6Address ipEnd = IPv6Address.fromString("1234:5678::8000:0000");
99+
IPv6Address ipEnd = IPv6Address.fromString("1234:5678::ffff:ffff:ffff:ffff");
94100
for (int i = 0; i < 10; i ++) {
95101
ipString = NetUtils.getIp6FromRange(ipStart.toString() + "-" + ipEnd.toString());
96102
s_logger.info("IP is " + ipString);
@@ -105,9 +111,12 @@ public void testIpv6() {
105111
assertFalse(NetUtils.isIp6RangeOverlap("1234:5678::f-1234:5678::ffff", "1234:5678::2-1234:5678::e"));
106112
assertFalse(NetUtils.isIp6RangeOverlap("1234:5678::f-1234:5678::f", "1234:5678::2-1234:5678::e"));
107113
//Test getNextIp6InRange
108-
assertEquals(NetUtils.getNextIp6InRange("1234:5678::8000:0000", range), "1234:5678::1");
114+
String range = "1234:5678::1-1234:5678::8000:0000";
115+
assertEquals(NetUtils.getNextIp6InRange("1234:5678::8000:0", range), "1234:5678::1");
109116
assertEquals(NetUtils.getNextIp6InRange("1234:5678::7fff:ffff", range), "1234:5678::8000:0");
110117
assertEquals(NetUtils.getNextIp6InRange("1234:5678::1", range), "1234:5678::2");
118+
range = "1234:5678::1-1234:5678::ffff:ffff:ffff:ffff";
119+
assertEquals(NetUtils.getNextIp6InRange("1234:5678::ffff:ffff:ffff:ffff", range), "1234:5678::1");
111120
//Test isIp6InNetwork
112121
assertFalse(NetUtils.isIp6InNetwork("1234:5678:abcd::1", "1234:5678::/64"));
113122
assertTrue(NetUtils.isIp6InNetwork("1234:5678::1", "1234:5678::/64"));

0 commit comments

Comments
 (0)