Monday, March 9, 2020

Calculate Network Subnet Range efficiently!

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.IntStream;

import static com.varra.auth.utils.CommonUtils.ipStringToLong;
import static java.lang.Integer.parseInt;
import static java.lang.Math.pow;
import static java.util.stream.Collectors.toList;

/**
* TODO Description go here.
*
* @author Rajakrishna V. Reddy
* @version 1.0
*/
public class SubnetCalculator {

private static final Pattern CIDR_PATTERN = Pattern.compile("/");

@Accessors(chain = true, fluent = true)
@Data
@Builder(access = AccessLevel.PRIVATE)
public static class Subnet {
private final int cidr;
private final int ipCount;
private final int startIp;
private final int endIp;

public static Subnet of(final String ipWithCIDR)
{
final String[] ipWithCIDRTokens = CIDR_PATTERN.split(ipWithCIDR);
final int numericCIDR = parseInt(ipWithCIDRTokens[1]);
final int netmaskNumeric = 0xffffffff << (32 - numericCIDR);
final int numberOfIPs = (int) pow(2, 32 - numericCIDR) - 1;
final int baseIP = (int)ipStringToLong(ipWithCIDRTokens[0]) & netmaskNumeric;
return Subnet.builder().cidr(numericCIDR).ipCount(numberOfIPs).startIp(baseIP).endIp(baseIP + numberOfIPs -1).build();
}
}

/**
* Specify IP in CIDR format like: new IPv4("10.1.0.25/16");
*
* @param ipWithCIDR ""
*/
public static List<String> getAvailableIps(final String ipWithCIDR) throws NumberFormatException {
return getAvailableIpsAsIntegers(ipWithCIDR).mapToObj(CommonUtils::ipLongToString).collect(toList());
}

/**
* Specify IP in CIDR format like: new IPv4("10.1.0.25/16");
*
* @param ipWithCIDR ""
* @return IntStream Stream of ips as integers
*/
public static IntStream getAvailableIpsAsIntegers(final String ipWithCIDR) throws NumberFormatException {
final Subnet subnet = Subnet.of(ipWithCIDR);
return IntStream.range(1, subnet.ipCount()).map(i -> i + subnet.startIp());
}

public static boolean isIpWithInSubnet(final String ipWithCIDR, final String ip) throws NumberFormatException {
final Subnet subnet = Subnet.of(ipWithCIDR);
final int ipAsInt = (int) ipStringToLong(ip);
return subnet.startIp() <= ipAsInt && ipAsInt <= subnet.endIp();
}
}