org.nervousync.utils.IPUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of utils-jdk11 Show documentation
Show all versions of utils-jdk11 Show documentation
Java utility collections, development by Nervousync Studio (NSYC)
/*
* Licensed to the Nervousync Studio (NSYC) 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 org.nervousync.utils;
import jakarta.annotation.Nonnull;
import org.nervousync.beans.ip.IPRange;
import org.nervousync.commons.Globals;
import org.nervousync.commons.RegexGlobals;
import org.nervousync.enumerations.ip.IPType;
import java.math.BigInteger;
/**
* IP Address Utilities
*
* Current utilities implements features:
* Calculate IP range by given address and CIDR value
* Convert between netmask address and CIDR value
* Convert between IPv4 and IPv6
* Convert between IP address and BigInteger(for support IPv6)
* Expand the combo IPv6 address
*
* IP地址工具
*
* 此工具集实现以下功能:
* 根据给定的地址和CIDR,计算IP地址范围
* 在子网掩码和CIDR之间转换数据
* 在IPv4和IPv6之间转换数据
* 在IP地址和BigInteger之间转换数据
* 将压缩显示的IPv6地址展开
*
*
* @author Steven Wee [email protected]
* @version $Revision: 1.2.0 $ $Date: Aug 15, 2022 16:23:13 $
*/
public final class IPUtils {
/**
* Split character for IPv4 address
* IPv4地址的间隔符
*/
private static final String SPLIT_CHARACTER_IPV4 = ".";
/**
* Split character for IPv6 address
* IPv6地址的间隔符
*/
private static final String SPLIT_CHARACTER_IPV6 = ":";
/**
* Split character for combo IPv6 address
* IPv6压缩地址的间隔符
*/
private static final String SPLIT_COMBO_CHARACTER_IPV6 = "::";
/**
* Private constructor for IPUtils
* IP地址工具集的私有构造方法
*/
private IPUtils() {
}
/**
* Calculate IP range by given address and CIDR value
* 根据给定的地址和CIDR,计算IP地址范围
*
* @param ipAddress IP address
* IP地址
* @param cidr CIDR value
* CIDR值
*
* @return Calculate result of IPRange instance
* 根据计算结果生成的IPRange对象
*/
public static IPRange calcRange(@Nonnull final String ipAddress, final int cidr) {
IPRange ipRange = new IPRange();
final String beginAddress;
final String endAddress;
if (ipAddress.contains(SPLIT_CHARACTER_IPV6)) {
ipRange.setIpType(IPType.IPv6);
beginAddress = beginIPv6(ipAddress, cidr);
endAddress = endIPv6(beginAddress, cidr);
} else {
ipRange.setIpType(IPType.IPv4);
String netmask = CIDRToNetmask(cidr);
beginAddress = beginIPv4(ipAddress, netmask);
endAddress = endIPv4(beginAddress, netmask);
}
ipRange.setBeginAddress(beginAddress);
ipRange.setEndAddress(endAddress);
return ipRange;
}
/**
* Convert netmask string to CIDR value
* 转换子网掩码字符串为CIDR值
*
* @param netmask IP address
* IP地址
*
* @return CIDR value
* CIDR值
*/
public static int NetmaskToCIDR(@Nonnull final String netmask) {
int result = 0;
String[] splitItems = StringUtils.tokenizeToStringArray(netmask, SPLIT_CHARACTER_IPV4);
for (String splitItem : splitItems) {
int number = Integer.parseInt(splitItem);
while (number > 0) {
if ((number % 2) == 1) {
result++;
}
number /= 2;
}
}
return result;
}
/**
* Convert CIDR value to netmask string
* 转换CIDR值为子网掩码字符串
*
* @param cidr CIDR value
* CIDR值
*
* @return Netmask address string
* 子网掩码字符串
*/
public static String CIDRToNetmask(final int cidr) {
int calcCIDR = cidr;
if (calcCIDR >= 0 && calcCIDR <= 32) {
StringBuilder stringBuilder = new StringBuilder();
int index = 0;
while (index < 4) {
stringBuilder.append(SPLIT_CHARACTER_IPV4).append(fillBitsFromLeft(calcCIDR));
calcCIDR -= 8;
if (calcCIDR < 0) {
calcCIDR = 0;
}
index++;
}
return stringBuilder.substring(1);
}
return Globals.DEFAULT_VALUE_STRING;
}
/**
* Check given IP address string is IPv4 address
* 检查给定的IP地址字符串是合法的IPv4地址
*
* @param ipAddress IP address string
* IP地址字符串
*
* @return Check result. true
for valid, false
for invalid
* 检查结果。true
合法地址,false
非法地址
*/
public static boolean isIPv4Address(@Nonnull final String ipAddress) {
return StringUtils.matches(ipAddress, RegexGlobals.IPV4_REGEX);
}
/**
* Check given IP address string is IPv6 address
* 检查给定的IP地址字符串是合法的IPv6地址
*
* @param ipAddress IP address string
* IP地址字符串
*
* @return Check result. true
for valid, false
for invalid
* 检查结果。true
合法地址,false
非法地址
*/
public static boolean isIPv6Address(@Nonnull final String ipAddress) {
return StringUtils.matches(ipAddress, RegexGlobals.IPV6_REGEX)
|| StringUtils.matches(ipAddress, RegexGlobals.IPV6_COMPRESS_REGEX);
}
/**
* Convert given IPv4 address string to compatible IPv6 address
* 转换给定的IPv4地址为IPv6兼容地址
*
* @param ipAddress IPv4 address string
* IP地址字符串
*
* @return Compatible IPv6 address string
* 转换后的IPv6兼容地址
*/
public static String IPv4ToCompatibleIPv6(@Nonnull final String ipAddress) {
if (StringUtils.matches(ipAddress, RegexGlobals.IPV4_REGEX)) {
return SPLIT_COMBO_CHARACTER_IPV6 + ipAddress;
}
return null;
}
/**
* Convert given IPv4 address string to IPv6 address
* 转换给定的IPv4地址为IPv6兼容地址
*
* @param ipAddress IPv4 address string
* IP地址字符串
*
* @return IPv6 address string
* 转换后的IPv6地址
*/
public static String IPv4ToIPv6(@Nonnull final String ipAddress) {
return IPv4ToIPv6(ipAddress, Boolean.TRUE);
}
/**
* Convert given IPv4 address string to IPv6 address
* 转换给定的IPv4地址为IPv6兼容地址
*
* @param ipAddress IPv4 address string
* IP地址字符串
* @param collapse Collapse converted IPv6 address
* 是否简写IPv6地址
*
* @return IPv6 address string
* 转换后的IPv6地址
*/
public static String IPv4ToIPv6(@Nonnull final String ipAddress, final boolean collapse) {
if (StringUtils.matches(ipAddress, RegexGlobals.IPV4_REGEX)) {
String[] splitAddress = StringUtils.tokenizeToStringArray(ipAddress, SPLIT_CHARACTER_IPV4);
StringBuilder stringBuilder;
if (collapse) {
stringBuilder = new StringBuilder(SPLIT_CHARACTER_IPV6);
} else {
stringBuilder = new StringBuilder("0000:0000:0000:0000:0000:0000");
}
int index = 0;
for (String addressItem : splitAddress) {
if (index % 2 == 0) {
stringBuilder.append(SPLIT_CHARACTER_IPV6);
}
stringBuilder.append(Integer.toHexString(Integer.parseInt(addressItem)));
index++;
}
return stringBuilder.toString().toUpperCase();
}
return null;
}
/**
* Convert given IP address string to byte array
* 转换给定的IP地址为字节数组
*
* @param ipAddress IP address string
* IP地址字符串
*
* @return Converted byte array
* 转换后的字节数组
*/
public static byte[] IPToBytes(@Nonnull final String ipAddress) {
if (StringUtils.matches(ipAddress, RegexGlobals.IPV4_REGEX)) {
return IPv4ToBytes(ipAddress);
} else if (StringUtils.matches(ipAddress, RegexGlobals.IPV6_REGEX)
|| StringUtils.matches(ipAddress, RegexGlobals.IPV6_COMPRESS_REGEX)) {
return IPv6ToBytes(ipAddress);
} else {
return new byte[0];
}
}
/**
* Convert given IPv4 address string to byte array
* 转换给定的IPv4地址为字节数组
*
* @param ipAddress IPv4 address string
* IPv4地址字符串
*
* @return Converted byte array
* 转换后的字节数组
*/
public static byte[] IPv4ToBytes(@Nonnull final String ipAddress) {
if (StringUtils.matches(ipAddress, RegexGlobals.IPV4_REGEX)) {
String[] splitAddress = StringUtils.tokenizeToStringArray(ipAddress, SPLIT_CHARACTER_IPV4);
byte[] addressBytes = new byte[4];
addressBytes[0] = (byte) Integer.parseInt(splitAddress[0]);
addressBytes[1] = (byte) Integer.parseInt(splitAddress[1]);
addressBytes[2] = (byte) Integer.parseInt(splitAddress[2]);
addressBytes[3] = (byte) Integer.parseInt(splitAddress[3]);
return addressBytes;
}
return null;
}
/**
* Convert given IPv6 address string to byte array
* 转换给定的IPv6地址为字节数组
*
* @param ipAddress IPv6 address string
* IPv6地址字符串
*
* @return Converted byte array
* 转换后的字节数组
*/
public static byte[] IPv6ToBytes(@Nonnull final String ipAddress) {
if (StringUtils.matches(ipAddress, RegexGlobals.IPV6_REGEX)
|| StringUtils.matches(ipAddress, RegexGlobals.IPV6_COMPRESS_REGEX)) {
String ipv6Address = expandIPv6(ipAddress);
String[] splitAddress = StringUtils.tokenizeToStringArray(ipv6Address, SPLIT_CHARACTER_IPV6);
byte[] addressBytes = new byte[16];
int index = 0;
for (String address : splitAddress) {
int tmp = Integer.parseInt(address, 16);
addressBytes[index] = (byte) (tmp >> 8);
addressBytes[index + 1] = (byte) tmp;
index += 2;
}
return addressBytes;
}
return null;
}
/**
* Expand the given combo IPv6 address string
* 展开给定的缩略IPv6地址字符串
*
* @param ipAddress Combo IPv6 address string
* 缩略的IPv6地址字符串
*
* @return Expanded IPv6 address string
* 展开后的IPv6地址字符串
*/
public static String expandIPv6(@Nonnull final String ipAddress) {
if (StringUtils.matches(ipAddress, RegexGlobals.IPV6_COMPRESS_REGEX)) {
int sigCount = StringUtils.countOccurrencesOf(ipAddress, SPLIT_CHARACTER_IPV6);
int expandCount = 8 - sigCount;
int position = 0;
StringBuilder stringBuilder = new StringBuilder();
while (true) {
int index = ipAddress.indexOf(SPLIT_CHARACTER_IPV6, position);
if (index == Globals.DEFAULT_VALUE_INT) {
stringBuilder.append(SPLIT_CHARACTER_IPV6).append(ipAddress.substring(position));
break;
} else {
if (index == position) {
while (expandCount > 0) {
stringBuilder.append(":0");
expandCount--;
}
} else {
stringBuilder.append(SPLIT_CHARACTER_IPV6).append(ipAddress, position, index);
}
position = index + 1;
}
}
return stringBuilder.substring(1);
}
return ipAddress;
}
/**
* Convert given IP address string to BigInteger instance
* 转换给定的IP地址为BigInteger实例对象
*
* @param ipAddress IP address string
* IP地址字符串
*
* @return Converted BigInteger instance
* 转换后的BigInteger实例对象
*/
public static BigInteger IPtoBigInteger(@Nonnull final String ipAddress) {
if (StringUtils.matches(ipAddress, RegexGlobals.IPV4_REGEX)) {
return IPv4ToBigInteger(ipAddress);
} else {
return IPv6ToBigInteger(ipAddress);
}
}
/**
* Convert given IPv4 address string to BigInteger instance
* 转换给定的IPv4地址为BigInteger实例对象
*
* @param ipAddress IPv4 address string
* IPv4地址字符串
*
* @return Converted BigInteger instance
* 转换后的BigInteger实例对象
*/
public static BigInteger IPv4ToBigInteger(@Nonnull final String ipAddress) {
if (StringUtils.matches(ipAddress, RegexGlobals.IPV4_REGEX)) {
String[] splitAddress = StringUtils.tokenizeToStringArray(ipAddress, SPLIT_CHARACTER_IPV4);
if (splitAddress.length == 4) {
long result = 0L;
for (int i = 0; i < splitAddress.length; i++) {
result += (Long.parseLong(splitAddress[i]) << 8 * (3 - i));
}
return BigInteger.valueOf(result);
}
}
return BigInteger.ZERO;
}
/**
* Convert given IPv6address string to BigInteger instance
* 转换给定的IPv6地址为BigInteger实例对象
*
* @param ipAddress IPv6 address string
* IPv6地址字符串
*
* @return Converted BigInteger instance
* 转换后的BigInteger实例对象
*/
public static BigInteger IPv6ToBigInteger(@Nonnull final String ipAddress) {
String fullAddress = expandIgnore(ipAddress);
if (StringUtils.matches(fullAddress, RegexGlobals.IPV6_REGEX)) {
String[] splitAddress = StringUtils.tokenizeToStringArray(fullAddress, SPLIT_CHARACTER_IPV6);
BigInteger bigInteger = BigInteger.ZERO;
int index = 0;
for (String split : splitAddress) {
BigInteger currentInteger;
if (StringUtils.matches(split, RegexGlobals.IPV4_REGEX)) {
currentInteger = IPv4ToBigInteger(split);
} else {
currentInteger = BigInteger.valueOf(Long.valueOf(split, 16));
}
if (currentInteger == null) {
return BigInteger.ZERO;
}
bigInteger = bigInteger.add(currentInteger.shiftLeft(16 * (splitAddress.length - index - 1)));
index++;
}
return bigInteger;
}
return BigInteger.ZERO;
}
/**
* Convert given BigInteger instance to IPv4 address string
* 转换给定的BigInteger实例对象为IPv4地址字符串
*
* @param bigInteger BigInteger instance
* BigInteger实例对象
*
* @return Converted IPv4 address string
* 转换后的IPv4地址字符串
*/
public static String BigIntegerToIPv4(@Nonnull final BigInteger bigInteger) {
StringBuilder ipv4Address = new StringBuilder();
BigInteger calcInteger = new BigInteger(bigInteger.toByteArray());
BigInteger ff = BigInteger.valueOf(0xFFL);
for (int i = 0; i < 4; i++) {
ipv4Address.insert(0, SPLIT_CHARACTER_IPV4 + calcInteger.and(ff));
calcInteger = calcInteger.shiftRight(8);
}
return ipv4Address.substring(1);
}
/**
* Convert given BigInteger instance to IPv6 address string
* 转换给定的BigInteger实例对象为IPv6地址字符串
*
* @param bigInteger BigInteger instance
* BigInteger实例对象
*
* @return Converted IPv6 address string
* 转换后的IPv6地址字符串
*/
public static String BigIntegerToIPv6Address(@Nonnull final BigInteger bigInteger) {
StringBuilder ipv6Address = new StringBuilder();
BigInteger calcInteger = new BigInteger(bigInteger.toByteArray());
BigInteger ff = BigInteger.valueOf(0xFFFFL);
for (int i = 0; i < 8; i++) {
ipv6Address.insert(0, SPLIT_CHARACTER_IPV6 + calcInteger.and(ff).toString(16));
calcInteger = calcInteger.shiftRight(16);
}
return ipv6Address.substring(1).replaceFirst(RegexGlobals.IPV6_COMPRESS_REGEX, SPLIT_COMBO_CHARACTER_IPV6);
}
/**
* Expand the given combo IPv6 address string and append 0
* 展开给定的缩略IPv6地址字符串并填充0
*
* @param ipv6Address Combo IPv6 address string
* 缩略的IPv6地址字符串
*
* @return Expanded IPv6 address string
* 展开后的IPv6地址字符串
*/
public static String expandIgnore(@Nonnull final String ipv6Address) {
String resultAddress = ipv6Address;
if (resultAddress.contains("::")) {
int count = StringUtils.countOccurrencesOf(resultAddress, SPLIT_CHARACTER_IPV6);
resultAddress = StringUtils.replace(resultAddress, SPLIT_COMBO_CHARACTER_IPV6,
":0000".repeat(Math.max(0, 8 - count)) + SPLIT_CHARACTER_IPV6);
if (resultAddress.startsWith(SPLIT_CHARACTER_IPV6)) {
resultAddress = "0000" + resultAddress;
}
if (resultAddress.endsWith(SPLIT_CHARACTER_IPV6)) {
resultAddress += "0000";
}
}
String[] addressItems = StringUtils.delimitedListToStringArray(resultAddress, SPLIT_CHARACTER_IPV6);
StringBuilder stringBuilder = new StringBuilder();
for (String addressItem : addressItems) {
StringBuilder addressItemBuilder = new StringBuilder(addressItem);
while (addressItemBuilder.length() < 4) {
addressItemBuilder.insert(0, "0");
}
addressItem = addressItemBuilder.toString();
stringBuilder.append(SPLIT_CHARACTER_IPV6).append(addressItem);
}
return stringBuilder.substring(1);
}
/**
* Calculate the begin IP address by given IP address and netmask string
* 根据给定的IP地址和子网掩码字符串计算起始IP地址
*
* @param ipAddress IP address string
* IP地址字符串
* @param netmask IP address
* IP地址
*
* @return Begin IPv4 address string
* 起始的IPv4地址字符串
*/
private static String beginIPv4(@Nonnull final String ipAddress, @Nonnull final String netmask) {
String[] addressItems = StringUtils.tokenizeToStringArray(ipAddress, SPLIT_CHARACTER_IPV4);
String[] maskItems = StringUtils.tokenizeToStringArray(netmask, SPLIT_CHARACTER_IPV4);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 4; i++) {
int itemValue = i < addressItems.length ? Integer.parseInt(addressItems[i])
: Globals.INITIALIZE_INT_VALUE;
int beginItem = itemValue & Integer.parseInt(maskItems[i]);
if (itemValue == 0 && i == 3) {
beginItem++;
}
stringBuilder.append(SPLIT_CHARACTER_IPV4).append(beginItem);
}
return stringBuilder.substring(1);
}
/**
* Calculate the end IP address by given IP address and netmask string
* 根据给定的IP地址和子网掩码字符串计算起始IP地址
*
* @param beginIP Begin IP address string
* 起始IP地址字符串
* @param netmask IP address
* IP地址
*
* @return End IPv4 address string
* 终止的IPv4地址字符串
*/
private static String endIPv4(@Nonnull final String beginIP, @Nonnull final String netmask) {
String[] addressItems = StringUtils.tokenizeToStringArray(beginIP, SPLIT_CHARACTER_IPV4);
String[] maskItems = StringUtils.tokenizeToStringArray(netmask, SPLIT_CHARACTER_IPV4);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 4; i++) {
int endItem = 255 - Integer.parseInt(addressItems[i]) ^ Integer.parseInt(maskItems[i]);
stringBuilder.append(SPLIT_CHARACTER_IPV4).append(endItem);
}
return stringBuilder.substring(1);
}
/**
* Calculate the begin IPv6 address by given IP address and netmask string
* 根据给定的IP地址和子网掩码字符串计算起始IP地址
*
* @param ipAddress IP address string
* IP地址字符串
* @param cidr CIDR value
* CIDR值
*
* @return Begin IPv6 address string
* 起始的IPv6地址字符串
*/
private static String beginIPv6(@Nonnull final String ipAddress, final int cidr) {
if (cidr >= Globals.INITIALIZE_INT_VALUE && cidr <= 128) {
String hexAddress = StringUtils.replace(expandIgnore(ipAddress), SPLIT_CHARACTER_IPV6, Globals.DEFAULT_VALUE_STRING);
StringBuilder baseIP = new StringBuilder(hexToBin(hexAddress).substring(Globals.INITIALIZE_INT_VALUE, cidr));
while (baseIP.length() < 128) {
baseIP.append("0");
}
return binToHex(baseIP.toString());
}
return Globals.DEFAULT_VALUE_STRING;
}
/**
* Calculate the end IPv6 address by given begin IPv6 address and netmask string
* 根据给定的IP地址和子网掩码字符串计算起始IP地址
*
* @param beginIP Begin IPv6 address string
* 起始IPv6地址字符串
* @param cidr CIDR value
* CIDR值
*
* @return End IPv6 address string
* 终止的IPv6地址字符串
*/
private static String endIPv6(@Nonnull final String beginIP, final int cidr) {
if (cidr >= Globals.INITIALIZE_INT_VALUE && cidr <= 128) {
String hexAddress = StringUtils.replace(expandIgnore(beginIP), SPLIT_CHARACTER_IPV6, Globals.DEFAULT_VALUE_STRING);
StringBuilder baseIP = new StringBuilder(hexToBin(hexAddress).substring(Globals.INITIALIZE_INT_VALUE, cidr));
while (baseIP.length() < 128) {
baseIP.append("1");
}
return binToHex(baseIP.toString());
}
return Globals.DEFAULT_VALUE_STRING;
}
/**
* Convert hex address to binary string
* 转换16进制地址为二进制地址字符串
*
* @param hexAddress Hex address string
* 16进制地址字符串
*
* @return Binary address string
* 二进制地址字符串
*/
private static String hexToBin(@Nonnull final String hexAddress) {
StringBuilder binBuilder = new StringBuilder();
int index = 0;
while (index < hexAddress.length()) {
int hexInt = Integer.parseInt(hexAddress.substring(index, index + 1), 16);
StringBuilder binItem = new StringBuilder(Integer.toString(hexInt, 2));
while (binItem.length() < 4) {
binItem.insert(0, "0");
}
binBuilder.append(binItem);
index++;
}
return binBuilder.toString();
}
/**
* Convert binary address to hex string
* 转换16进制地址为二进制地址字符串
*
* @param binAddress Binary address string
* 二进制地址字符串
*
* @return Hex address string
* 16进制地址字符串
*/
private static String binToHex(@Nonnull final String binAddress) {
StringBuilder binBuilder = new StringBuilder();
int index = 0;
while (index < binAddress.length()) {
if (index % 16 == 0) {
binBuilder.append(SPLIT_CHARACTER_IPV6);
}
int binInt = Integer.parseInt(binAddress.substring(index, index + 4), 2);
binBuilder.append(Integer.toString(binInt, 16).toUpperCase());
index += 4;
}
return binBuilder.substring(1);
}
private static int fillBitsFromLeft(final int value) {
if (value >= 8) {
return 255;
} else {
return 256 - Double.valueOf(Math.pow(2, (8 - value))).intValue();
}
}
}