/***************************************************************************
* Copyright (c) 2012-2014 VMware, Inc. All Rights Reserved.
* Licensed 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.vmware.bdd.utils;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.List;
import com.vmware.bdd.apitypes.IpBlock;
import com.vmware.bdd.exception.BddException;
import java.util.regex.Pattern;
public class IpAddressUtil {
public static boolean isValidIp(long addr) {
InetAddress ip = getAddressFromLong(addr);
return !ip.isLoopbackAddress() && !ip.isMulticastAddress();
}
public static boolean isValidIp(String ipAddr) {
Long ip = getAddressAsLong(ipAddr);
if (ipAddr == null) {
return false;
}
return isValidIp(ip);
}
public static boolean isValidIp(long netmask, long addr) {
long hostPart = addr & ~netmask;
int bits = 32 - getNetworkPrefixBits(netmask);
// should not be network and broadcast addresses (all 0 and all 1)
if (hostPart == 0 || hostPart == (1L << bits) -1) {
return false;
}
return isValidIp(addr);
}
public static boolean isValidIp(String netmask, String ipAddr) {
Long mask = getAddressAsLong(netmask);
Long ip = getAddressAsLong(ipAddr);
if (mask == null || ipAddr == null) {
return false;
}
return isValidIp(mask, ip);
}
public static InetAddress getAddressFromLong(Long addr) {
if (addr == null) {
return null;
}
AuAssert.check(addr >= 0 && addr < (1L << 32));
byte[] bytes =
new byte[] { (byte) ((addr >> 24) & 0xff), (byte) ((addr >> 16) & 0xff),
(byte) ((addr >> 8) & 0xff), (byte) (addr & 0xff) };
try {
return InetAddress.getByAddress(bytes);
} catch (UnknownHostException e) {
AuAssert.unreachable();
return null;
}
}
public static Long getAddressAsLong(InetAddress addr) {
if (addr == null) {
return null;
}
byte[] bytes = addr.getAddress();
AuAssert.check(bytes.length == 4); // ipv4 only
// byte & 0xff is a hack to use java unsigned byte
return ((bytes[0] & 0xffL) << 24) + ((bytes[1] & 0xffL) << 16)
+ ((bytes[2] & 0xffL) << 8) + (bytes[3] & 0xffL);
}
/**
* Convert an string to an internal representation as long. The accepted IP
* address format is not strictly consistent to RFC standards.
*
* @param addr
* address to convert
* @return internal representation, null if the input is not a valid IP
* address
*/
public static Long getAddressAsLong(String addr) {
if (addr == null) {
return null;
}
String[] parts = addr.split("\\.");
if (parts.length != 4) {
return null;
}
long ip = 0;
try {
for (int i = 0; i < 4; ++i) {
long part = Integer.parseInt(parts[i]);
if (part < 0 || part > 255) {
return null;
}
ip += part << ((3 - i) * 8);
}
} catch (NumberFormatException ex) {
return null;
}
return ip;
}
/**
* Get the number of network prefix bits from a netmask. This function does
* not validate whether the netmask is really usufull or not, for example, it
* will treat "255.255.255.255", "255.255.255.254", "255.255.255.252" as
* valid netmasks though they can not be used practically.
*
* @param netmask
* netmask
* @return a 1 - 32 integer indicates the network part length, -1 when the
* input is not a valid netmask.
*/
public static int getNetworkPrefixBits(long netmask) {
AuAssert.check(netmask >= 0 && netmask < (1L << 32));
int i = 0;
long tmp = netmask;
while (i <= 32) {
if ((tmp & 1L) == 1L) {
long expected = ((1L << 32) - 1L) >> i;
if ((expected & tmp) == expected) {
return 32 - i;
} else {
return -1;
}
}
++i;
tmp = tmp >> 1;
}
return -1;
}
public static boolean isValidNetmask(long netmask) {
return getNetworkPrefixBits(netmask) != -1;
}
public static boolean isValidNetmask(String netmask) {
Long internal = getAddressAsLong(netmask);
return internal!= null && getNetworkPrefixBits(internal) != -1;
}
/**
* Check whether an IP address is valid in a specified network.
*
* @param network
* network address
* @param netmask
* network netmask
* @param ip
* ip to be checked
* @return whether ip is valid in this network
*/
public static boolean networkContains(long network, long netmask, long ip) {
return network == (netmask & ip);
}
public static void verifyIPBlocks(List<IpBlock> ipBlocks, final long netmask) {
AuAssert.check(ipBlocks != null, "Spring should guarantee this");
for (IpBlock blk : ipBlocks) {
Long begin = getAddressAsLong(blk.getBeginIp());
Long end = getAddressAsLong(blk.getEndIp());
if (begin == null || end == null || begin > end
|| !isValidIp(netmask, begin) || !isValidIp(netmask, end)) {
throw BddException.INVALID_PARAMETER("IP block",
"[" + blk.getBeginIp() + ", " + blk.getEndIp() + "]");
}
}
}
/**
* Considering one host may have more than 1 nic(each nic may have ipv4 or ipv6 address)
* this function will traverse all the nics and get the first none loopback ipv4 address
* @return: the first none loopback address of the host
* 0.0.0.0 if failed
*/
public static String getHostManagementIp() {
Enumeration<NetworkInterface> interfaces;
try {
interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface i = (NetworkInterface) interfaces.nextElement();
for (Enumeration<InetAddress> inetAddresses = i.getInetAddresses(); inetAddresses.hasMoreElements();) {
InetAddress addr = (InetAddress) inetAddresses.nextElement();
if (!addr.isLoopbackAddress()) {
if (addr instanceof Inet4Address) {
return addr.getHostAddress();
}
}
}
}
} catch (SocketException e) {
return Constants.NULL_IPV4_ADDRESS;
}
return Constants.NULL_IPV4_ADDRESS;
}
}