// // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // package com.cloud.utils.net; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.math.BigInteger; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.URI; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Formatter; import java.util.List; import java.util.Random; import java.util.Set; import java.util.SortedSet; import java.util.StringTokenizer; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; import org.apache.commons.net.util.SubnetUtils; import org.apache.commons.validator.routines.InetAddressValidator; import org.apache.log4j.Logger; import com.cloud.utils.IteratorUtil; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; import com.googlecode.ipv6.IPv6Address; import com.googlecode.ipv6.IPv6AddressRange; import com.googlecode.ipv6.IPv6Network; public class NetUtils { protected final static Logger s_logger = Logger.getLogger(NetUtils.class); private static final int MAX_CIDR = 32; private static final int RFC_3021_31_BIT_CIDR = 31; public final static String HTTP_PORT = "80"; public final static String HTTPS_PORT = "443"; public final static int VPN_PORT = 500; public final static int VPN_NATT_PORT = 4500; public final static int VPN_L2TP_PORT = 1701; public final static int HAPROXY_STATS_PORT = 8081; public final static String UDP_PROTO = "udp"; public final static String TCP_PROTO = "tcp"; public final static String ANY_PROTO = "any"; public final static String ICMP_PROTO = "icmp"; public final static String ALL_PROTO = "all"; public final static String HTTP_PROTO = "http"; public final static String SSL_PROTO = "ssl"; public final static String ALL_CIDRS = "0.0.0.0/0"; public final static int PORT_RANGE_MIN = 0; public final static int PORT_RANGE_MAX = 65535; public final static int DEFAULT_AUTOSCALE_VM_DESTROY_TIME = 2 * 60; // Grace period before Vm is destroyed public final static int DEFAULT_AUTOSCALE_POLICY_INTERVAL_TIME = 30; public final static int DEFAULT_AUTOSCALE_POLICY_QUIET_TIME = 5 * 60; private final static Random s_rand = new Random(System.currentTimeMillis()); public static long createSequenceBasedMacAddress(final long macAddress) { return macAddress | 0x060000000000l | (long)s_rand.nextInt(32768) << 25 & 0x00fffe000000l; } public static String getHostName() { try { final InetAddress localAddr = InetAddress.getLocalHost(); if (localAddr != null) { return localAddr.getHostName(); } } catch (final UnknownHostException e) { s_logger.warn("UnknownHostException when trying to get host name. ", e); } return "localhost"; } public static InetAddress getLocalInetAddress() { try { return InetAddress.getLocalHost(); } catch (final UnknownHostException e) { s_logger.warn("UnknownHostException in getLocalInetAddress().", e); return null; } } public static String resolveToIp(final String host) { try { final InetAddress addr = InetAddress.getByName(host); return ipFromInetAddress(addr); } catch (final UnknownHostException e) { s_logger.warn("Unable to resolve " + host + " to IP due to UnknownHostException"); return null; } } public static InetAddress[] getAllLocalInetAddresses() { final List<InetAddress> addrList = new ArrayList<InetAddress>(); try { for (final NetworkInterface ifc : IteratorUtil.enumerationAsIterable(NetworkInterface.getNetworkInterfaces())) { if (ifc.isUp() && !ifc.isVirtual()) { for (final InetAddress addr : IteratorUtil.enumerationAsIterable(ifc.getInetAddresses())) { addrList.add(addr); } } } } catch (final SocketException e) { s_logger.warn("SocketException in getAllLocalInetAddresses().", e); } final InetAddress[] addrs = new InetAddress[addrList.size()]; if (addrList.size() > 0) { System.arraycopy(addrList.toArray(), 0, addrs, 0, addrList.size()); } return addrs; } public static String[] getLocalCidrs() { final String defaultHostIp = getDefaultHostIp(); final List<String> cidrList = new ArrayList<String>(); try { for (final NetworkInterface ifc : IteratorUtil.enumerationAsIterable(NetworkInterface.getNetworkInterfaces())) { if (ifc.isUp() && !ifc.isVirtual() && !ifc.isLoopback()) { for (final InterfaceAddress address : ifc.getInterfaceAddresses()) { final InetAddress addr = address.getAddress(); final int prefixLength = address.getNetworkPrefixLength(); if (prefixLength < MAX_CIDR && prefixLength > 0) { final String ip = ipFromInetAddress(addr); if (ip.equalsIgnoreCase(defaultHostIp)) { cidrList.add(ipAndNetMaskToCidr(ip, getCidrNetmask(prefixLength))); } } } } } } catch (final SocketException e) { s_logger.warn("UnknownHostException in getLocalCidrs().", e); } return cidrList.toArray(new String[0]); } public static String getDefaultHostIp() { if (SystemUtils.IS_OS_WINDOWS) { final Pattern pattern = Pattern.compile("\\s*0.0.0.0\\s*0.0.0.0\\s*(\\S*)\\s*(\\S*)\\s*"); try { final Process result = Runtime.getRuntime().exec("route print -4"); final BufferedReader output = new BufferedReader(new InputStreamReader(result.getInputStream())); String line = output.readLine(); while (line != null) { final Matcher matcher = pattern.matcher(line); if (matcher.find()) { return matcher.group(2); } line = output.readLine(); } } catch (final IOException e) { s_logger.debug("Caught IOException", e); } return null; } else { NetworkInterface nic = null; final String pubNic = getDefaultEthDevice(); if (pubNic == null) { return null; } try { nic = NetworkInterface.getByName(pubNic); } catch (final SocketException e) { return null; } String[] info = null; try { info = NetUtils.getNetworkParams(nic); } catch (final NullPointerException ignored) { s_logger.debug("Caught NullPointerException when trying to getDefaultHostIp"); } if (info != null) { return info[0]; } return null; } } public static String getDefaultEthDevice() { if (SystemUtils.IS_OS_MAC) { final String defDev = Script.runSimpleBashScript("/sbin/route -n get default 2> /dev/null | grep interface | awk '{print $2}'"); return defDev; } final String defaultRoute = Script.runSimpleBashScript("/sbin/route | grep default"); if (defaultRoute == null) { return null; } final String[] defaultRouteList = defaultRoute.split("\\s+"); if (defaultRouteList.length != 8) { return null; } return defaultRouteList[7]; } public static InetAddress getFirstNonLoopbackLocalInetAddress() { final InetAddress[] addrs = getAllLocalInetAddresses(); if (addrs != null) { for (final InetAddress addr : addrs) { if (s_logger.isInfoEnabled()) { s_logger.info("Check local InetAddress : " + addr.toString() + ", total count :" + addrs.length); } if (!addr.isLoopbackAddress()) { return addr; } } } s_logger.warn("Unable to determine a non-loopback address, local inet address count :" + addrs.length); return null; } public static InetAddress[] getInterfaceInetAddresses(final String ifName) { final List<InetAddress> addrList = new ArrayList<InetAddress>(); try { for (final NetworkInterface ifc : IteratorUtil.enumerationAsIterable(NetworkInterface.getNetworkInterfaces())) { if (ifc.isUp() && !ifc.isVirtual() && ifc.getName().equals(ifName)) { for (final InetAddress addr : IteratorUtil.enumerationAsIterable(ifc.getInetAddresses())) { addrList.add(addr); } } } } catch (final SocketException e) { s_logger.warn("SocketException in getAllLocalInetAddresses().", e); } final InetAddress[] addrs = new InetAddress[addrList.size()]; if (addrList.size() > 0) { System.arraycopy(addrList.toArray(), 0, addrs, 0, addrList.size()); } return addrs; } public static String getLocalIPString() { final InetAddress addr = getLocalInetAddress(); if (addr != null) { return ipFromInetAddress(addr); } return "127.0.0.1"; } public static String ipFromInetAddress(final InetAddress addr) { assert addr != null; final byte[] ipBytes = addr.getAddress(); final StringBuffer sb = new StringBuffer(); sb.append(ipBytes[0] & 0xff).append("."); sb.append(ipBytes[1] & 0xff).append("."); sb.append(ipBytes[2] & 0xff).append("."); sb.append(ipBytes[3] & 0xff); return sb.toString(); } public static boolean isLocalAddress(final InetAddress addr) { final InetAddress[] addrs = getAllLocalInetAddresses(); if (addrs != null) { for (final InetAddress self : addrs) { if (self.equals(addr)) { return true; } } } return false; } public static boolean isLocalAddress(final String strAddress) { InetAddress addr; try { addr = InetAddress.getByName(strAddress); return isLocalAddress(addr); } catch (final UnknownHostException e) { } return false; } public static String getMacAddress(final InetAddress address) { final StringBuffer sb = new StringBuffer(); final Formatter formatter = new Formatter(sb); try { final NetworkInterface ni = NetworkInterface.getByInetAddress(address); final byte[] mac = ni.getHardwareAddress(); for (int i = 0; i < mac.length; i++) { formatter.format("%02X%s", mac[i], i < mac.length - 1 ? ":" : ""); } } catch (final SocketException e) { s_logger.error("SocketException when trying to retrieve MAC address", e); } finally { formatter.close(); } return sb.toString(); } public static long getMacAddressAsLong(final InetAddress address) { long macAddressAsLong = 0; try { final NetworkInterface ni = NetworkInterface.getByInetAddress(address); final byte[] mac = ni.getHardwareAddress(); for (int i = 0; i < mac.length; i++) { macAddressAsLong |= (long)(mac[i] & 0xff) << (mac.length - i - 1) * 8; } } catch (final SocketException e) { s_logger.error("SocketException when trying to retrieve MAC address", e); } return macAddressAsLong; } /** * This method will fail in case we have a 31 Bit prefix network * See RFC 3021. * * In order to avoid calling this method, please check the <code>NetUtils.is31PrefixCidr(cidr)</code> first. */ public static boolean ipRangesOverlap(final String startIp1, final String endIp1, final String startIp2, final String endIp2) { final long startIp1Long = ip2Long(startIp1); long endIp1Long = startIp1Long; if (endIp1 != null) { endIp1Long = ip2Long(endIp1); } final long startIp2Long = ip2Long(startIp2); long endIp2Long = startIp2Long; if (endIp2 != null) { endIp2Long = ip2Long(endIp2); } if (startIp1Long == startIp2Long || startIp1Long == endIp2Long || endIp1Long == startIp2Long || endIp1Long == endIp2Long) { return true; } else if (startIp1Long > startIp2Long && startIp1Long < endIp2Long) { return true; } else if (endIp1Long > startIp2Long && endIp1Long < endIp2Long) { return true; } else if (startIp2Long > startIp1Long && startIp2Long < endIp1Long) { return true; } else if (endIp2Long > startIp1Long && endIp2Long < endIp1Long) { return true; } else { return false; } } public static long ip2Long(final String ip) { final String[] tokens = ip.split("[.]"); assert tokens.length == 4; long result = 0; for (int i = 0; i < tokens.length; i++) { try { result = result << 8 | Integer.parseInt(tokens[i]); } catch (final NumberFormatException e) { throw new RuntimeException("Incorrect number", e); } } return result; } public static String long2Ip(final long ip) { final StringBuilder result = new StringBuilder(15); result.append(ip >> 24 & 0xff).append("."); result.append(ip >> 16 & 0xff).append("."); result.append(ip >> 8 & 0xff).append("."); result.append(ip & 0xff); return result.toString(); } public static long mac2Long(final String macAddress) { final String[] tokens = macAddress.split(":"); assert tokens.length == 6; long result = 0; for (int i = 0; i < tokens.length; i++) { result = result << 8; result |= Integer.parseInt(tokens[i], 16); } return result; } public static String[] getNicParams(final String nicName) { try { final NetworkInterface nic = NetworkInterface.getByName(nicName); return getNetworkParams(nic); } catch (final SocketException e) { return null; } } public static String[] getNetworkParams(final NetworkInterface nic) { final List<InterfaceAddress> addrs = nic.getInterfaceAddresses(); if (addrs == null || addrs.size() == 0) { return null; } InterfaceAddress addr = null; for (final InterfaceAddress iaddr : addrs) { final InetAddress inet = iaddr.getAddress(); if (!inet.isLinkLocalAddress() && !inet.isLoopbackAddress() && !inet.isMulticastAddress() && inet.getAddress().length == 4) { addr = iaddr; break; } } if (addr == null) { return null; } final String[] result = new String[3]; result[0] = addr.getAddress().getHostAddress(); try { final byte[] mac = nic.getHardwareAddress(); result[1] = byte2Mac(mac); } catch (final SocketException e) { s_logger.debug("Caught exception when trying to get the mac address ", e); } result[2] = prefix2Netmask(addr.getNetworkPrefixLength()); return result; } public static String prefix2Netmask(final short prefix) { long addr = 0; for (int i = 0; i < prefix; i++) { addr = addr | 1 << 31 - i; } return long2Ip(addr); } public static String byte2Mac(final byte[] m) { final StringBuilder result = new StringBuilder(17); final Formatter formatter = new Formatter(result); formatter.format("%02x:%02x:%02x:%02x:%02x:%02x", m[0], m[1], m[2], m[3], m[4], m[5]); formatter.close(); return result.toString(); } public static String long2Mac(final long macAddress) { final StringBuilder result = new StringBuilder(17); try (Formatter formatter = new Formatter(result)) { formatter.format("%02x:%02x:%02x:%02x:%02x:%02x", macAddress >> 40 & 0xff, macAddress >> 32 & 0xff, macAddress >> 24 & 0xff, macAddress >> 16 & 0xff, macAddress >> 8 & 0xff, macAddress & 0xff); } return result.toString(); } public static boolean isValidPrivateIp(final String ipAddress, final String guestIPAddress) { final InetAddress privIp = parseIpAddress(ipAddress); if (privIp == null) { return false; } if (!privIp.isSiteLocalAddress()) { return false; } String firstGuestOctet = "10"; if (guestIPAddress != null && !guestIPAddress.isEmpty()) { final String[] guestIPList = guestIPAddress.split("\\."); firstGuestOctet = guestIPList[0]; } final String[] ipList = ipAddress.split("\\."); if (!ipList[0].equals(firstGuestOctet)) { return false; } return true; } public static boolean isSiteLocalAddress(final String ipAddress) { if (ipAddress == null) { return false; } else { final InetAddress ip = parseIpAddress(ipAddress); if(ip != null) { return ip.isSiteLocalAddress(); } return false; } } public static boolean validIpRange(final String startIP, final String endIP) { if (endIP == null || endIP.isEmpty()) { return true; } final long startIPLong = NetUtils.ip2Long(startIP); final long endIPLong = NetUtils.ip2Long(endIP); return startIPLong <= endIPLong; } public static boolean isValidIp(final String ip) { final InetAddressValidator validator = InetAddressValidator.getInstance(); return validator.isValidInet4Address(ip); } public static boolean is31PrefixCidr(final String cidr) { final boolean isValidCird = isValidCIDR(cidr); if (isValidCird){ final String[] cidrPair = cidr.split("\\/"); final String cidrSize = cidrPair[1]; final int cidrSizeNum = Integer.parseInt(cidrSize); if (cidrSizeNum == RFC_3021_31_BIT_CIDR) { return true; } } return false; } public static boolean isValidCIDR(final String cidr) { if (cidr == null || cidr.isEmpty()) { return false; } try { IPv6Network.fromString(cidr); return true; } catch (IllegalArgumentException e) {} final String[] cidrPair = cidr.split("\\/"); if (cidrPair.length != 2) { return false; } final String cidrAddress = cidrPair[0]; final String cidrSize = cidrPair[1]; if (!isValidIp(cidrAddress)) { return false; } int cidrSizeNum = -1; try { cidrSizeNum = Integer.parseInt(cidrSize); } catch (final Exception e) { return false; } if (cidrSizeNum < 0 || cidrSizeNum > MAX_CIDR) { return false; } return true; } public static boolean isValidNetmask(final String netmask) { if (!isValidIp(netmask)) { return false; } final long ip = ip2Long(netmask); int count = 0; boolean finished = false; for (int i = 31; i >= 0; i--) { if ((ip >> i & 0x1) == 0) { finished = true; } else { if (finished) { return false; } count += 1; } } if (count == 0) { return false; } return true; } private static InetAddress parseIpAddress(final String address) { final StringTokenizer st = new StringTokenizer(address, "."); final byte[] bytes = new byte[4]; if (st.countTokens() == 4) { try { for (int i = 0; i < 4; i++) { bytes[i] = (byte)Integer.parseInt(st.nextToken()); } return InetAddress.getByAddress(address, bytes); } catch (final NumberFormatException nfe) { return null; } catch (final UnknownHostException uhe) { return null; } } return null; } public static String getCidrFromGatewayAndNetmask(final String gatewayStr, final String netmaskStr) { final long netmask = ip2Long(netmaskStr); final long gateway = ip2Long(gatewayStr); final long firstPart = gateway & netmask; final long size = getCidrSize(netmaskStr); return long2Ip(firstPart) + "/" + size; } public static String[] getIpRangeFromCidr(final String cidr, final long size) { assert size < MAX_CIDR : "You do know this is not for ipv6 right? Keep it smaller than 32 but you have " + size; final String[] result = new String[2]; final long ip = ip2Long(cidr); final long startNetMask = ip2Long(getCidrNetmask(size)); final long start = (ip & startNetMask) + 1; long end = start; end = end >> MAX_CIDR - size; end++; end = (end << MAX_CIDR - size) - 2; result[0] = long2Ip(start); result[1] = long2Ip(end); return result; } public static Set<Long> getAllIpsFromCidr(final String cidr, final long size, final Set<Long> usedIps) { assert size < MAX_CIDR : "You do know this is not for ipv6 right? Keep it smaller than 32 but you have " + size; final Set<Long> result = new TreeSet<Long>(); final long ip = ip2Long(cidr); final long startNetMask = ip2Long(getCidrNetmask(size)); long start = (ip & startNetMask) + 1; long end = start; end = end >> MAX_CIDR - size; end++; end = (end << MAX_CIDR - size) - 2; int maxIps = 255; // get 255 ips as maximum while (start <= end && maxIps > 0) { if (!usedIps.contains(start)) { result.add(start); maxIps--; } start++; } return result; } /** * Given a cidr, this method returns an ip address within the range but * is not in the avoid list. * * @param startIp ip that the cidr starts with * @param size size of the cidr * @param avoid set of ips to avoid * @return ip that is within the cidr range but not in the avoid set. -1 if unable to find one. */ public static long getRandomIpFromCidr(final String startIp, final int size, final SortedSet<Long> avoid) { return getRandomIpFromCidr(ip2Long(startIp), size, avoid); } /** * Given a cidr, this method returns an ip address within the range but * is not in the avoid list. * Note: the gateway address has to be specified in the avoid list * * @param cidr ip that the cidr starts with * @param size size of the cidr * @param avoid set of ips to avoid * @return ip that is within the cidr range but not in the avoid set. -1 if unable to find one. */ public static long getRandomIpFromCidr(final long cidr, final int size, final SortedSet<Long> avoid) { assert size < MAX_CIDR : "You do know this is not for ipv6 right? Keep it smaller than 32 but you have " + size; final long startNetMask = ip2Long(getCidrNetmask(size)); final long startIp = (cidr & startNetMask) + 1; //exclude the first ip since it isnt valid, e.g., 192.168.10.0 int range = 1 << MAX_CIDR - size; //e.g., /24 = 2^8 = 256 range = range - 1; //exclude end of the range since that is the broadcast address, e.g., 192.168.10.255 if (avoid.size() >= range) { return -1; } //Reduce the range by the size of the avoid set //e.g., cidr = 192.168.10.0, size = /24, avoid = 192.168.10.1, 192.168.10.20, 192.168.10.254 // range = 2^8 - 1 - 3 = 252 range = range - avoid.size(); final int next = s_rand.nextInt(range); //note: nextInt excludes last value long ip = startIp + next; for (final Long avoidable : avoid) { if (ip >= avoidable) { ip++; } else { break; } } return ip; } public static String getIpRangeStartIpFromCidr(final String cidr, final long size) { final long ip = ip2Long(cidr); final long startNetMask = ip2Long(getCidrNetmask(size)); final long start = (ip & startNetMask) + 1; return long2Ip(start); } public static String getIpRangeEndIpFromCidr(final String cidr, final long size) { final long ip = ip2Long(cidr); final long startNetMask = ip2Long(getCidrNetmask(size)); final long start = (ip & startNetMask) + 1; long end = start; end = end >> MAX_CIDR - size; end++; end = (end << MAX_CIDR - size) - 2; return long2Ip(end); } public static boolean sameSubnet(final String ip1, final String ip2, final String netmask) { if (ip1 == null || ip1.isEmpty() || ip2 == null || ip2.isEmpty()) { return true; } final String subnet1 = NetUtils.getSubNet(ip1, netmask); final String subnet2 = NetUtils.getSubNet(ip2, netmask); return subnet1.equals(subnet2); } public static boolean sameSubnetCIDR(final String ip1, final String ip2, final long cidrSize) { if (ip1 == null || ip1.isEmpty() || ip2 == null || ip2.isEmpty()) { return true; } final String subnet1 = NetUtils.getCidrSubNet(ip1, cidrSize); final String subnet2 = NetUtils.getCidrSubNet(ip2, cidrSize); return subnet1.equals(subnet2); } public static String getSubNet(final String ip, final String netmask) { final long ipAddr = ip2Long(ip); final long subnet = ip2Long(netmask); final long result = ipAddr & subnet; return long2Ip(result); } public static String getCidrSubNet(final String ip, final long cidrSize) { final long numericNetmask = netMaskFromCidr(cidrSize); final String netmask = NetUtils.long2Ip(numericNetmask); return getSubNet(ip, netmask); } /** * @param cidrSize * @return */ static long netMaskFromCidr(final long cidrSize) { return ((long)0xffffffff) >> MAX_CIDR - cidrSize << MAX_CIDR - cidrSize; } public static String ipAndNetMaskToCidr(final String ip, final String netmask) { if (!isValidIp(ip)) { return null; } if (!isValidNetmask(netmask)) { return null; } final long ipAddr = ip2Long(ip); final long subnet = ip2Long(netmask); final long result = ipAddr & subnet; int bits = subnet == 0 ? 0 : 1; long subnet2 = subnet; while ((subnet2 = subnet2 >> 1 & subnet) != 0) { bits++; } return long2Ip(result) + "/" + Integer.toString(bits); } public static String[] ipAndNetMaskToRange(final String ip, final String netmask) { final long ipAddr = ip2Long(ip); long subnet = ip2Long(netmask); final long start = (ipAddr & subnet) + 1; long end = start; int bits = subnet == 0 ? 0 : 1; while ((subnet = subnet >> 1 & subnet) != 0) { bits++; } end = end >> MAX_CIDR - bits; end++; end = (end << MAX_CIDR - bits) - 2; return new String[] {long2Ip(start), long2Ip(end)}; } public static Pair<String, Integer> getCidr(final String cidr) { final String[] tokens = cidr.split("/"); return new Pair<String, Integer>(tokens[0], Integer.parseInt(tokens[1])); } public static enum SupersetOrSubset { isSuperset, isSubset, neitherSubetNorSuperset, sameSubnet, errorInCidrFormat } public static SupersetOrSubset isNetowrkASubsetOrSupersetOfNetworkB(final String cidrA, final String cidrB) { if (!areCidrsNotEmpty(cidrA, cidrB)) { return SupersetOrSubset.errorInCidrFormat; } final Long[] cidrALong = cidrToLong(cidrA); final Long[] cidrBLong = cidrToLong(cidrB); long shift = 0; if (cidrALong[1] >= cidrBLong[1]) { shift = MAX_CIDR - cidrBLong[1]; } else { shift = MAX_CIDR - cidrALong[1]; } final long result = (cidrALong[0] >> shift) - (cidrBLong[0] >> shift); if (result == 0) { if (cidrALong[1] < cidrBLong[1]) { //this implies cidrA is super set of cidrB return SupersetOrSubset.isSuperset; } else if (cidrALong[1].equals(cidrBLong[1])) { //this implies both the cidrs are equal return SupersetOrSubset.sameSubnet; } // implies cidrA is subset of cidrB return SupersetOrSubset.isSubset; } //this implies no overlap. return SupersetOrSubset.neitherSubetNorSuperset; } public static boolean isNetworkAWithinNetworkB(final String cidrA, final String cidrB) { if (!areCidrsNotEmpty(cidrA, cidrB)) { return false; } Long[] cidrALong = cidrToLong(cidrA); Long[] cidrBLong = cidrToLong(cidrB); long shift = MAX_CIDR - cidrBLong[1]; return cidrALong[0] >> shift == cidrBLong[0] >> shift; } static boolean areCidrsNotEmpty(String cidrA, String cidrB) { return StringUtils.isNotEmpty(cidrA) && StringUtils.isNotEmpty(cidrB); } public static Long[] cidrToLong(final String cidr) { if (cidr == null || cidr.isEmpty()) { throw new CloudRuntimeException("empty cidr can not be converted to longs"); } final String[] cidrPair = cidr.split("\\/"); if (cidrPair.length != 2) { throw new CloudRuntimeException("cidr is not formatted correctly: "+ cidr); } final String cidrAddress = cidrPair[0]; final String cidrSize = cidrPair[1]; if (!isValidIp(cidrAddress)) { throw new CloudRuntimeException("cidr is not valid in ip space" + cidr); } long cidrSizeNum = getCidrSizeFromString(cidrSize); final long numericNetmask = netMaskFromCidr(cidrSizeNum); final long ipAddr = ip2Long(cidrAddress); final Long[] cidrlong = {ipAddr & numericNetmask, cidrSizeNum}; return cidrlong; } /** * @param cidrSize * @return * @throws CloudRuntimeException */ static long getCidrSizeFromString(final String cidrSize) throws CloudRuntimeException { long cidrSizeNum = -1; try { cidrSizeNum = Integer.parseInt(cidrSize); } catch (final NumberFormatException e) { throw new CloudRuntimeException("cidrsize is not a valid int: " + cidrSize, e); } if(cidrSizeNum > 32 || cidrSizeNum < 0) {// assuming IPv4 throw new CloudRuntimeException("cidr size out of range: " + cidrSizeNum); } return cidrSizeNum; } public static String getCidrSubNet(final String cidr) { if (cidr == null || cidr.isEmpty()) { return null; } final String[] cidrPair = cidr.split("\\/"); if (cidrPair.length != 2) { return null; } final String cidrAddress = cidrPair[0]; final String cidrSize = cidrPair[1]; if (!isValidIp(cidrAddress)) { return null; } long cidrSizeNum = getCidrSizeFromString(cidrSize); final long numericNetmask = netMaskFromCidr(cidrSizeNum); final String netmask = NetUtils.long2Ip(numericNetmask); return getSubNet(cidrAddress, netmask); } public static String getCidrNetmask(final long cidrSize) { final long numericNetmask = netMaskFromCidr(cidrSize); return long2Ip(numericNetmask); } public static String getCidrNetmask(final String cidr) { final String[] cidrPair = cidr.split("\\/"); final long guestCidrSize = Long.parseLong(cidrPair[1]); return getCidrNetmask(guestCidrSize); } public static String cidr2Netmask(final String cidr) { final String[] tokens = cidr.split("\\/"); return getCidrNetmask(Integer.parseInt(tokens[1])); } public static long getCidrSize(final String netmask) { final long ip = ip2Long(netmask); int count = 0; for (int i = 0; i < MAX_CIDR; i++) { if ((ip >> i & 0x1) == 0) { count++; } else { break; } } return MAX_CIDR - count; } public static boolean isValidPort(final String p) { try { final int port = Integer.parseInt(p); return !(port > 65535 || port < 1); } catch (final NumberFormatException e) { return false; } } public static boolean isValidPort(final int p) { return !(p > 65535 || p < 1); } public static boolean isValidLBPort(final String p) { try { final int port = Integer.parseInt(p); return !(port > 65535 || port < 1); } catch (final NumberFormatException e) { return false; } } public static boolean isValidProto(final String p) { final String proto = p.toLowerCase(); return proto.equals(TCP_PROTO) || proto.equals(UDP_PROTO) || proto.equals(ICMP_PROTO); } public static boolean isValidSecurityGroupProto(final String p) { final String proto = p.toLowerCase(); return proto.equals(TCP_PROTO) || proto.equals(UDP_PROTO) || proto.equals(ICMP_PROTO) || proto.equals(ALL_PROTO); } public static boolean isValidAlgorithm(final String p) { final String algo = p.toLowerCase(); return algo.equals("roundrobin") || algo.equals("leastconn") || algo.equals("source"); } public static boolean isValidAutoScaleAction(final String p) { final String action = p.toLowerCase(); return action.equals("scaleup") || action.equals("scaledown"); } public static String getLinkLocalNetMask() { return "255.255.0.0"; } public static String getLinkLocalGateway() { return "169.254.0.1"; } public static String getLinkLocalCIDR() { return "169.254.0.0/16"; } public static String[] getLinkLocalIPRange(final int size) { if (size > 16 || size <= 0) { return null; } /* reserve gateway */ final String[] range = getIpRangeFromCidr(getLinkLocalGateway(), MAX_CIDR - size); if (range[0].equalsIgnoreCase(getLinkLocalGateway())) { /* remove the gateway */ long ip = ip2Long(range[0]); ip += 1; range[0] = long2Ip(ip); } return range; } public static String getLinkLocalIpEnd() { final String[] cidrPair = getLinkLocalCIDR().split("\\/"); final String cidr = cidrPair[0]; return getIpRangeEndIpFromCidr(cidr, MAX_CIDR - Long.parseLong(cidrPair[1])); } public static String portRangeToString(final int portRange[]) { return Integer.toString(portRange[0]) + ":" + Integer.toString(portRange[1]); } public static boolean verifyDomainNameLabel(final String hostName, final boolean isHostName) { // must be between 1 and 63 characters long and may contain only the ASCII letters 'a' through 'z' (in a // case-insensitive manner), // the digits '0' through '9', and the hyphen ('-'). // Can not start with a hyphen and digit, and must not end with a hyphen // If it's a host name, don't allow to start with digit if (hostName.length() > 63 || hostName.length() < 1) { s_logger.warn("Domain name label must be between 1 and 63 characters long"); return false; } else if (!hostName.toLowerCase().matches("[a-z0-9-]*")) { s_logger.warn("Domain name label may contain only the ASCII letters 'a' through 'z' (in a case-insensitive manner)"); return false; } else if (hostName.startsWith("-") || hostName.endsWith("-")) { s_logger.warn("Domain name label can not start with a hyphen and digit, and must not end with a hyphen"); return false; } else if (isHostName && hostName.matches("^[0-9-].*")) { s_logger.warn("Host name can't start with digit"); return false; } return true; } public static boolean verifyDomainName(final String domainName) { // don't allow domain name length to exceed 190 chars (190 + 63 (max host name length) = 253 = max domainName length if (domainName.length() < 1 || domainName.length() > 190) { s_logger.trace("Domain name must be between 1 and 190 characters long"); return false; } if (domainName.startsWith(".") || domainName.endsWith(".")) { s_logger.trace("Domain name can't start or end with ."); return false; } final String[] domainNameLabels = domainName.split("\\."); for (int i = 0; i < domainNameLabels.length; i++) { if (!verifyDomainNameLabel(domainNameLabels[i], false)) { s_logger.warn("Domain name label " + domainNameLabels[i] + " is incorrect"); return false; } } return true; } public static String getDhcpRange(final String cidr) { final String[] splitResult = cidr.split("\\/"); final long size = Long.parseLong(splitResult[1]); return NetUtils.getIpRangeStartIpFromCidr(splitResult[0], size); } // Check if 2 CIDRs have exactly same IP Range public static boolean isSameIpRange(final String cidrA, final String cidrB) { if (!NetUtils.isValidCIDR(cidrA)) { s_logger.info("Invalid value of cidr " + cidrA); return false; } if (!NetUtils.isValidCIDR(cidrB)) { s_logger.info("Invalid value of cidr " + cidrB); return false; } final String[] cidrPairFirst = cidrA.split("\\/"); final String[] cidrPairSecond = cidrB.split("\\/"); final Long networkSizeFirst = Long.valueOf(cidrPairFirst[1]); final Long networkSizeSecond = Long.valueOf(cidrPairSecond[1]); final String ipRangeFirst[] = NetUtils.getIpRangeFromCidr(cidrPairFirst[0], networkSizeFirst); final String ipRangeSecond[] = NetUtils.getIpRangeFromCidr(cidrPairFirst[0], networkSizeSecond); final long startIpFirst = NetUtils.ip2Long(ipRangeFirst[0]); final long endIpFirst = NetUtils.ip2Long(ipRangeFirst[1]); final long startIpSecond = NetUtils.ip2Long(ipRangeSecond[0]); final long endIpSecond = NetUtils.ip2Long(ipRangeSecond[1]); if (startIpFirst == startIpSecond && endIpFirst == endIpSecond) { return true; } return false; } public static boolean validateGuestCidr(final String cidr) { // RFC 1918 - The Internet Assigned Numbers Authority (IANA) has reserved the // following three blocks of the IP address space for private internets: // 10.0.0.0 - 10.255.255.255 (10/8 prefix) // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) // RFC 6598 - The IETF detailed shared address space for use in ISP CGN // deployments and NAT devices that can handle the same addresses occurring both on inbound and outbound interfaces. // ARIN returned space to the IANA as needed for this allocation. // The allocated address block is 100.64.0.0/10 final String[] allowedNetBlocks = {"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10"}; if (!isValidCIDR(cidr)) { s_logger.warn("Cidr " + cidr + " is not valid"); return false; } for (String block: allowedNetBlocks) { if (isNetworkAWithinNetworkB(cidr, block)) { return true; } } // not in allowedNetBlocks - return false s_logger.warn("cidr " + cidr + " is not RFC 1918 or 6598 compliant"); return false; } public static boolean verifyInstanceName(final String instanceName) { //instance name for cloudstack vms shouldn't contain - and spaces if (instanceName.contains("-") || instanceName.contains(" ") || instanceName.contains("+")) { s_logger.warn("Instance name can not contain hyphen, spaces and \"+\" char"); return false; } return true; } public static boolean isNetworksOverlap(final String cidrA, final String cidrB) { try { Long[] cidrALong = cidrToLong(cidrA); Long[] cidrBLong = cidrToLong(cidrB); final long shift = MAX_CIDR - (cidrALong[1] > cidrBLong[1] ? cidrBLong[1] : cidrALong[1]); return cidrALong[0] >> shift == cidrBLong[0] >> shift; } catch (CloudRuntimeException e) { s_logger.error(e.getLocalizedMessage(),e); } return false; } public static boolean isValidS2SVpnPolicy(final String policyType, final String policys) { if (policyType == null || policyType.isEmpty()) { return false; } if (policys == null || policys.isEmpty()) { return false; } for (final String policy : policys.split(",")) { if (policy.isEmpty()) { return false; } final String cipherHash = policy.split(";")[0]; if (cipherHash.isEmpty()) { return false; } final String[] list = cipherHash.split("-"); if (list.length != 2) { return false; } final String cipher = list[0]; final String hash = list[1]; if (!cipher.matches("3des|aes128|aes192|aes256")) { return false; } if (!hash.matches("md5|sha1|sha256|sha384|sha512")) { return false; } String group = null; if (!policy.equals(cipherHash)) { group = policy.split(";")[1]; } if (group == null && policyType.toLowerCase().matches("ike")) { return false; // StrongSwan requires a DH group for the IKE policy } if (group != null && !group.matches("modp1024|modp1536|modp2048|modp3072|modp4096|modp6144|modp8192")) { return false; } } return true; } public static boolean isValidCidrList(final String cidrList) { for (final String guestCidr : cidrList.split(",")) { if (!isValidCIDR(guestCidr)) { return false; } } return true; } public static boolean validateGuestCidrList(final String guestCidrList) { for (final String guestCidr : guestCidrList.split(",")) { if (!validateGuestCidr(guestCidr)) { return false; } } return true; } public static boolean validateIcmpType(final long icmpType) { //Source - http://www.erg.abdn.ac.uk/~gorry/course/inet-pages/icmp-code.html if (!(icmpType >= 0 && icmpType <= 255)) { s_logger.warn("impcType is not within 0-255 range"); return false; } return true; } public static boolean validateIcmpCode(final long icmpCode) { //Source - http://www.erg.abdn.ac.uk/~gorry/course/inet-pages/icmp-code.html if (!(icmpCode >= 0 && icmpCode <= 15)) { s_logger.warn("Icmp code should be within 0-15 range"); return false; } return true; } public static boolean isValidIpv6(final String ip) { try { IPv6Address.fromString(ip); } catch (final IllegalArgumentException ex) { return false; } return true; } public static boolean isValidIp6Cidr(final String ip6Cidr) { try { IPv6Network.fromString(ip6Cidr); } catch (final IllegalArgumentException ex) { return false; } return true; } public static int getIp6CidrSize(final String ip6Cidr) { IPv6Network network = null; try { network = IPv6Network.fromString(ip6Cidr); } catch (final IllegalArgumentException ex) { return 0; } return network.getNetmask().asPrefixLength(); } // Can cover 127 bits public static String getIp6FromRange(final String ip6Range) { final String[] ips = ip6Range.split("-"); final String startIp = ips[0]; final IPv6Address start = IPv6Address.fromString(startIp); final BigInteger gap = countIp6InRange(ip6Range); BigInteger next = new BigInteger(gap.bitLength(), s_rand); while (next.compareTo(gap) >= 0) { next = new BigInteger(gap.bitLength(), s_rand); } InetAddress resultAddr = null; final BigInteger startInt = convertIPv6AddressToBigInteger(start); if (startInt != null) { final BigInteger resultInt = startInt.add(next); try { resultAddr = InetAddress.getByAddress(resultInt.toByteArray()); } catch (final UnknownHostException e) { return null; } } if( resultAddr != null) { final IPv6Address ip = IPv6Address.fromInetAddress(resultAddr); return ip.toString(); } return null; } //RFC3315, section 9.4 public static String getDuidLL(final String macAddress) { final String duid = "00:03:00:01:" + macAddress; return duid; } private static BigInteger convertIPv6AddressToBigInteger(final IPv6Address addr) { InetAddress inetAddr; try { inetAddr = addr.toInetAddress(); } catch (final UnknownHostException e) { return null; } return new BigInteger(inetAddr.getAddress()); } // Can cover 127 bits public static BigInteger countIp6InRange(final String ip6Range) { if (ip6Range == null) { return null; } final String[] ips = ip6Range.split("-"); final String startIp = ips[0]; String endIp = ips[0]; if (ips.length > 1) { endIp = ips[1]; } try { final BigInteger startInt = convertIPv6AddressToBigInteger(IPv6Address.fromString(startIp)); final BigInteger endInt = convertIPv6AddressToBigInteger(IPv6Address.fromString(endIp)); if (endInt != null && startInt != null && startInt.compareTo(endInt) <= 0) { return endInt.subtract(startInt).add(BigInteger.ONE); } } catch (final IllegalArgumentException ex) { s_logger.error("Failed to convert a string to an IPv6 address", ex); } return null; } public static boolean isIp6InRange(final String ip6, final String ip6Range) { if (ip6Range == null) { return false; } final String[] ips = ip6Range.split("-"); final String startIp = ips[0]; String endIp = null; if (ips.length > 1) { endIp = ips[1]; } final IPv6Address start = IPv6Address.fromString(startIp); final IPv6Address end = IPv6Address.fromString(endIp); final IPv6Address ip = IPv6Address.fromString(ip6); if (start.compareTo(ip) <= 0 && end.compareTo(ip) >= 0) { return true; } return false; } public static boolean isIp6InNetwork(final String ip6, final String ip6Cidr) { IPv6Network network = null; try { network = IPv6Network.fromString(ip6Cidr); } catch (final IllegalArgumentException ex) { return false; } final IPv6Address ip = IPv6Address.fromString(ip6); return network.contains(ip); } public static boolean isIp6RangeOverlap(final String ipRange1, final String ipRange2) { String[] ips = ipRange1.split("-"); final String startIp1 = ips[0]; String endIp1 = null; if (ips.length > 1) { endIp1 = ips[1]; } final IPv6Address start1 = IPv6Address.fromString(startIp1); final IPv6Address end1 = IPv6Address.fromString(endIp1); final IPv6AddressRange range1 = IPv6AddressRange.fromFirstAndLast(start1, end1); ips = ipRange2.split("-"); final String startIp2 = ips[0]; String endIp2 = null; if (ips.length > 1) { endIp2 = ips[1]; } final IPv6Address start2 = IPv6Address.fromString(startIp2); final IPv6Address end2 = IPv6Address.fromString(endIp2); final IPv6AddressRange range2 = IPv6AddressRange.fromFirstAndLast(start2, end2); return range1.overlaps(range2); } public static String getNextIp6InRange(final String currentIp, final String ipRange) { final String[] ips = ipRange.split("-"); final String startIp = ips[0]; String endIp = null; if (ips.length > 1) { endIp = ips[1]; } final IPv6Address start = IPv6Address.fromString(startIp); final IPv6Address end = IPv6Address.fromString(endIp); final IPv6Address current = IPv6Address.fromString(currentIp); IPv6Address result = null; if (current.equals(end)) { result = start; } else { result = current.add(1); } String resultIp = null; if (result != null) { resultIp = result.toString(); } return resultIp; } public static String standardizeIp6Address(final String ip6Addr) { try { return IPv6Address.fromString(ip6Addr).toString(); } catch (final IllegalArgumentException ex) { throw new IllegalArgumentException("Invalid IPv6 address: " + ex.getMessage()); } } public static String standardizeIp6Cidr(final String ip6Cidr){ try { return IPv6Network.fromString(ip6Cidr).toString(); } catch (final IllegalArgumentException ex) { throw new IllegalArgumentException("Invalid IPv6 CIDR: " + ex.getMessage()); } } static final String VLAN_PREFIX = "vlan://"; static final int VLAN_PREFIX_LENGTH = VLAN_PREFIX.length(); public static boolean isValidVlan(String vlan) { if (null == vlan || "".equals(vlan)) { return false; } if (vlan.startsWith(VLAN_PREFIX)) { vlan = vlan.substring(VLAN_PREFIX_LENGTH); } try { final int vnet = Integer.parseInt(vlan); if (vnet <= 0 || vnet >= 4095) { // the valid range is 1- 4094 return false; } return true; } catch (final NumberFormatException e) { return false; } } static final String VLAN_UNTAGGED = "untagged"; public static boolean isSameIsolationId(String one, String other) { // check nulls // check empty strings if ((one == null || one.isEmpty()) && (other == null || other.isEmpty())) { return true; } if (one == null || other == null) { return false; } // check 'untagged' if (one.contains(VLAN_UNTAGGED) && other.contains(VLAN_UNTAGGED)) { return true; } // if one is a number check the other as number and as 'vlan://' + number if (one.startsWith(VLAN_PREFIX)) { one = one.substring(VLAN_PREFIX_LENGTH); } if (other.startsWith(VLAN_PREFIX)) { other = other.substring(VLAN_PREFIX_LENGTH); } // check valid uris or numbers if (one.equalsIgnoreCase(other)) { return true; } return false; } // Attention maintainers: these pvlan functions should take into account code // in Networks.BroadcastDomainType, where URI construction is done for other // types of BroadcastDomainTypes public static URI generateUriForPvlan(final String primaryVlan, final String isolatedPvlan) { return URI.create("pvlan://" + primaryVlan + "-i" + isolatedPvlan); } public static String getPrimaryPvlanFromUri(final URI uri) { final String[] vlans = uri.getHost().split("-"); if (vlans.length < 1) { return null; } return vlans[0]; } public static String getIsolatedPvlanFromUri(final URI uri) { final String[] vlans = uri.getHost().split("-"); if (vlans.length < 2) { return null; } for (final String vlan : vlans) { if (vlan.startsWith("i")) { return vlan.replace("i", " ").trim(); } } return null; } public static String generateMacOnIncrease(final String baseMac, final long l) { long mac = mac2Long(baseMac); if (l > 0xFFFFl) { return null; } mac = mac + (l << 24); mac = mac & 0x06FFFFFFFFFFl; return long2Mac(mac); } public static boolean isIpWithtInCidrRange(final String ipAddress, final String cidr) { if (!isValidIp(ipAddress)) { return false; } if (!isValidCIDR(cidr)) { return false; } // check if the gatewayip is the part of the ip range being added. // RFC 3021 - 31-Bit Prefixes on IPv4 Point-to-Point Links // GW Netmask Stat IP End IP // 192.168.24.0 - 255.255.255.254 - 192.168.24.0 - 192.168.24.1 // https://tools.ietf.org/html/rfc3021 // Added by Wilder Rodrigues final SubnetUtils subnetUtils = new SubnetUtils(cidr); subnetUtils.setInclusiveHostCount(true); final boolean isInRange = subnetUtils.getInfo().isInRange(ipAddress); return isInRange; } public static Boolean IsIpEqualToNetworkOrBroadCastIp(final String requestedIp, final String cidr, final long size) { assert size < MAX_CIDR : "You do know this is not for ipv6 right? Keep it smaller than 32 but you have " + size; final long ip = ip2Long(cidr); final long startNetMask = ip2Long(getCidrNetmask(size)); final long start = ip & startNetMask; long end = start; end = end >> MAX_CIDR - size; end++; end = (end << MAX_CIDR - size) - 1; final long reqIp = ip2Long(requestedIp); if (reqIp == start || reqIp == end) { return true; } return false; } public static boolean isNetworkorBroadcastIP(String ip, String netmask){ String cidr = getCidrFromGatewayAndNetmask(ip,netmask); final SubnetUtils subnetUtils = new SubnetUtils(cidr); subnetUtils.setInclusiveHostCount(false); final boolean isInRange = subnetUtils.getInfo().isInRange(ip); return !isInRange; } public static IPv6Address EUI64Address(final IPv6Network cidr, final String macAddress) { if (cidr.getNetmask().asPrefixLength() > 64) { throw new IllegalArgumentException("IPv6 subnet " + cidr.toString() + " is not 64 bits or larger in size"); } String mac[] = macAddress.toLowerCase().split(":"); return IPv6Address.fromString(cidr.getFirst().toString() + Integer.toHexString(Integer.parseInt(mac[0], 16) ^ 2) + mac[1] + ":" + mac[2] + "ff:fe" + mac[3] +":" + mac[4] + mac[5]); } public static IPv6Address EUI64Address(final String cidr, final String macAddress) { return EUI64Address(IPv6Network.fromString(cidr), macAddress); } public static IPv6Address ipv6LinkLocal(final String macAddress) { return EUI64Address(IPv6Network.fromString("fe80::/64"), macAddress); } }